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;
use App\Entities\Usuarios\UsersEntity;
use App\Models\UserModel;
use CodeIgniter\Shield\Authentication\Passwords\ValidationRules;
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->get('delete/(:num)', 'SeriesFacturas::delete/$1', ['as' => 'seriesFacturasDelete']);
$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->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(
'printpresupuestos',
['namespace' => 'App\Controllers\Pdf'],

View File

@ -312,10 +312,6 @@ class Cliente extends \App\Controllers\BaseResourceController
$onlyActiveOnes = false;
try{
$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){
$menu = [];

View File

@ -238,10 +238,24 @@ class SeriesFacturas extends BaseResourceController
$onlyActiveOnes = false;
$menu = $this->model->getSelect2MenuItems($columns2select, $columns2select[1], $onlyActiveOnes, $searchStr);
$nonItem = new \stdClass;
$nonItem->id = '';
$nonItem->text = '- ' . lang('Basic.global.None') . ' -';
array_unshift($menu, $nonItem);
$newTokenHash = csrf_hash();
$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();
$csrfTokenName = csrf_token();
$data = [

View File

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

View File

@ -3,6 +3,8 @@
namespace App\Controllers\Facturacion;
use App\Models\Facturas\FacturaModel;
use App\Entities\Facturas\FacturaEntity;
use App\Models\Clientes\ClienteModel;
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)
{
$this->viewData['pageTitle'] = lang('Pedidos.moduleTitle');
$this->viewData['pageTitle'] = lang('Facturas.facturas');
// Se indica que este controlador trabaja con soft_delete
$this->viewData = ['usingServerSideDataTable' => true];
// Breadcrumbs
$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);
@ -51,10 +53,9 @@ class Facturas extends \App\Controllers\BaseResourceController
$viewData = [
'currentModule' => static::$controllerSlug,
'pageSubTitle' => lang('Basic.global.ManageAllRecords', [lang('Pedidos.pedido')]),
'pageSubTitle' => lang('Basic.global.ManageAllRecords', [lang('Facturas.facturas')]),
'usingServerSideDataTable' => true,
'pageTitle' => lang('Facturas.facturas'),
'estadoPedidos' => 'todos',
['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);
}
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(){
if ($this->request->isAJAX()) {
@ -87,13 +210,425 @@ class Facturas extends \App\Controllers\BaseResourceController
return $this->respond(Collection::datatable(
$resourceData,
$model_linea->getResource("")->countAllResults(),
$model_linea->getResource($search)->countAllResults()
$this->model->getResource("")->countAllResults(),
$this->model->getResource($search)->countAllResults()
));
} else {
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(){
if ($this->request->isAJAX()) {

View File

@ -192,7 +192,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
$this->viewData['presupuestoEntity'] = $presupuestoEntity;
$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
// 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,
);
$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]);
return $this->respond($return_data);
@ -1449,9 +1449,18 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
}
// Servicios
if ($datos_guardas > 0) {
array_push($servicios, 62); // Plegado de guardas
// se comprueba si $datos guardas es un array
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,
'retractilado5' => 5,

View File

@ -7,91 +7,81 @@ use App\Models\UserModel;
class Profile extends BaseController
{
private $user_model;
private $id_user;
function __construct()
{
$this->user_model = new UserModel();
$this->id_user = auth()->user()->id;
}
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'] = [
['title' => lang("App.menu_dashboard"), 'route' => "/home", 'active' => false],
['title' => lang("App.profile_title"), 'route' => "", 'active' => true]
];
$data['btn_return'] = [
'title' => lang("App.global_come_back"),
'route' => '/',
'class' => 'btn btn-dark mr-1',
'icon' => 'fas fa-angle-left'
];
// Get the User Provider (UserModel by default)
$users = auth()->getProvider();
$data['btn_submit'] = [
'title' => lang("App.global_save"),
'route' => '',
'class' => 'btn btn-primary mr-1',
'icon' => 'fas fa-save'
];
// Find by the user_id
$data['obj'] = $users->findById(auth()->id());
$session = session();
$data['obj'] = $this->user_model->where('id', $this->id_user)->first();
echo view(getenv('theme.path') . 'form/profile/index', $data);
echo view(getenv('theme.path') . 'form/profile/profileDetails', $data);
}
public function store()
{
$session = session();
helper('form');
$rules = [
'first_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 = [
'first_name' => ['required' => lang("App.profile_rules_first_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")
]
];
if ($this->validate($rules ?? [], $rules_error ?? [])) {
if (!empty($this->id_user)) {
$this->user_model->save([
'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();
// Validar la entrada
if (!$this->validate($rules, $rules_error)) {
// Si la validación falla, redirigir de vuelta con errores
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
}
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 = [
'id' => null,
'pedido_id' => null,
'factura_retificada_id' => null,
'factura_retificativa_id' => null,
'factura_rectificada_id' => null,
'factura_rectificativa_id' => null,
'cliente_id' => null,
'serie_id' => null,
'numero' => null,
@ -33,18 +33,14 @@ class FacturaEntity extends \CodeIgniter\Entity\Entity
'updated_at' => null,
'deleted_at' => null,
'user_created_id' => null,
'user_update_id' => null,
'user_updated_id' => null,
];
protected $casts = [
'id' => 'int',
'pedido_id' => 'int',
'factura_retificada_id' => 'int',
'factura_retificativa_id' => 'int',
'cliente_id' => 'int',
'serie_id' => 'int',
'estado' => 'int',
'estado_pago' => 'int',
'base' => 'float',
'total' => 'float',
'pendiente' => 'float',

View File

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

View File

@ -14,7 +14,7 @@ class FacturaPagoEntity extends \CodeIgniter\Entity\Entity
'forma_pago_id' => null,
'total' => 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",
"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()
{
$fullName =
(!empty($this->attributes["first_name"]) ? trim($this->attributes["first_name"]) . " " : "") .
(!empty($this->attributes["last_name"]) ? trim($this->attributes["last_name"]) : "");
$name = empty($fullName) ? $this->attributes["username"] : $fullName;
return $name;
$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

@ -1,16 +1,30 @@
<?php
namespace App\Entities\Usuarios;
use CodeIgniter\Entity;
use CodeIgniter\Shield\Entities\User;
class UsersEntity extends User
{
protected $attributes = [
"first_name" => null,
"last_name" => null
'first_name' => null,
'last_name'=> null,
'cliente_id' => null,
'comments' => null,
];
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',
'wait' => 'Wait',
'yes' => 'Yes',
'back' => 'Back',
],

View File

@ -1,6 +1,7 @@
<?php
return [
'id' => 'ID',
'factura' => 'Invoice',
'facturaList' => 'Invoice List',
'facturas' => 'Invoices',
@ -21,6 +22,7 @@ return [
'serieFacturacion' => 'Billing Series',
'creditoAsegurado' => 'Secured Credit',
'facturaRectificada' => 'Rectified Invoice',
'facturaRectificativa' => 'Rectifying Invoice',
'razonSocial' => 'Business Name',
'cif' => 'Tax ID',
'direccion' => 'Address',
@ -54,4 +56,29 @@ return [
'giroDocimiliado' => 'Direct Debit',
'pagare' => 'Promissory Note',
'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',
'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_cubierta' => "\nCover printed on %s 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_ph" => "Escriba su número de celular",
"profile_password" => "Cambiar Contraseña",
"profile_password_ph" => "Escribe tu contraseña",
"profile_confirm_password" => "Confirmar seña",
"profile_confirm_password_ph" => "Confirma tu contraseña anterior",
"profile_password_ph" => "Escribe nueva contraseña para cambiarla",
"profile_confirm_password" => "Confirmar contraseña",
"profile_confirm_password_ph" => "Confirma tu contraseña anterior para cambiarla",
"profile_date_birth" => "Fecha de Nacimiento",
"profile_date_birth_ph" => "Seleccionar fecha de nacimiento",
"profile_address" => "Dirección",

View File

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

View File

@ -1,6 +1,7 @@
<?php
return [
'id' => 'ID',
'factura' => 'Factura',
'facturaList' => 'Listado de Facturas',
'facturas' => 'Facturas',
@ -21,6 +22,7 @@ return [
'serieFacturacion' => 'Serie facturación',
'creditoAsegurado' => 'Crédito asegurado',
'facturaRectificada' => 'Factura rectificada',
'facturaRectificativa' => 'Factura rectificativa',
'razonSocial' => 'Razón Social',
'cif' => 'CIF',
'direccion' => 'Dirección',
@ -54,4 +56,30 @@ return [
'giroDomiciliado' => 'Giro domiciliado',
'pagare' => 'Pagaré',
'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',
'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_cubierta' => "\nCubierta impresa a %s 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',
'confirmado' => 'Presupuesto confirmado',
'totalAceptado' => 'Total aceptado',
// Preview
'preview' => 'Previsualización de configuraciones',
'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' => [
'max_length' => 'El campo {field} no puede exceder {param} caracteres en longitud.',
'required' => 'El campo {field} es obligatorio.',

View File

@ -315,4 +315,21 @@ class ClienteModel extends \App\Models\BaseModel
public function creditoDisponible($cliente_id){
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
{
protected $table = "lg_formas_pago";
protected $table = "formas_pago";
/**
* 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.
*

View File

@ -91,4 +91,36 @@ class SeriesFacturasModel extends \App\Models\BaseModel
->orLike("t1.grupo", $search)
->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
protected $allowedFields = [
'factura_id',
'pedido_impresion_id',
'pedido_linea_impresion_id',
'pedido_maquetacion_id',
'descripcion',
'cantidad',
@ -21,7 +21,7 @@ class FacturaLineaModel extends \App\Models\BaseModel {
'total',
'data',
'deleted_at',
'user_update_id'
'user_updated_id'
];
protected $returnType = "App\Entities\Facturas\FacturaLineaEntity";
@ -30,4 +30,68 @@ class FacturaLineaModel extends \App\Models\BaseModel {
protected $useSoftDeletes = true;
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)",
];
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
protected $allowedFields = [
'pedido_id',
'factura_retificada_id',
'factura_retificativa_id',
'customer_id',
'factura_rectificada_id',
'factura_rectificativa_id',
'cliente_id',
'serie_id',
'numero',
'estado',
@ -40,18 +48,18 @@ class FacturaModel extends \App\Models\BaseModel {
'pendiente',
'total_pagos',
'creditoAsegurado',
'customer_nombre',
'customer_address',
'customer_cif',
'customer_pais',
'customer_cp',
'customer_ciudad',
'customer_provincia',
'cliente_nombre',
'cliente_address',
'cliente_cif',
'cliente_pais',
'cliente_cp',
'cliente_ciudad',
'cliente_provincia',
'created_at',
'updated_at',
'deleted_at',
'user_created_id',
'user_update_id'
'user_updated_id'
];
protected $returnType = "App\Entities\Facturas\FacturaEntity";
@ -69,16 +77,20 @@ class FacturaModel extends \App\Models\BaseModel {
$builder = $this->db
->table($this->table . " t1")
->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,
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("facturas_pagos t3", "t3.factura_id = t1.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)
? $builder
@ -88,4 +100,48 @@ class FacturaModel extends \App\Models\BaseModel {
->orLike("t1.id", $search)
->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',
'total',
'deleted_at',
'user_update_id'
'user_updated_id'
];
protected $returnType = "App\Entities\Facturas\FacturaPagoEntity";
@ -23,4 +23,20 @@ class FacturaPagoModel extends \App\Models\BaseModel {
protected $useSoftDeletes = true;
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)
->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" => [
"label" => "Presupuestos.titulo",
"rules" => "trim|required|max_length[30]",
"rules" => "trim|required|max_length[300]",
],
"inc_rei" => [
"label" => "Presupuestos.incRei",
@ -538,7 +538,7 @@ class PresupuestoModel extends \App\Models\BaseModel
return $json;
}
public function generarLineaPedido($presupuesto_id)
public function generarLineaPedido($presupuesto_id, $forFactura = false, $pedido_id = 0)
{
$builder = $this->db
->table($this->table . " t1")
@ -565,13 +565,18 @@ class PresupuestoModel extends \App\Models\BaseModel
$presupuesto = $presupuesto[0];
// Libro
if($presupuesto->tipo < 10){
if($presupuesto->tipo < 10 || $presupuesto->tipo==20 || $presupuesto->tipo==21){
if($presupuesto->papel_formato_personalizado == 1){
$presupuesto->tamanio= $presupuesto->papel_formato_ancho . "x" . $presupuesto->papel_formato_alto;
}
$presupuesto->concepto = sprintf(lang('Pedidos.lineasTemplates.libro'),
$presupuesto->numero,
if($forFactura){
$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->paginas,
$presupuesto->titulo,

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Models;
use App\Entities\Usuarios\UsersEntity;
use CodeIgniter\Shield\Models\UserModel as ShieldUserModel;
class UserModel extends ShieldUserModel
@ -17,26 +18,51 @@ class UserModel extends ShieldUserModel
'first_name', // Añadido
'last_name', // Añadido
'cliente_id', // Añadido
'comments', // Añadido
];
}
protected $returnType = UsersEntity::class;
protected $useSoftDeletes = true;
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
protected $deletedField = 'deleted_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [
"username" => [
"label" => "correo duplicado",
"rules" => "is_unique[users.username]",
]
"first_name" => "required|trim|max_length[150]",
"last_name" => "required|trim|max_length[150]",
'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
->table("users" . " t1")
->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) {
var $confirmDialog = $("#modalConfirmYesNo");
$confirmDialog.modal('show');
$("#labelTitleConfirmDialog").html(title);
$("#labelMsgConfirmDialog").html(msg);
$("#btnYesConfirmDialog").off('click').click(function () {
yesCallbackFn();
$confirmDialog.modal("hide");
});
$("#btnNoConfirmDialog").off('click').click(function () {
noCallbackFn();
$confirmDialog.modal("hide");
});
}
var $confirmDialog = $("#modalConfirmYesNo");
$confirmDialog.modal('show');
$("#labelTitleConfirmDialog").html(title);
$("#labelMsgConfirmDialog").html(msg);
$("#btnYesConfirmDialog").off('click').click(function () {
yesCallbackFn();
$confirmDialog.modal("hide");
});
$("#btnNoConfirmDialog").off('click').click(function () {
noCallbackFn();
$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() ?>

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.formaPago') ?></th>
<th><?= lang('Facturas.vencimiento') ?></th>
<th><?= lang('Facturas.dias') ?></th>
<th class="text-nowrap"><?= lang('Basic.global.Action') ?></th>
</tr>
</thead>
@ -49,12 +50,22 @@
const lastColNr = $('#tableOfFacturas').find("tr:first th").length - 1;
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">
<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>
</div>
</td>`;
}
};
theTable = $('#tableOfFacturas').DataTable({
@ -100,7 +111,24 @@
{ 'data': 'base' },
{ 'data': 'total' },
{ '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',
render: function(data, type, row, meta) {
switch(data){
@ -141,8 +169,7 @@
}
}
},
{ 'data': 'total_presupuesto' },
{ 'data': forma_pago,
{ 'data': 'forma_pago',
render: function(data, type, row, meta) {
switch(data){
case "cheque":
@ -170,20 +197,21 @@
break;
default:
return '--'; // Debug
return data; // Debug
break;
}
}
},
{ 'data': vencimiento },
{ 'data': 'vencimiento' },
{ 'data': 'dias_vencimiento' },
{ 'data': actionBtns }
]
});
$(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')}` );
window.location.href = url;
});

View File

@ -10,6 +10,21 @@
<div id="accordionFacturasTip" class="accordion-collapse collapse show" data-bs-parent="#accordioFacturas">
<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>
@ -19,6 +34,77 @@
<?=$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() ?>

View File

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

View File

@ -16,7 +16,7 @@
</div>
<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">
<?= lang('Presupuestos.clienteId') ?>*
</label>

View File

@ -97,7 +97,7 @@
$total = $presupuestoEntity->total_aceptado;
$iva = $presupuestoEntity->iva_reducido?1.04:1.21;
$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 '<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'))
isColor = true;
let isHq = false;
if($('#colorNegroDiv').hasClass('checked') || $('#colorColorHqDiv').hasClass('checked'))
if($('#colorNegroHqDiv').hasClass('checked') || $('#colorColorHqDiv').hasClass('checked'))
isHq = true;
if(!comprobarTiradasPOD()){

View File

@ -76,6 +76,16 @@
</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-collapse -->

View File

@ -177,8 +177,8 @@ function updateTotales(updateLP=true, updateServicios=true, updateEnvio=true){
margenEnvios = parseFloat($('#margenEnvios').attr('val'))
}
var totalCostes = totalPapel + totalImpresion + totalServicios + totalEnvios
var totalMargenes = margenPapel + margenImpresion + margenServicios + margenEnvios
var totalCostes = parseFloat(totalPapel.toFixed(2)) + parseFloat(totalImpresion.toFixed(2)) + parseFloat(totalServicios.toFixed(2)) + parseFloat(totalEnvios.toFixed(2))
var totalMargenes = parseFloat(margenPapel.toFixed(2)) + parseFloat(margenImpresion.toFixed(2)) + parseFloat(margenServicios.toFixed(2)) + parseFloat(margenEnvios.toFixed(2))
$('#totalCostes').text((addSeparatorsNF(totalCostes.toFixed(2), ".", ",", ".")) + "€")
$('#totalMargenes').text((addSeparatorsNF(totalMargenes.toFixed(2), ".", ",", ".")) + "€")
$('#totalCostes').attr('val',(totalCostes).toFixed(2) + '€')
@ -251,11 +251,13 @@ function getValuesResumenForm(){
formResumen += '&total_presupuesto=' + $('#totalDespuesDecuento').attr('val');
formResumen += '&total_precio_unidad=' + $('#precioUnidadPresupuesto').attr('val');
formResumen += '&total_factor=' + $('#total_factor').text();
formResumen += '&total_factor_ponderado=' + $('#total_factor_ponderado').text();
// replace , for . in the values
formResumen += '&total_factor=' + $('#factor').text().replace(/,/g, '.');
formResumen += '&total_factor_ponderado=' + $('#factor_ponderado').text().replace(/,/g, '.');
if($('#confirmar_presupuesto').prop('checked')){
formResumen += '&confirmar=1';
formResumen += '&confirmar=1';
formResumen += '&total_aceptado=' + $('#totalDespuesDecuento').attr('val');
}
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/general_settings_layout') ?>
<?= $this->extend('themes/vuexy/main/defaultlayout') ?>
<?= $this->section('content'); ?>
<!--Content Body-->
@ -12,10 +11,11 @@
<form id="formAccountSettings" method="POST" action="<?= site_url("profile/store") ?>">
<?= csrf_field() ?>
<div class="row">
<div class="mb-3 col-md-6">
<label for="first_name" class="form-label"><?= lang("App.profile_first_name") ?></label>
<div class="mb-3 col-md-4">
<label for="first_name" class="form-label"><?= lang("App.profile_first_name") ?> *</label>
<input
class="form-control"
tabindex="1"
type="text"
id="first_name"
name="first_name"
@ -24,9 +24,10 @@
autofocus
/>
</div>
<div class="mb-3 col-md-6">
<label for="last_name" class="form-label"><?= lang("App.profile_last_name") ?></label>
<div class="mb-3 col-md-4">
<label for="last_name" class="form-label"><?= lang("App.profile_last_name") ?> *</label>
<input class="form-control"
tabindex="2"
type="text"
name="last_name"
id="last_name"
@ -34,54 +35,52 @@
value="<?= (isset($obj)) ? $obj->last_name : set_value('last_name'); ?>"
/>
</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>
<input
class="form-control"
tabindex="3"
type="text"
id="email"
name="email"
disabled
placeholder="<?= lang("App.profile_email_ph") ?>"
value="<?= (isset($obj)) ? $obj->email : set_value('email'); ?>"
/>
</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 class="mt-2">
<button type="submit" class="btn btn-primary me-2"><?= $btn_submit['title'] ?? '' ?></button>
<button type="reset" class="btn btn-label-secondary"><?= $btn_return['title'] ?? '' ?></button>
<button type="submit" class="btn btn-primary me-2"><?= lang("Basic.global.Save") ?? '' ?></button>
<?= anchor(route_to("home"), lang("Basic.global.Cancel"), ["class" => "btn btn-dark"]) ?>
</div>
</form>
</div>
<!-- /Account -->
</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>
<?php $settings = session()->get('settings'); ?>
@ -96,12 +95,7 @@
<?= $this->section('additionalInlineJs') ?>
"use strict";
$(document).ready(function () {
$('#first_name').focus();
$('#first_name').focus();
});
$('.file-upload').on('click', function (e) {
e.preventDefault();
$('#file').trigger('click');
});
<?= $this->endSection() ?>

View File

@ -1,26 +1,41 @@
<div class="row">
<div class="col-md-12 col-lg-6 px-4">
<div class="col-md-12 col-lg-12 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">
<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><!--//.mb-3 -->
<div class="col-md-6 col-lg-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>
</div>
<div class="mb-3">
<label for="email" class="form-label">
<?= lang('Users.email') ?>*
</label>
<input tabindex="13" type="email" id="email" name="email" maxLength="150" class="form-control"
value="<?= old('email', $user->email) ?>">
</div><!--//.mb-3 -->
<div class="col-md-6 col-lg-4">
<div class="mb-3">
<label for="email" class="form-label">
<?= lang('Users.email') ?>*
</label>
<input tabindex="3" type="email" id="email" name="email" maxLength="150" class="form-control"
value="<?= old('email', $user->email) ?>">
</div>
</div>
</div>
<div class="row">
<div class="mb-3">
<div class="form-group">
<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">
<option value=""><?= lang('Basic.global.pleaseSelectA', [lang('Users.group')]) ?></option>
<?php
@ -36,59 +51,106 @@
<?php endforeach; ?>
</select>
</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 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">
<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 tabindex="7" id="cliente_id" name="cliente_id" class="form-control select2bs2" style="width: 100%;">
<?php if (isset($clienteList) && is_array($clienteList) && !empty($clienteList)) :
foreach ($clienteList as $k => $v) : ?>
<option value="<?= $k ?>" <?= $k == $user->cliente_id ? ' selected' : '' ?>>
<?= $v ?>
</option>
<?php endforeach;
<?php endforeach;
endif; ?>
</select>
</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>
<th><?= lang('Users.firstName') ?></th>
<th><?= lang('Users.lastName') ?></th>
<th><?= lang('Users.group') ?></th>
<th><?= lang('Users.lastAccess') ?></th>
<th><?= lang('Users.email') ?></th>
<th><?= lang('Users.lastAccess') ?></th>
<?php /*
<th><?= lang('Users.mobile') ?></th>
<th><?= lang('Users.email') ?></th>
@ -46,11 +46,10 @@
<td class="align-middle">
<?= empty($item->last_name) || strlen($item->last_name) < 51 ? esc($item->last_name) : character_limiter(esc($item->last_name), 50) ?>
</td>
<td class="align-middle">
<?= empty($item->group) ? "" : character_limiter(esc(lang('Users.' . $item->group)), 50) ?>
</td>
<td class="align-middle text-nowrap">
<td class="align-middle">
<?= empty($item->email) ? "" : character_limiter(esc(lang($item->email)), 50) ?>
</td>
<td class="align-middle text-nowrap">
<?= empty($item->last_active) ? '' : date('d/m/Y H:m:s', strtotime($item->last_active)) ?>
</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"
>
<i class="ti ti-report-search ti-md"></i>
</a>
</li>
<!--/ Search Budgets -->
@ -232,8 +231,8 @@ $picture = "/assets/img/default-user.png";
</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>
<span class="fw-semibold d-block"><?= auth()->user()->getFullName(); ?></span>
<small class="text-muted"><?= auth()->user()->getEmail(); ?></small>
</div>
</div>
</a>
@ -247,13 +246,6 @@ $picture = "/assets/img/default-user.png";
<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>

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

View File

@ -12,7 +12,7 @@ if (auth()->user()->inGroup('beta')) {
</a>
<ul class="menu-sub">
<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") ?>
</a>
</li>

View File

@ -247,8 +247,8 @@ if (!empty($token) && $tfa == false) {
</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>
<span class="fw-semibold d-block"><?= auth()->user()->getFullName(); ?></span>
<small class="text-muted"><?= auth()->user()->getEmail(); ?></small>
</div>
</div>
</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.
)