Merge branch 'main' into feat/pedidos-export

This commit is contained in:
amazuecos
2024-08-10 21:11:10 +02:00
49 changed files with 2337 additions and 599 deletions

View File

@ -70,7 +70,6 @@ $routes->group('configuracion', ['namespace' => 'App\Controllers\Configuracion']
/* Series Factura */
$routes->group('series-facturas', ['namespace' => 'App\Controllers\Configuracion'], function ($routes) {
$routes->get('', 'SeriesFacturas::index', ['as' => 'seriesFacturasList']);
$routes->match(['get', 'post'], 'add', 'SeriesFacturas::add', ['as' => 'seriesFacturasAdd']);
$routes->match(['get', 'post'], 'edit/(:num)', 'SeriesFacturas::edit/$1', ['as' => 'seriesFacturasEdit']);
@ -79,6 +78,15 @@ $routes->group('configuracion', ['namespace' => 'App\Controllers\Configuracion']
$routes->post('menuitemsFacturas', 'SeriesFacturas::menuItemsFacturas', ['as' => 'menuItemsOfSeriesFacturas']);
});
/* Formas de Pago */
$routes->group('formas-pago', ['namespace' => 'App\Controllers\Configuracion'], function ($routes) {
$routes->get('', 'FormasPago::index', ['as' => 'formasPagoList']);
$routes->match(['get', 'post'], 'add', 'FormasPago::add', ['as' => 'formasPagoAdd']);
$routes->match(['get', 'post'], 'edit/(:num)', 'FormasPago::edit/$1', ['as' => 'formasPagoEdit']);
$routes->get('delete/(:num)', 'FormasPago::delete/$1', ['as' => 'formasPagoDelete']);
$routes->post('datatable', 'FormasPago::datatable', ['as' => 'formasPagoDT']);
});
});
@ -655,13 +663,22 @@ $routes->group('facturas', ['namespace' => 'App\Controllers\Facturacion'], funct
$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->post('addExcedentes/(:any)', 'Facturas::addExcedentes/$1', ['as' => 'addLineaExcedentes']);
$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']);
});

View File

@ -395,7 +395,7 @@ class Cliente extends \App\Controllers\BaseResourceController
protected function getFormaDePagoListItems($selId = null)
{
$data = ['' => lang('Basic.global.pleaseSelectA', [mb_strtolower(lang('FormasPagoes.formaDePago'))])];
$data = ['' => lang('Basic.global.pleaseSelectA', [mb_strtolower(lang('FormasPago.formaDePago'))])];
if (!empty($selId)) :
$formaPagoModel = model('App\Models\Configuracion\FormaPagoModel');

View File

@ -9,7 +9,7 @@ use App\Entities\Configuracion\FormaPagoEntity;
use App\Models\Configuracion\FormaPagoModel;
class Formaspagos extends \App\Controllers\BaseResourceController
class FormasPago extends \App\Controllers\BaseResourceController
{
protected $modelName = FormaPagoModel::class;
@ -22,15 +22,22 @@ class Formaspagos extends \App\Controllers\BaseResourceController
protected static $controllerSlug = 'formas-pagos';
protected static $viewPath = 'themes/vuexy/form/configuracion/formasPagoViews/';
protected static $viewPath = 'themes/vuexy/form/configuracion/formas-pago/';
protected $indexRoute = 'formaDePagoList';
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{
$this->viewData['pageTitle'] = lang('FormasPagoes.moduleTitle');
$this->viewData['pageTitle'] = lang('FormasPago.moduleTitle');
$this->viewData['usingSweetAlert'] = true;
// Breadcrumbs (IMN)
$this->viewData['breadcrumb'] = [
['title' => lang("App.menu_configuration"), 'route' => "javascript:void(0);", 'active' => false],
['title' => lang("App.menu_formas_pago"), 'route' => route_to('formasPagoList'), 'active' => true]
];
parent::initController($request, $response, $logger);
}
@ -40,7 +47,7 @@ class Formaspagos extends \App\Controllers\BaseResourceController
$viewData = [
'currentModule' => static::$controllerSlug,
'pageSubTitle' => lang('Basic.global.ManageAllRecords', [lang('FormasPagoes.formaDePago')]),
'pageSubTitle' => lang('Basic.global.ManageAllRecords', [lang('FormasPago.formaDePago')]),
'formaPagoEntity' => new FormaPagoEntity(),
'usingServerSideDataTable' => true,
@ -55,22 +62,15 @@ class Formaspagos extends \App\Controllers\BaseResourceController
public function add()
{
if ($this->request->getPost()) :
$nullIfEmpty = true; // !(phpversion() >= '8.1');
$postData = $this->request->getPost();
$sanitizedData = $this->sanitized($postData, $nullIfEmpty);
$sanitizedData = $this->sanitized($postData, true);
$noException = true;
if ($successfulResult = $this->canValidate()) : // if ($successfulResult = $this->validate($this->formValidationRules) ) :
if ($this->canValidate()) :
try {
$successfulResult = $this->model->skipValidation(true)->save($sanitizedData);
@ -93,7 +93,8 @@ class Formaspagos extends \App\Controllers\BaseResourceController
if ($thenRedirect) :
if (!empty($this->indexRoute)) :
return redirect()->to(route_to($this->indexRoute))->with('sweet-success', $message);
return redirect()->to(site_url('/configuracion/formas-pago/edit/' . $id))->with('sweet-success', $message);
//return redirect()->to(route_to($this->indexRoute))->with('sweet-success', $message);
else:
return $this->redirect2listView('sweet-success', $message);
endif;
@ -106,11 +107,8 @@ class Formaspagos extends \App\Controllers\BaseResourceController
endif; // ($requestMethod === 'post')
$this->viewData['formaPagoEntity'] = isset($sanitizedData) ? new FormaPagoEntity($sanitizedData) : new FormaPagoEntity();
$this->viewData['formAction'] = route_to('createFormaDePago');
$this->viewData['boxTitle'] = lang('Basic.global.addNew') . ' ' . lang('FormasPagoes.moduleTitle') . ' ' . lang('Basic.global.addNewSuffix');
$this->viewData['formAction'] = route_to('formasPagoAdd');
$this->viewData['boxTitle'] = lang('Basic.global.addNew') . ' ' . lang('FormasPago.moduleTitle') . ' ' . lang('Basic.global.addNewSuffix');
return $this->displayForm(__METHOD__);
} // end function add()
@ -125,25 +123,18 @@ class Formaspagos extends \App\Controllers\BaseResourceController
$formaPagoEntity = $this->model->find($id);
if ($formaPagoEntity == false) :
$message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('FormasPagoes.formaDePago')), $id]);
$message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('FormasPago.formaDePago')), $id]);
return $this->redirect2listView('sweet-error', $message);
endif;
if ($this->request->getPost()) :
$nullIfEmpty = true; // !(phpversion() >= '8.1');
$postData = $this->request->getPost();
$sanitizedData = $this->sanitized($postData, $nullIfEmpty);
$sanitizedData = $this->sanitized($postData, true);
$noException = true;
if ($successfulResult = $this->canValidate()) : // if ($successfulResult = $this->validate($this->formValidationRules) ) :
if ($this->canValidate()) :
try {
$successfulResult = $this->model->skipValidation(true)->update($id, $sanitizedData);
@ -152,13 +143,12 @@ class Formaspagos extends \App\Controllers\BaseResourceController
$this->dealWithException($e);
}
else:
$this->viewData['warningMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('FormasPagoes.formaDePago'))]);
$this->viewData['warningMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('FormasPago.formaDePago'))]);
$this->session->setFlashdata('formErrors', $this->model->errors());
endif;
$formaPagoEntity->fill($sanitizedData);
$thenRedirect = false;
endif;
if ($noException && $successfulResult) :
@ -179,11 +169,8 @@ class Formaspagos extends \App\Controllers\BaseResourceController
endif; // ($requestMethod === 'post')
$this->viewData['formaPagoEntity'] = $formaPagoEntity;
$this->viewData['formAction'] = route_to('updateFormaDePago', $id);
$this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('FormasPagoes.moduleTitle') . ' ' . lang('Basic.global.edit3');
$this->viewData['formAction'] = route_to('formasPagoEdit', $id);
$this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('FormasPago.moduleTitle') . ' ' . lang('Basic.global.edit3');
return $this->displayForm(__METHOD__, $id);
} // end function edit(...)

View File

@ -66,7 +66,6 @@ class SeriesFacturas extends BaseResourceController
$noException = true;
if ($successfulResult = $this->canValidate()) :
if ($this->canValidate()) :
try {
$successfulResult = $this->model->skipValidation(true)->save($sanitizedData);
@ -105,7 +104,6 @@ class SeriesFacturas extends BaseResourceController
$this->viewData['formAction'] = route_to('seriesFacturasAdd');
$this->viewData['boxTitle'] = lang('Basic.global.addNew') . ' ' . lang('SeriesFacturas.moduleTitle') . ' ' . lang('Basic.global.addNewSuffix');
return $this->displayForm(__METHOD__);
} // end function add()
@ -126,7 +124,6 @@ class SeriesFacturas extends BaseResourceController
if ($this->request->getPost()) :
$postData = $this->request->getPost();
$sanitizedData = $this->sanitized($postData, true);
if ($this->request->getPost('show_erp') == null) {
$sanitizedData['show_erp'] = false;

View File

@ -143,6 +143,11 @@ class Facturas extends \App\Controllers\BaseResourceController
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;
@ -168,9 +173,15 @@ class Facturas extends \App\Controllers\BaseResourceController
$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');
@ -207,6 +218,38 @@ class Facturas extends \App\Controllers\BaseResourceController
}
}
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()) {
@ -313,6 +356,123 @@ class Facturas extends \App\Controllers\BaseResourceController
}
}
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();
$pendiente = $postData['pendiente'] ?? 0;
$total = $postData['total'] ?? 0;
$data = [
'base' => $postData['base'] ?? 0,
'total' => $total,
'pendiente' => $pendiente,
'total_pagos' => $postData['total_pagos'] ?? 0,
'user_updated_id' => auth()->user()->id,
'estado_pago' => (intval($pendiente)==0 && intval($total)!=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 addExcedentes($factura_id){
if ($this->request->isAJAX()) {
$model_factura_linea = model('\App\Models\Facturas\FacturaLineaModel');
$postData = $this->request->getPost();
$cantidad = $postData['cantidad'] ?? 0;
$precio_unidad = $postData['precio_unidad'] ?? 0;
$iva = $postData['iva'] ?? 0;
$descripcion = $postData['descripcion'] ?? '';
$descuento = $postData['descuento'] ?? 0;
$pedido_linea_impresion_id = $postData['pedido_linea_impresion_id'] ?? null;
$pedido_linea_maquetacion_id = $postData['pedido_linea_maquetacion_id'] ?? null;
$pedido_id = $postData['pedido_id'] ?? 0;
$nuevo_precio_unidad = round($precio_unidad*(100-floatval($descuento))/100, 4);
$base = round($cantidad * $nuevo_precio_unidad, 2);
$total_iva = round($base * $iva / 100, 2);
$data = (object)[
'factura_id'=>$factura_id,
'pedido_linea_impresion_id'=>$pedido_linea_impresion_id,
'pedido_linea_maquetacion_id'=>$pedido_linea_maquetacion_id,
'descripcion'=>$newString = preg_replace_callback('/Impresión de (\d+) ejemplares/', function ($matches) use ($cantidad) {
return 'Impresión de ' . $cantidad . ' ejemplares';
}, $descripcion),
'cantidad'=>$cantidad,
'precio_unidad'=> $nuevo_precio_unidad,
'iva' => $iva,
'base' => $base,
'total_iva' => $total_iva,
'total' => round($base + $total_iva, 2),
'user_updated_id' => auth()->user()->id,
];
$model_factura_linea->insert($data);
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data_ret = [
$csrfTokenName => $newTokenHash
];
return $this->respond($data_ret);
}
else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function addLineaPedidoImpresion($factura_id){
@ -324,48 +484,55 @@ class Facturas extends \App\Controllers\BaseResourceController
try{
$pedido_linea_id = $this->request->getPost('lineaPedido') ?? 0;
$linea = $model_pedido_linea->find($pedido_linea_id);
$factura = $this->model->find($factura_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;
if($factura){
$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,
];
if($linea){
$presupuesto = $model_presupuesto->find($linea->presupuesto_id);
$model_factura_linea->insert($data);
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);
$base = round($base, 2);
$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;
$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
$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,
];
return $this->respond($data);
$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);
}
}
}
}
@ -386,6 +553,113 @@ class Facturas extends \App\Controllers\BaseResourceController
}
}
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
************************************/
@ -407,6 +681,9 @@ class Facturas extends \App\Controllers\BaseResourceController
$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

@ -83,96 +83,100 @@ class FacturasLineas extends \App\Controllers\BaseResourceController
include(APPPATH . "ThirdParty/DatatablesEditor/DataTables.php");
// Build our Editor instance and process the data coming from _POST
$response = Editor::inst( $db, 'cliente_plantilla_precios_lineas' )
$response = Editor::inst( $db, 'facturas_lineas' )
->fields(
Field::inst( 'plantilla_id' ),
Field::inst( 'tipo' ),
Field::inst( 'tipo_maquina' ),
Field::inst( 'tipo_impresion' ),
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' ),
Field::inst( 'updated_at' ),
Field::inst( 'tiempo_min' )
->getFormatter( 'Format::toDecimalChar')->setFormatter( 'Format::fromDecimalChar')
->validator( 'Validate::notEmpty',array(
'message' => lang('ClientePrecios.validation.required'))
)
->validator('Validate::numeric', array(
"decimal" => ',',
'message' => lang('ClientePrecios.validation.decimal'))
),
Field::inst( 'tiempo_max' )
->getFormatter( 'Format::toDecimalChar')->setFormatter( 'Format::fromDecimalChar')
->validator( 'Validate::notEmpty',array(
'message' => lang('ClientePrecios.validation.required'))
)
->validator('Validate::numeric', array(
"decimal" => ',',
'message' => lang('ClientePrecios.validation.decimal'))
),
Field::inst( 'precio_hora' )
->getFormatter( 'Format::toDecimalChar')->setFormatter( 'Format::fromDecimalChar')
->validator( 'Validate::notEmpty',array(
'message' => lang('ClientePrecios.validation.required'))
)
->validator('Validate::numeric', array(
"decimal" => ',',
'message' => lang('ClientePrecios.validation.decimal'))
),
Field::inst( 'margen' )
->getFormatter( 'Format::toDecimalChar')->setFormatter( 'Format::fromDecimalChar')
->validator( 'Validate::notEmpty',array(
'message' => lang('ClientePrecios.validation.required'))
)
->validator('Validate::numeric', array(
"decimal" => ',',
'message' => lang('ClientePrecios.validation.decimal'))
),
)
->validator(function ($editor, $action, $data) {
if ($action === Editor::ACTION_CREATE || $action === Editor::ACTION_EDIT) {
foreach ($data['data'] as $pkey => $values) {
// Si no se quiere borrar...
if ($data['data'][$pkey]['is_deleted'] != 1) {
$process_data['tiempo_min'] = $data['data'][$pkey]['tiempo_min'];
$process_data['tiempo_max'] = $data['data'][$pkey]['tiempo_max'];
$process_data['tipo'] = $data['data'][$pkey]['tipo'];
$process_data['tipo_maquina'] = $data['data'][$pkey]['tipo_maquina'];
$process_data['tipo_impresion'] = $data['data'][$pkey]['tipo_impresion'];
$response = $this->model->checkIntervals($process_data, $pkey, $data['data'][$pkey]['plantilla_id']);
// No se pueden duplicar valores al crear o al editar
if (!empty($response)) {
return $response;
}
}
}
}
})
->on('preCreate', function ($editor, &$values) {
$session = session();
$datetime = (new \CodeIgniter\I18n\Time("now"));
$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($session->id_user);
->setValue(auth()->user()->id);
$editor
->field('updated_at')
->setValue($datetime->format('Y-m-d H:i:s'));
->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, &$values) {
$session = session();
$datetime = (new \CodeIgniter\I18n\Time("now"));
->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($session->id_user);
->setValue(auth()->user()->id);
$editor
->field('updated_at')
->setValue($datetime->format('Y-m-d H:i:s'));
->field('base')
->setValue($totales['base']);
$editor
->field('total_iva')
->setValue($totales['total_iva']);
$editor
->field('total')
->setValue($totales['total']);
})
->debug(true)
->process($_POST)
@ -189,4 +193,36 @@ class FacturasLineas extends \App\Controllers\BaseResourceController
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

@ -245,13 +245,31 @@ class Pedido extends \App\Controllers\BaseResourceController
$estado = $reqData['estado'] ?? 'todos';
if($estado == 'todos') $estado = '';
$model_linea = model('\App\Models\Pedidos\PedidoLineaModel');
$resourceData = $model_linea->getResource($search, $estado)->orderBy($order, $dir)->limit($length, $start)->get()->getResultObject();
$showTotal = $reqData['showTotal'] ?? false;
$searchValues = get_filter_datatables_columns($reqData);
$model_linea = model('\App\Models\Pedidos\PedidoLineaModel');
$resourceData = $model_linea->getResource($searchValues, $estado)->orderBy($order, $dir)->limit($length, $start)->get()->getResultObject();
$totalTirada = $model_linea->getSumOfTirada($searchValues, $estado, $start, $length);
$total = $model_linea->getSumOfTotalAceptado($searchValues, $estado, $start, $length);
$total2 = 0;
if($showTotal){
$total2 = $model_linea->getTotalOfTotalAceptado();
}
if($total2 != 0){
$total = "" . $total . " \n(" . $total2 . ")";
}
return $this->respond(Collection::datatable(
$resourceData,
$model_linea->getResource("", $estado)->countAllResults(),
$model_linea->getResource($search, $estado)->countAllResults()
$model_linea->getResource($searchValues, $estado)->countAllResults(),
"",
[
'total_tirada' => $totalTirada,
'total' => $total
]
));
} else {
return $this->failUnauthorized('Invalid request', 403);

View File

@ -111,7 +111,7 @@ class Buscador extends \App\Controllers\BaseResourceController
return $this->respond(Collection::datatable(
$resourceData,
$this->model->getResource("")->countAllResults(),
$this->model->getResource($search)->countAllResults()
$this->model->getResource($searchValues)->countAllResults()
));
} else {
return $this->failUnauthorized('Invalid request', 403);

View File

@ -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);
@ -1073,14 +1073,12 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
try {
$return_data = [];
if ($extra_info) {
$info = [
'merma' => 0,
'lomo_cubierta' => 0.0,
'lomo_sobrecubierta' => 0.0,
'user_id' => auth()->user()->id,
];
}
$info = [
'merma' => 0,
'lomo_cubierta' => 0.0,
'lomo_sobrecubierta' => 0.0,
'user_id' => auth()->user()->id,
];
$tirada = $datos_entrada['tirada'];
$tamanio = $datos_entrada['tamanio'];
@ -1568,11 +1566,13 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
));
}
$info['lomo_cubierta'] = $lomo;
$info['lomo_sobrecubierta'] = $lomo_sobrecubierta;
$return_data['info'] = $info;
if ($extra_info) { // && $tirada[$t] == $selected_tirada) {
$info['lomo_cubierta'] = $lomo;
$info['lomo_sobrecubierta'] = $lomo_sobrecubierta;
$return_data['info'] = $info;
$return_data['info']['interior'] = $interior;
$return_data['info']['cubierta'] = $cubierta;
$return_data['info']['sobrecubierta'] = $linea_sobrecubierta;

View File

@ -25,12 +25,7 @@ class Test extends BaseController
$data = $model->obtenerLineasPedidoSinFacturar(999);
*/
$model = model("\App\Models\Facturas\FacturaLineaModel");
$data = $model->getResource(9)->get()->getResultObject();
echo('<pre>');
var_dump($data);
echo('</pre>');
xdebug_info();

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,14 +33,12 @@ 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',
'base' => '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

@ -679,7 +679,7 @@ return [
"menu_calendario" => "Calendar",
"menu_paises" => "Countries",
"menu_correo" => "Mail",
"menu_formaspago" => "Payment methods",
"menu_formas_pago" => "Payment methods",
"menu_imposiciones" => "Impositions",
"menu_maquina" => "Machines",
"menu_papelgenerico" => "Generic paper",

View File

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

View File

@ -22,6 +22,7 @@ return [
'serieFacturacion' => 'Billing Series',
'creditoAsegurado' => 'Secured Credit',
'facturaRectificada' => 'Rectified Invoice',
'facturaRectificativa' => 'Rectifying Invoice',
'razonSocial' => 'Business Name',
'cif' => 'Tax ID',
'direccion' => 'Address',
@ -61,8 +62,23 @@ return [
'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

@ -11,7 +11,6 @@ return [
'formasDePagos' => 'Formas de Pagos',
'formasPago' => 'Formas Pago',
'formasPagoList' => 'Formas Pago List',
'formasPagoes' => 'Formas Pagoes',
'id' => 'ID',
'moduleTitle' => 'Formas Pagoes',
'nombre' => 'Nombre',

View File

@ -78,6 +78,8 @@ return [
'facturas' => 'Invoices',
'showTotal' => 'Show totals',
'validation' => [
],

View File

@ -682,7 +682,7 @@ return [
"menu_calendario" => "Calendario",
"menu_paises" => "Paises",
"menu_correo" => "Correo",
"menu_formaspago" => "Metodos de pago",
"menu_formas_pago" => "Formas de pago",
"menu_imposiciones" => "Imposiciones",
"menu_maquina" => "Maquinas",
"menu_maquina_defecto" => "Maquinas por defecto",

View File

@ -90,6 +90,7 @@ return [
'wait' => 'Espere',
'yes' => 'Si',
'no' => 'No',
'back' => 'Volver',
],

View File

@ -22,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',
@ -61,8 +62,24 @@ return [
'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

@ -78,6 +78,8 @@ return [
'facturas' => 'Facturas',
'showTotal' => 'Mostrar totales',
'validation' => [
],

View File

@ -37,6 +37,7 @@ return [
'tarifaExtraSection' => 'Tarifas extra',
'proveedoresSection' => 'Proveedores',
'paisesSection' => 'Países',
'formasPagoSection' => 'Formas de Pago',
'maquinasSection' => 'Máquinas',
'maquinasDefectoSection' => 'Máquinas por defecto',
'papelGenericoSection' => 'Papel genérico',

View File

@ -257,7 +257,7 @@ class ClienteModel extends \App\Models\BaseModel
LEFT JOIN lg_paises t4 ON t1.pais_id = t4.id
LEFT JOIN users t5 ON t1.comercial_id = t5.id
LEFT JOIN users t6 ON t1.soporte_id = t6.id
LEFT JOIN lg_formas_pago t7 ON t1.forma_pago_id = t7.id";
LEFT JOIN formas_pago t7 ON t1.forma_pago_id = t7.id";
if (!is_null($limit) && intval($limit) > 0) {
$sql .= " LIMIT " . intval($limit);
}
@ -287,7 +287,7 @@ class ClienteModel extends \App\Models\BaseModel
)
->where("is_deleted", 0);;
$builder->join("users t5", "t1.comercial_id = t5.id", "left");
$builder->join("lg_formas_pago t7", "t1.forma_pago_id = t7.id", "left");
$builder->join("formas_pago t7", "t1.forma_pago_id = t7.id", "left");
return empty($search)

View File

@ -15,7 +15,7 @@ class Collection
*
* @return array
*/
public static function datatable(array $data, int $recordsTotal, int $recordsFiltered, string $error = null)
public static function datatable(array $data, int $recordsTotal, int $recordsFiltered, string $error = null, $extra_data = [])
{
$draw = 1;
$req = service('request');
@ -38,6 +38,10 @@ class Collection
$response['error'] = $error;
}
if (count($extra_data)>0) {
$response['extra'] = $extra_data;
}
return $response;
}
}

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.
@ -15,8 +15,6 @@ class FormaPagoModel extends \App\Models\BaseModel
const SORTABLE = [
1 => "t1.id",
2 => "t1.nombre",
3 => "t1.created_at",
4 => "t1.updated_at",
];
protected $allowedFields = ["nombre"];
@ -26,18 +24,30 @@ class FormaPagoModel extends \App\Models\BaseModel
protected $validationRules = [
"nombre" => [
"label" => "FormasPagoes.nombre",
"label" => "FormasPago.nombre",
"rules" => "trim|required|max_length[255]",
],
];
protected $validationMessages = [
"nombre" => [
"max_length" => "FormasPagoes.validation.nombre.max_length",
"required" => "FormasPagoes.validation.nombre.required",
"max_length" => "FormasPago.validation.nombre.max_length",
"required" => "FormasPago.validation.nombre.required",
],
];
public function getMenuItems(){
$items = $this->findAll();
$menuItems = [];
foreach ($items as $item) {
$menuItems[] = [
"value" => $item->id,
"label" => $item->nombre,
];
}
return $menuItems;
}
/**
* Get resource data.
*
@ -49,7 +59,7 @@ class FormaPagoModel extends \App\Models\BaseModel
{
$builder = $this->db
->table($this->table . " t1")
->select("t1.id AS id, t1.nombre AS nombre, t1.created_at AS created_at, t1.updated_at AS updated_at");
->select("t1.id AS id, t1.nombre AS nombre");
return empty($search)
? $builder
@ -57,12 +67,6 @@ class FormaPagoModel extends \App\Models\BaseModel
->groupStart()
->like("t1.id", $search)
->orLike("t1.nombre", $search)
->orLike("t1.created_at", $search)
->orLike("t1.updated_at", $search)
->orLike("t1.id", $search)
->orLike("t1.nombre", $search)
->orLike("t1.created_at", $search)
->orLike("t1.updated_at", $search)
->groupEnd();
}
}

View File

@ -108,4 +108,19 @@ class SeriesFacturasModel extends \App\Models\BaseModel
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

@ -38,12 +38,16 @@ class FacturaLineaModel extends \App\Models\BaseModel {
->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 concepto, t1.cantidad as unidades, t1.precio_unidad AS precio_unidad, t1.iva AS iva,
t1.base AS subtotal, 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"
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, t4.tirada_flexible AS tirada_flexible, t4.descuento_tirada_flexible AS descuento_tirada_flexible,
t6.cantidad AS cantidad_albaran"
)
->join("pedidos_linea t2", "t2.id = t1.pedido_linea_impresion_id", "left")
->join("presupuestos t3", "t3.id = t2.presupuesto_id", "left")
->join("clientes t4", "t4.id = t3.cliente_id", "left")
->join("albaranes t5", "t5.pedido_id = t2.pedido_id", "left")
->join("albaranes_lineas t6", "t6.albaran_id = t5.id", "left")
->where("t1.factura_id", $factura_id)
->where("t1.deleted_at", null);
@ -68,5 +72,30 @@ class FacturaLineaModel extends \App\Models\BaseModel {
->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,11 +23,19 @@ 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',
'factura_rectificada_id',
'factura_rectificativa_id',
'cliente_id',
'serie_id',
'numero',
@ -51,7 +59,7 @@ class FacturaModel extends \App\Models\BaseModel {
'updated_at',
'deleted_at',
'user_created_id',
'user_update_id'
'user_updated_id'
];
protected $returnType = "App\Entities\Facturas\FacturaEntity";
@ -72,13 +80,17 @@ class FacturaModel extends \App\Models\BaseModel {
"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, DATE_FORMAT(t3.fecha_vencimiento_at, '%d/%m/%Y') AS vencimiento"
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
@ -89,6 +101,30 @@ class FacturaModel extends \App\Models\BaseModel {
->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
@ -98,5 +134,14 @@ class FacturaModel extends \App\Models\BaseModel {
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

@ -14,12 +14,20 @@ class PedidoLineaModel extends \App\Models\BaseModel
protected $useAutoIncrement = true;
const SORTABLE = [
0 => "t1.id",
1 => "t1.estado",
2 => "t1.total_precio",
3 => "t1.total_tirada",
0 => "t2.id",
1 => "t2.updated_at",
2 => "t2.fecha_entrega_real",
3 => "t4.nombre",
4 => "CONCAT(t5.first_name, ' ', t5.last_name)",
5 => "t3.titulo",
6 => "t6.nombre",
7 => "t3.inc_rei",
8 => "t3.paginas",
9 => "t3.tirada",
10 => "t3.total_aceptado",
11 => "t2.estado"
];
protected $allowedFields = [
"pedido_id",
"presupuesto_id",
@ -40,7 +48,7 @@ class PedidoLineaModel extends \App\Models\BaseModel
public static $labelField = "id";
public function getResource(string $search = "", $estado="")
public function getResource($search = [], $estado="")
{
$builder = $this->db
->table($this->table . " t1")
@ -67,49 +75,146 @@ class PedidoLineaModel extends \App\Models\BaseModel
}
}
// Falta implementar la busqueda por grupos
return empty($search)
? $builder
: $builder
->groupStart()
->like("t1.id", $search)
->orLike("t1.id", $search)
->groupEnd();
if (empty($search))
return $builder;
else {
$builder->groupStart();
foreach ($search as $col_search) {
if ($col_search[0] != 1 && $col_search[0] != 2)
$builder->like(self::SORTABLE[$col_search[0]], $col_search[2]);
else {
$dates = explode(" ", $col_search[2]);
$builder->where(self::SORTABLE[$col_search[0]] . ">=", $dates[0]);
$builder->where(self::SORTABLE[$col_search[0]] . "<=", $dates[1]);
}
}
$builder->groupEnd();
return $builder;
}
}
public function obtenerLineasPedidoSinFacturar($cliente_id){
$resultaArray = [];
public function getSumOfTirada(array $search, $estado = '', $start = 0, $length = 5)
{
$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");
->selectSum('t3.tirada', 'total_tirada');
$builder->join("pedidos t2", "t2.id = t1.pedido_id", "left");
$builder->join("presupuestos t3", "t3.id = t1.presupuesto_id", "left");
$builder->join("tipos_presupuestos t4", "t4.id = t3.tipo_impresion_id", "left");
$builder->join("pedidos t2", "t2.id = t1.pedido_id", "left");
$builder->join("presupuestos t3", "t1.presupuesto_id = t3.id", "left");
$builder->join("facturas_pedidos_lineas fpl", "fpl.pedido_linea_id = t1.id", "left");
$builder->where("t3.cliente_id", $cliente_id);
$builder->where("t2.estado", "finalizado");
// Aplica los filtros de búsqueda y estado
if (!empty($search)) {
$builder->groupStart();
foreach ($search as $col_search) {
if ($col_search[0] != 1 && $col_search[0] != 2)
$builder->like(self::SORTABLE[$col_search[0]], $col_search[2]);
else {
$dates = explode(" ", $col_search[2]);
$builder->where(self::SORTABLE[$col_search[0]] . ">=", $dates[0]);
$builder->where(self::SORTABLE[$col_search[0]] . "<=", $dates[1]);
}
}
$builder->groupEnd();
}
if ($estado !== '') {
$builder->where('estado', $estado);
}
// Aplicar el orden y el límite
$builder->limit($length, $start);
return $builder->get()->getRow()->total_tirada;
}
public function getSumOfTotalAceptado(array $search, $estado = '', $start = 0, $length = 5)
{
$builder = $this->db
->table($this->table . " t1")
->selectSum('t3.total_aceptado', 'total');
$builder->join("pedidos t2", "t2.id = t1.pedido_id", "left");
$builder->join("presupuestos t3", "t1.presupuesto_id = t3.id", "left");
$builder->where("(`t3`.`tirada` > `fpl`.`cantidad` OR fpl.pedido_linea_id IS NULL)");
// Aplica los filtros de búsqueda y estado
if (!empty($search)) {
$builder->groupStart();
foreach ($search as $col_search) {
if ($col_search[0] != 1 && $col_search[0] != 2)
$builder->like(self::SORTABLE[$col_search[0]], $col_search[2]);
else {
$dates = explode(" ", $col_search[2]);
$builder->where(self::SORTABLE[$col_search[0]] . ">=", $dates[0]);
$builder->where(self::SORTABLE[$col_search[0]] . "<=", $dates[1]);
}
}
$builder->groupEnd();
}
if ($estado !== '') {
$builder->where('estado', $estado);
}
// Aplicar el orden y el límite
$builder
->limit($length, $start);
return $builder->get()->getRow()->total;
}
public function getTotalOfTotalAceptado()
{
$builder = $this->db
->table($this->table . " t1")
->selectSum('t3.total_aceptado', 'total');
$builder->join("pedidos t2", "t2.id = t1.pedido_id", "left");
$builder->join("presupuestos t3", "t1.presupuesto_id = t3.id", "left");
return $builder->get()->getRow()->total;
}
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){
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

@ -215,7 +215,7 @@ class PresupuestoModel extends \App\Models\BaseModel
", t2.nombre AS cliente, t3.nombre AS forma_pago, t4.nombre AS tipo_impresion, t5.nombre AS tipologia, t6.nombre AS pais, t7.estado AS estado, t8.id AS papel_formato, t9.first_name AS total_confirmado_user, t10.first_name AS aprobado_user FROM " .
$this->table .
" t1 LEFT JOIN clientes
t2 ON t1.cliente_id = t2.id LEFT JOIN lg_formas_pago
t2 ON t1.cliente_id = t2.id LEFT JOIN formas_pago
t3 ON t1.forma_pago_id = t3.id LEFT JOIN lg_tipos_impresion
t4 ON t1.tipo_impresion_id = t4.id LEFT JOIN lg_tipologias_libros
t5 ON t1.tipologia_id = t5.id LEFT JOIN lg_paises

View File

@ -21,7 +21,7 @@
<th><?= lang('Clientes.cif') ?></th>
<th><?= lang('Clientes.email') ?></th>
<th><?= lang('Users.comercial') ?></th>
<th><?= lang('FormasPagoes.formaDePago') ?></th>
<th><?= lang('FormasPago.formaDePago') ?></th>
<th><?= lang('Clientes.vencimiento') ?></th>
<th class="text-nowrap"><?= lang('Basic.global.Action') ?></th>
</tr>

View File

@ -1,12 +1,11 @@
<div class="row">
<div class="col-md-12 col-lg-12 px-4">
<div class="mb-3">
<label for="nombre" class="form-label">
<?=lang('FormasPagoes.nombre') ?>*
</label>
<input type="text" id="nombre" name="nombre" required maxLength="255" class="form-control" value="<?=old('nombre', $formaPagoEntity->nombre) ?>">
</div><!--//.mb-3 -->
</div><!--//.col -->
</div><!-- //.row -->
<div class="row">
<div class="col-md-12 col-lg-12 px-4">
<div class="mb-3">
<label for="nombre" class="form-label">
<?= lang('FormasPago.nombre') ?>*
</label>
<input type="text" id="nombre" name="nombre" required maxLength="255" class="form-control"
value="<?= old('nombre', $formaPagoEntity->nombre) ?>">
</div><!--//.mb-3 -->
</div><!--//.col -->
</div><!-- //.row -->

View File

@ -1,26 +1,45 @@
<?= $this->include("themes_commonPartialsBs/select2bs5") ?>
<?= $this->include("themes_commonPartialsBs/sweetalert") ?>
<?= $this->include("themes/_commonPartialsBs/sweetalert") ?>
<?= $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="formaDePagoForm" method="post" action="<?= $formAction ?>">
<?= csrf_field() ?>
<div class="card-body">
<?= view("themes_commonPartialsBs/_alertBoxes") ?>
<?= !empty($validation->getErrors()) ? $validation->listErrors("bootstrap_style") : "" ?>
<?= view("themes/vuexy/form/configuracion/formasPagoViews/_formaDePagoFormItems") ?>
</div><!-- /.card-body -->
<div class="card-footer">
<?= anchor(route_to("formaDePagoList"), lang("Basic.global.Cancel"), ["class" => "btn btn-secondary float-start"]) ?>
<input type="submit" class="btn btn-primary float-end" name="save" value="<?= lang("Basic.global.Save") ?>">
</div><!-- /.card-footer -->
</form>
</div><!-- //.card -->
<div class="card card-info">
<div class="card-header">
<h3 class="card-title"><?= $boxTitle ?? $pageTitle ?></h3>
</div><!--//.card-header -->
<form id="formaDePagoForm" class="card-body" method="post" action="<?= $formAction ?>">
<?= csrf_field() ?>
<div class="card-body">
<?= view("themes/_commonPartialsBs/_alertBoxes") ?>
<?= !empty($validation->getErrors()) ? $validation->listErrors("bootstrap_style") : "" ?>
<?= view("themes/vuexy/form/configuracion/formas-pago/_formaDePagoFormItems") ?>
</div><!-- /.card-body -->
<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("formasPagoList"),
lang("Basic.global.Cancel"),
["class" => "btn btn-secondary float-start",]
) ?>
</div>
</form>
</div><!-- //.card -->
</div><!--//.col -->
</div><!--//.row -->
<?= $this->endSection() ?>
<?= $this->section('additionalExternalJs') ?>
<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/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>
<?= $this->endSection() ?>

View File

@ -1,25 +1,23 @@
<?=$this->include('themes_commonPartialsBs/datatables') ?>
<?=$this->include('themes_commonPartialsBs/sweetalert') ?>
<?=$this->extend('themes'.config('Basics')->theme['name'].'/AdminLayout/defaultLayout') ?>
<?=$this->include('themes/_commonPartialsBs/datatables') ?>
<?=$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-md-12">
<div class="card card-info">
<div class="card-header">
<h3 class="card-title"><?=lang('FormasPagoes.formaDePagoList') ?></h3>
<h3 class="card-title"><?=lang('FormasPago.formaPagoList') ?></h3>
<?=anchor(route_to('formasPagoAdd'), lang('Basic.global.addNew').' '.lang('FormasPago.formaPago'), ['class'=>'btn btn-primary float-end']); ?>
</div><!--//.card-header -->
<div class="card-body">
<?= view('themes_commonPartialsBs/_alertBoxes'); ?>
<?= view('themes/_commonPartialsBs/_alertBoxes'); ?>
<table id="tableOfFormasdepagos" class="table table-striped table-hover" style="width: 100%;">
<thead>
<tr>
<th class="text-nowrap"><?= lang('Basic.global.Action') ?></th>
<th><?=lang('FormasPagoes.id')?></th>
<th><?= lang('FormasPagoes.nombre') ?></th>
<th><?= lang('FormasPagoes.createdAt') ?></th>
<th><?= lang('FormasPagoes.updatedAt') ?></th>
<th><?= lang('FormasPago.nombre') ?></th>
<th class="text-nowrap"><?= lang('Basic.global.Action') ?></th>
</tr>
</thead>
@ -29,7 +27,7 @@
</table>
</div><!--//.card-body -->
<div class="card-footer">
<?=anchor(route_to('newFormaDePago'), lang('Basic.global.addNew').' '.lang('FormasPagoes.formaDePago'), ['class'=>'btn btn-primary float-end']); ?>
</div><!--//.card-footer -->
</div><!--//.card -->
</div><!--//.col -->
@ -40,125 +38,83 @@
<?=$this->section('additionalInlineJs') ?>
const lastColNr = $('#tableOfFormasdepagos').find("tr:first th").length - 1;
const actionBtns = function(data) {
return `<td class="text-right py-0 align-middle">
<div class="btn-group btn-group-sm">
<button class="btn btn-sm btn-warning btn-edit me-1" data-id="${data.id}"><?= lang('Basic.global.edit') ?></button>
<button class="btn btn-sm btn-danger btn-delete ms-1" data-id="${data.id}"><?= lang('Basic.global.Delete') ?></button>
</div>
</td>`;
};
theTable = $('#tableOfFormasdepagos').DataTable({
processing: true,
serverSide: true,
autoWidth: true,
responsive: true,
scrollX: true,
lengthMenu: [ 5, 10, 25, 50, 75, 100, 250, 500, 1000, 2500 ],
pageLength: 10,
lengthChange: true,
"dom": 'lfrtipB', // 'lfBrtip', // you can try different layout combinations by uncommenting one or the other
// "dom": '<"top"lf><"clear">rt<"bottom"ipB><"clear">', // remember to comment this line if you uncomment the above
"buttons": [
'copy', 'csv', 'excel', 'print', {
extend: 'pdfHtml5',
orientation: 'landscape',
pageSize: 'A4'
}
],
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('dataTableOfFormasDePagos') ?>',
method: 'POST',
headers: {'X-Requested-With': 'XMLHttpRequest'},
async: true,
}),
columnDefs: [
{
orderable: false,
searchable: false,
targets: [0,lastColNr]
}
],
columns : [
{ 'data': actionBtns },
{ 'data': 'id' },
{ 'data': 'nombre' },
{ 'data': 'created_at' },
{ 'data': 'updated_at' },
{ 'data': actionBtns }
]
});
const lastColNr = $('#tableOfFormasdepagos').find("tr:first th").length - 1;
const actionBtns = 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-pencil ti-sm btn-edit mx-2" data-id="${data.id}"></i></a>
<a href="javascript:void(0);"><i class="ti ti-trash ti-sm btn-delete mx-2" data-id="${data.id}" data-bs-toggle="modal" data-bs-target="#confirm2delete"></i></a>
</div>
</td>`;
};
theTable.on( 'draw.dt', function () {
const dateCols = [3, 4];
const shortDateFormat = '<?= convertPhpDateToMomentFormat('mm/dd/YYYY')?>';
const dateTimeFormat = '<?= convertPhpDateToMomentFormat('mm/dd/YYYY h:i a')?>';
for (let coln of dateCols) {
theTable.column(coln, { page: 'current' }).nodes().each( function (cell, i) {
const datestr = cell.innerHTML;
const dateStrLen = datestr.toString().trim().length;
if (dateStrLen > 0) {
let dateTimeParts= datestr.split(/[- :]/); // regular expression split that creates array with: year, month, day, hour, minutes, seconds values
dateTimeParts[1]--; // monthIndex begins with 0 for January and ends with 11 for December so we need to decrement by one
const d = new Date(...dateTimeParts); // new Date(datestr);
const md = moment(d);
const usingThisFormat = dateStrLen > 11 ? dateTimeFormat : shortDateFormat;
const formattedDateStr = md.format(usingThisFormat);
cell.innerHTML = formattedDateStr;
}
});
theTable = $('#tableOfFormasdepagos').DataTable({
processing: true,
serverSide: true,
autoWidth: true,
responsive: true,
scrollX: true,
lengthMenu: [ 5, 10, 25, 50, 75, 100, 250, 500, 1000, 2500 ],
pageLength: 10,
lengthChange: true,
"dom": 'lfBrtip',
"buttons": [
'copy', 'csv', 'excel', 'print', {
extend: 'pdfHtml5',
orientation: 'landscape',
pageSize: 'A4'
}
],
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('formasPagoDT') ?>',
method: 'POST',
headers: {'X-Requested-With': 'XMLHttpRequest'},
async: true,
}),
columnDefs: [
{
orderable: false,
searchable: false,
targets: [0,lastColNr]
}
],
columns : [
{ 'data': 'nombre' },
{ 'data': actionBtns }
]
});
$(document).on('click', '.btn-edit', function(e) {
window.location.href = `<?= route_to('formaDePagoList') ?>/${$(this).attr('data-id')}/edit`;
$(document).on('click', '.btn-edit', function(e) {
window.location.href = `/configuracion/formas-pago/edit/${$(this).attr('data-id')}`;
});
$(document).on('click', '.btn-delete', function(e) {
Swal.fire({
title: '<?= lang('Basic.global.sweet.sureToDeleteTitle', [mb_strtolower(lang('FormasPagoes.forma de pago'))]) ?>',
text: '<?= lang('Basic.global.sweet.sureToDeleteText') ?>',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
confirmButtonText: '<?= lang('Basic.global.sweet.deleteConfirmationButton') ?>',
cancelButtonText: '<?= lang('Basic.global.Cancel') ?>',
cancelButtonColor: '#d33'
})
.then((result) => {
const dataId = $(this).data('id');
const row = $(this).closest('tr');
if (result.value) {
$.ajax({
url: `<?= route_to('formaDePagoList') ?>/${dataId}`,
method: 'DELETE',
}).done((data, textStatus, jqXHR) => {
Toast.fire({
icon: 'success',
title: data.msg ?? jqXHR.statusText,
});
theTable.clearPipeline();
theTable.row($(row)).invalidate().draw();
}).fail((jqXHR, textStatus, errorThrown) => {
Toast.fire({
icon: 'error',
title: jqXHR.responseJSON.messages.error,
});
})
}
});
$(document).on('click', '.btn-delete', function(e) {
$(".btn-remove").attr('data-id', $(this).attr('data-id'));
});
$(document).on('click', '.btn-remove', function(e) {
const dataId = $(this).attr('data-id');
const row = $(this).closest('tr');
if ($.isNumeric(dataId)) {
$.ajax({
url: `/configuracion/formas-pago/delete/${dataId}`,
method: 'GET',
}).done((data, textStatus, jqXHR) => {
$('#confirm2delete').modal('toggle');
theTable.clearPipeline();
theTable.row($(row)).invalidate().draw();
popSuccessAlert(data.msg ?? jqXHR.statusText);
}).fail((jqXHR, textStatus, errorThrown) => {
popErrorAlert(jqXHR.responseJSON.messages.error)
})
}
});

View File

@ -6,26 +6,29 @@
<?= $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="seriesFacturasForm" class="card-body" method="post" action="<?= $formAction ?>">
<?= csrf_field() ?>
<?= view("themes/_commonPartialsBs/_alertBoxes") ?>
<?= !empty($validation->getErrors()) ? $validation->listErrors("bootstrap_style") : "" ?>
<?= view("themes/vuexy/form/configuracion/series-facturas/_seriesFacturasFormItems") ?>
<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("seriesFacturasList"), lang("Basic.global.Cancel"), ["class" => "btn btn-secondary float-start",]) ?>
</div><!-- /.card-footer -->
</form>
</div><!-- //.card -->
<div class="card card-info">
<div class="card-header">
<h3 class="card-title"><?= $boxTitle ?? $pageTitle ?></h3>
</div><!--//.card-header -->
<form id="seriesFacturasForm" class="card-body" method="post" action="<?= $formAction ?>">
<?= csrf_field() ?>
<?= view("themes/_commonPartialsBs/_alertBoxes") ?>
<?= !empty($validation->getErrors()) ? $validation->listErrors("bootstrap_style") : "" ?>
<?= view("themes/vuexy/form/configuracion/series-facturas/_seriesFacturasFormItems") ?>
<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("seriesFacturasList"),
lang("Basic.global.Cancel"),
["class" => "btn btn-secondary float-start",]
) ?>
</div>
</form>
</div><!-- //.card -->
</div><!--//.col -->
</div><!--//.row -->
@ -33,20 +36,22 @@
<?=$this->section('css') ?>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/datatables-editor/editor.dataTables.min.css') ?>">
<link rel="stylesheet" href="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/buttons/buttons.bootstrap5.min.css") ?>">
<?=$this->endSection() ?>
<?= $this->section('css') ?>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/datatables-editor/editor.dataTables.min.css') ?>">
<link rel="stylesheet"
href="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/buttons/buttons.bootstrap5.min.css") ?>">
<?= $this->endSection() ?>
<?= $this->section('additionalExternalJs') ?>
<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/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>
<?=$this->endSection() ?>
<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/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>
<?= $this->endSection() ?>

View File

@ -112,7 +112,7 @@
const row = $(this).closest('tr');
if ($.isNumeric(dataId)) {
$.ajax({
url: `/configuracion/series-facturas//delete/${dataId}`,
url: `/configuracion/series-facturas/delete/${dataId}`,
method: 'GET',
}).done((data, textStatus, jqXHR) => {
$('#confirm2delete').modal('toggle');

View File

@ -117,13 +117,11 @@ $('#addNewPedidoImpresion').on('click', function(){
success: function(response) {
yeniden(response.<?= csrf_token() ?>);
// Se actualiza la tabla de lineas de factura
$('#tableOfLineasFactura').DataTable().clearPipeline();
$('#tableOfLineasFactura').DataTable().ajax.reload();
// 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();
$('#tableOfLineasFactura').DataTable().columns.adjust().draw();
}
});
});

View File

@ -11,7 +11,11 @@
<div class="accordion-body">
<div class="row">
<h4><?= lang('Facturas.factura') . ': '?> <span style="color:red;"> <?= lang('Facturas.' . $facturaEntity->estado)?> </span></h4>
<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">
@ -38,7 +42,7 @@
<label for="serie_id" class="form-label">
<?= lang('Facturas.serieFacturacion') ?>
</label>
<select id="serie_id" tabindex="2" name="serie_id" class="form-control select2bs2" style="width: 100%;">
<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>
@ -50,7 +54,7 @@
<label for="creditoAsegurado" class="form-label">
<?= lang('Facturas.creditoAsegurado') ?>
</label>
<select id="creditoAsegurado" tabindex="3" name="creditoAsegurado" class="form-control select2bs2" style="width: 100%;">
<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>
@ -63,7 +67,7 @@
<label for="fecha_factura_at" class="form-label">
<?= lang('Facturas.fechaFactura') ?>
</label>
<input type="text" value="" tabindex="4" id="fecha_factura_at" name="fecha_factura_at" tabindex="1" maxLength="11" class="form-control" value="<?= old('fecha_factura_at', $facturaEntity->fecha_factura_at) ?>" >
<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>
@ -76,7 +80,7 @@
<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 id="cliente_id" tabindex="5" name="tabindex="5"" class="form-control select2bs2" style="width: 100%;">
<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>
@ -86,12 +90,29 @@
<div class="row mb-2">
<div class="col-md-12 col-lg-6 px-4">
<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 id="cliente_nombre" name="cliente_nombre" tabindex="6" class="form-control"" value="<?= old('cliente_nombre', $facturaEntity->cliente_nombre) ?>"></input>
<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>
@ -100,7 +121,7 @@
<label for="cliente_cif" class="form-label">
<?= lang('Facturas.cif') ?>
</label>
<input id="cliente_cif" name="cliente_cif" tabindex="7" class="form-control" value="<?= old('cliente_cif', $facturaEntity->cliente_cif) ?>"></input>
<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>
@ -109,7 +130,7 @@
<label for="cliente_pais" class="form-label">
<?= lang('Facturas.pais') ?>
</label>
<input id="cliente_pais" name="cliente_pais" tabindex="8" class="form-control"" value="<?= old('cliente_pais', $facturaEntity->cliente_pais) ?>"></input>
<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>
@ -122,7 +143,7 @@
<label for="cliente_direccion" class="form-label">
<?= lang('Facturas.direccion') ?>
</label>
<input id="cliente_direccion" name="cliente_direccion" tabindex="6" class="form-control"" value="<?= old('cliente_address', $facturaEntity->cliente_address) ?>"></input>
<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>
@ -131,7 +152,7 @@
<label for="cliente_cp" class="form-label">
<?= lang('Facturas.cp') ?>
</label>
<input id="cliente_cp" name="cliente_cp" tabindex="7" class="form-control" value="<?= old('cliente_cp', $facturaEntity->cliente_cp) ?>"></input>
<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>
@ -140,7 +161,7 @@
<label for="cliente_ciudad" class="form-label">
<?= lang('Facturas.localidad') ?>
</label>
<input id="cliente_ciudad" name="cliente_ciudad" tabindex="8" class="form-control"" value="<?= old('cliente_ciudad', $facturaEntity->cliente_ciudad) ?>"></input>
<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>
@ -149,7 +170,7 @@
<label for="cliente_provincia" class="form-label">
<?= lang('Facturas.provincia') ?>
</label>
<input id="cliente_provincia" name="cliente_provincia" tabindex="8" class="form-control"" value="<?= old('cliente_provincia', $facturaEntity->cliente_provincia) ?>"></input>
<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>
@ -163,11 +184,11 @@
<?php if ($facturaEntity->estado === 'validada' && (auth()->user()->inGroup('beta') || auth()->user()->inGroup('admin'))) : ?>
<button
type="button"
class="btn btn-label-primary float-start me-sm-3 me-1"
name="pasarBorrador"
id="pasarBorrador" >
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("Facturas.pasarBorrador") ?>
<?= lang("Basic.global.edit") ?>
</button>
<?php endif; ?>
@ -304,4 +325,66 @@ $('#cliente_id').select2({
}
});
$('#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

@ -13,7 +13,7 @@
<table id="tableOfLineasFactura" class="table table-striped table-hover" style="width: 100%;grid-template-columns: 1fr 1fr 6fr 1fr 1fr 1fr;">
<thead>
<tr>
<th></th>
<th style="max-width:60px;"></th>
<th>id</th>
<th></th>
<th></th>
@ -31,26 +31,26 @@
</tbody>
<tfoot>
<tr>
<td colspan="8" style="text-align:right">Subtotal:</td>
<td colspan="9" style="text-align:right">Subtotal:</td>
<td id="subtotal-sum"></td>
<td></td>
<td></td>
</tr>
<tr>
<td colspan="8" style="text-align:right">I.V.A.:</td>
<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="8" style="text-align:right">Total:</td>
<td colspan="9" style="text-align:right">Total:</td>
<td id="total-sum"></td>
<td></td>
<td></td>
</tr>
<tr>
<td colspan="8" style="text-align:right">Pendiente de pago:</td>
<td id="pendiente-pago"></td>
<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>
@ -81,33 +81,54 @@
const actionBtns = function(data) {
// se comprueba si data es null
if (data.pedido_id === null) {
<?php if($facturaEntity->estado != 'borrador') :?>
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"><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>
<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>
</div>
<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>
</td>`;
}
else{
</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>
</td>`;
</div>
`;
}
<?php endif; ?>
};
var editor_lineas = new $.fn.dataTable.Editor( {
ajax: {
url: "<?= route_to('editorOfLineasFacturas') ?>",
@ -119,23 +140,57 @@ var editor_lineas = new $.fn.dataTable.Editor( {
idSrc: 'id',
fields: [
{
name: "unidades",
name: "cantidad",
}, {
name: "concepto"
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;
}
}
});
@ -155,9 +210,10 @@ editor_lineas.on( 'submitSuccess', function ( e, json, data, action ) {
// Activate an inline edit on click of a table cell
$('#tableOfLineasFactura').on( 'click', 'tbody span.edit', function (e) {
editor_lineas.inline(
tableLineas.cells(this.parentNode.parentNode, '*').nodes(),
{
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>',
@ -175,45 +231,102 @@ var tableLineas = $('#tableOfLineasFactura').DataTable({
responsive: true,
scrollX: true,
columns: [
{data: null, render: actionBtns},
{
data: actionBtns,
className: 'row-edit dt-center'
},
{data: "id"},
{data: "pedido_linea_impresion_id"},
{data: "pedido_maquetacion_id"},
{data: "pedido_id"},
{data: "unidades"},
{data: "cantidad"},
{
data: "concepto",
data: "descripcion",
render: function (data, type, row, meta) {
// se convierten a float data.total_aceptado y subtotal
var total_aceptado = parseFloat(row.total_aceptado);
var subtotal = parseFloat(row.subtotal);
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 + '€)';
var error_text = '';
if(total_aceptado != subtotal){
error_text = 'El total del pedido ('+ total_aceptado + '€) no coincide con la línea ('+ subtotal + '€)';
}
var returned_data = `
<div>
${data}
</div>
<div class="mt-5">
<span style="color: red;" id="error-${meta.row}">${error_text}</span>
</div>
<div class="row mt-2">
<div style="margin-top: auto;" class="col-md-12 col-lg-2 px-4">
<label for="total-aceptado_-${meta.row}">Total aceptado</label>
<input readonly style="max-width: 110px;" type="text" id="total-aceptado_${meta.row}" value="${row.total_aceptado}">
</div>
`;
if (row.tirada_flexible === "1"){
returned_data += `
<div style="margin-top: auto;" class="col-md-12 col-lg-2 px-4">
<label for="descuento-tf_${meta.row}">Descuento tirada flexible</label>
<input readonly style="max-width: 110px;" type="text" id="descuento-tf_${meta.row}" value="${row.descuento_tirada_flexible}">
</div>
<div style="margin-top: auto;" class="col-md-12 col-lg-2 px-4">
<label for="tirada-albaran_${meta.row}">Tirada albarán</label>
<input readonly style="max-width: 110px;" type="text" id="tirada-albaran_${meta.row}" value="${row.cantidad_albaran}">
</div>
`;
if(row.cantidad<row.cantidad_albaran){
returned_data += `
<div style="margin-top: auto;" class="col-md-12 col-lg-2 px-4">
<button
type="button"
class="btn btn-label-primary float-start me-sm-3 me-1 btn-excedentes"
name="btn-excedentes_${meta.row}"
id="btn-excedentes_${meta.row}"
data-row="${meta.row}"
>
<span class="ti-xs ti ti-circle-plus me-1"></span>
Excedentes
</button>
</div>
</div>
`;
}
else{
returned_data += `
</div>
`;
}
}
else{
returned_data += `
</div>
`;
}
return returned_data;
}
else{
return `
<div>
${data}
</div>
`;
}
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>
`;
}
},
{data: "precio_unidad"},
{data: "iva"},
{data: "subtotal"},
{data: "base"},
{data: "total_iva"},
{data: "total"},
],
@ -241,67 +354,123 @@ var tableLineas = $('#tableOfLineasFactura').DataTable({
],
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 totalSubtotal = api
.column(8)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
var totalIVA = api
.column(9)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
var totalTotal = api
.column(10)
.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
var pendientePago = totalTotal ;//- totalIVA;
$('#pendiente-pago').html(pendientePago.toFixed(2));
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,
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v
}
}).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) {
//$(".btn-remove").attr('data-id', $(this).attr('data-id'));
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, null, [dataId, row])
deleteConfirmedLinea, function(){}, [dataId, row])
}
});
function deleteConfirmed(params){
function deleteConfirmedLinea(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,
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v
}
}).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({
@ -324,4 +493,57 @@ $(document).on('click', '.btn-view_pedido', function(e) {
});
$('#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);
});
$(document).on('click', '.btn-excedentes', function(e) {
const row = $(this).data('row');
const row_data = tableLineas.row(row).data();
const pedido_id = row_data.pedido_id;
var pedido_linea_impresion_id = null;
var pedido_linea_maquetacion_id = null;
if(row_data.pedido_linea_impresion_id != null){
pedido_linea_impresion_id = row_data.pedido_linea_impresion_id
}
else{
pedido_linea_maquetacion_id = row_data.pedido_maquetacion_id
}
var factura_id = <?= $facturaEntity->id ?>;
var url = '<?= route_to('addLineaExcedentes', ':factura_id') ?>';
url = url.replace(':factura_id', factura_id );
$.ajax({
url: url,
method: 'POST',
data: {
pedido_id: pedido_id,
pedido_linea_impresion_id: pedido_linea_impresion_id,
pedido_linea_maquetacion_id: pedido_linea_maquetacion_id,
precio_unidad: row_data.precio_unidad,
descripcion: row_data.descripcion,
iva: row_data.iva,
descuento: row_data.descuento_tirada_flexible,
cantidad: parseInt(row_data.cantidad_albaran)-parseInt(row_data.cantidad),
<?= csrf_token() ?? "token" ?> : <?= csrf_token() ?>v
}
}).done((data, textStatus, jqXHR) => {
$('#tableOfLineasFactura').DataTable().clearPipeline();
$('#tableOfLineasFactura').DataTable().draw();
}).fail((jqXHR, textStatus, errorThrown) => {
popErrorAlert(jqXHR.responseJSON.messages.error)
})
});
<?=$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

@ -22,14 +22,35 @@
<?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">
<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"]) ?>
<?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 -->
@ -41,8 +62,46 @@
<?= $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() ?>
@ -51,6 +110,7 @@
<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') ?>
@ -64,6 +124,9 @@
<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>
@ -110,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){
@ -179,13 +197,14 @@
break;
default:
return '--'; // Debug
return data; // Debug
break;
}
}
},
{ 'data': 'vencimiento' },
{ 'data': 'dias_vencimiento' },
{ 'data': actionBtns }
]
});

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

@ -11,6 +11,14 @@
</div><!--//.card-header -->
<div class="card-body">
<?= view('themes/_commonPartialsBs/_alertBoxes'); ?>
<div class="row">
<div class="form-check form-check-inline">
<input type="checkbox" class="form-check-input" id="showTotal" name="showTotal">
<label for="showTotal" class="form-check-label">
<?= lang('Pedidos.showTotal') ?>
</label>
</div>
</div>
<table id="tableOfPedidos" class="table table-striped table-hover" style="width: 100%;">
<thead>
@ -23,11 +31,11 @@
<th><?= lang('Pedidos.titulo') ?></th>
<th><?= lang('Pedidos.ubicacion') ?></th>
<th><?= lang('Pedidos.inc_rei') ?></th>
<th><?= lang('Pedidos.num_paginas') ?></th>
<th><?= lang('Pedidos.tiradas') ?></th>
<th><?= lang('Pedidos.total_presupuesto') ?></th>
<th class='noFilter'><?= lang('Pedidos.num_paginas') ?></th>
<th class='totalizador'><?= lang('Pedidos.tiradas') ?></th>
<th class='totalizador'><?= lang('Pedidos.total_presupuesto') ?></th>
<th><?= lang('Pedidos.estado') ?></th>
<th class="text-nowrap"><?= lang('Basic.global.Action') ?></th>
<th class="noFilter text-nowrap"><?= lang('Basic.global.Action') ?></th>
</tr>
</thead>
<tbody>
@ -57,24 +65,130 @@
</td>`;
};
theTable = $('#tableOfPedidos').DataTable({
// Setup - add a text input to each footer cell
$('#tableOfPedidos thead tr').clone(true).appendTo('#tableOfPedidos thead');
$('#tableOfPedidos thead tr:eq(1) th').each(function (i) {
if (!$(this).hasClass("noFilter")) {
var title = $(this).text();
if($(this).hasClass("totalizador")){
if(i==9){
$(this).html('<label id="total_tirada" />');
}
else if(i==10){
$(this).html('<label id="total_aceptado" />');
}
}
else{
if(i==1 || i==2){
name = 'bs-rangepicker-range_' + i;
$(this).html('<input id="'+name+'" type="text" class="form-control " style="min-width:100px;max-width:120px;font-size:0.8rem !important;" />');
var bsRangePickerRange = $('#' + name);
bsRangePickerRange.daterangepicker({
ranges: {
'<?= lang('datePicker.hoy') ?>': [moment(), moment()],
'<?= lang('datePicker.ayer') ?>': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
'<?= lang('datePicker.ultimos7') ?>': [moment().subtract(6, 'days'), moment()],
'<?= lang('datePicker.ultimos30') ?>': [moment().subtract(29, 'days'), moment()],
'<?= lang('datePicker.esteMes') ?>': [moment().startOf('month'), moment().endOf('month')],
'<?= lang('datePicker.ultimoMes') ?>': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
},
opens: 'right',
language: '<?= config('Basics')->i18n ?>',
"locale": {
"customRangeLabel": "<?= lang('datePicker.personalizar') ?>",
"format": "YYYY-MM-DD",
"separator": " ",
"applyLabel": "<?= lang('datePicker.aplicar') ?>",
"cancelLabel": "<?= lang('datePicker.limpiar') ?>",
},
"alwaysShowCalendars": true,
autoUpdateInput: false,
});
bsRangePickerRange.on('apply.daterangepicker', function(ev, picker) {
$(this).val(picker.startDate.format('YYYY-MM-DD') + ' ' + picker.endDate.format('YYYY-MM-DD'));
theTable
.column(i)
.search(this.value)
.draw();
});
bsRangePickerRange.on('cancel.daterangepicker', function(ev, picker) {
$(this).val('');
theTable
.column(i)
.search(this.value)
.draw();
});
}
else if (i == 11) {
// Agregar un selector en la tercera columna
$(this).html('<select class="form-control" style="min-width:100px;max-width:120px;font-size:0.8rem !important;"></select>');
// Agregar opciones al selector
var selector = $('select', this);
selector.append('<option value="">Todos</option>'); // Opción vacía
selector.append('<option value="validacion"><?= lang('Pedidos.validacion') ?></option>');
selector.append('<option value="produccion"><?= lang('Pedidos.produccion') ?></option>');
selector.append('<option value="finalizado"><?= lang('Pedidos.finalizado') ?></option>');
selector.append('<option value="enviado"><?= lang('Pedidos.enviado') ?></option>');
selector.append('<option value="cancelado"><?= lang('Pedidos.cancelado') ?></option>');
selector.on('change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
theTable.column(i).search(val).draw();
});
}
else{
$(this).html('<input type="text" class="form-control " style="min-width:100px;max-width:120px;font-size:0.8rem !important;" />');
$('input', this).on('change clear', function () {
if (theTable.column(i).search() !== this.value) {
theTable
.column(i)
.search(this.value)
.draw();
}
});
}
}
}
else {
$(this).html('<span></span>');
}
});
var theTable = $('#tableOfPedidos').DataTable({
select: {
style: 'multi',
info: false
},
orderCellsTop: true,
fixedHeader: true,
processing: true,
serverSide: true,
autoWidth: true,
responsive: true,
searching: true,
scrollX: true,
lengthMenu: [ 5, 10, 25, 50, 75, 100, 250, 500, 1000, 2500 ],
pageLength: 50,
pageLength: 100,
lengthChange: true,
"dom": 'lfBrtip',
"dom": '<"mb-3"l>Brtip',
"buttons": [
'copy', 'csv', 'excel', 'print', {
'colvis', 'copy', 'csv', 'excel', 'print', {
extend: 'pdfHtml5',
orientation: 'landscape',
pageSize: 'A4'
}
],
stateSave: true,
stateSave: false,
order: [[0, 'asc']],
language: {
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
@ -82,8 +196,9 @@
ajax : $.fn.dataTable.pipeline( {
url: '<?= route_to('dataTableOfPedidos') ?>',
method: 'POST',
data: {
estado: "<?= $estadoPedidos ?>",
data: function(d, settings){
d.estado= "<?= $estadoPedidos ?>";
d.showTotal= $('#showTotal').is(':checked')? "1":"0";
},
headers: {'X-Requested-With': 'XMLHttpRequest'},
async: true,
@ -91,7 +206,7 @@
columnDefs: [
{
orderable: false,
searchable: false,
searchable: true,
targets: [lastColNr]
}
],
@ -138,39 +253,76 @@
}
},
{ 'data': actionBtns }
]
],
drawCallback: function (settings) {
$('#total_tirada').text(settings.json.extra.total_tirada);
$('#total_aceptado').text(settings.json.extra.total);
}
});
theTable.on( 'draw.dt', function () {
const boolCols = [];
for (let coln of boolCols) {
const dateCols = [1,2];
const priceCols = [10];
for (let coln of dateCols) {
theTable.column(coln, { page: 'current' }).nodes().each( function (cell, i) {
cell.innerHTML = cell.innerHTML == '1' ? '<i class="ti ti-check"></i>' : '';
const datestr = cell.innerHTML;
const dateStrLen = datestr.toString().trim().length;
if (dateStrLen > 0) {
let dateTimeParts= datestr.split(/[- :]/); // regular expression split that creates array with: year, month, day, hour, minutes, seconds values
dateTimeParts[1]--; // monthIndex begins with 0 for January and ends with 11 for December so we need to decrement by one
const d = new Date(...dateTimeParts); // new Date(datestr);
cell.innerHTML = d.toLocaleDateString();
}
});
}
for (let coln of priceCols) {
theTable.column(coln, { page: 'current' }).nodes().each( function (cell, i) {
cell.innerHTML = parseFloat(cell.innerHTML).toFixed(2);
});
}
});
$(document).on('click', '.btn-edit', function(e) {
var url = '<?= route_to('editarPedido', ':id') ?>';
url = url.replace(':id', `${$(this).attr('data-id')}` );
window.location.href = url;
});
theTable.on('click', 'tbody tr', function (e) {
e.currentTarget.classList.toggle('selected');
});
$('#showTotal').on('change', function() {
theTable.clearPipeline();
theTable.ajax.reload(null, false);
//theTable.draw();
});
<?=$this->endSection() ?>
<?=$this->section('css') ?>
<link rel="stylesheet" href="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/buttons/buttons.bootstrap5.min.css") ?>">
<link rel="stylesheet" href="<?= site_url("/themes/vuexy/vendor/libs/datatables-sk/plugins/fixedheader/fixedHeader.dataTables.min.css") ?>">
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/bootstrap-daterangepicker/bootstrap-daterangepicker.css') ?>" />
<?=$this->endSection() ?>
<?= $this->section('additionalExternalJs') ?>
<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/select/dataTables.select.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/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/buttons/buttons.colVis.min.js") ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/moment/moment.js') ?>"></script>
<script src="<?= site_url('themes/vuexy/vendor/libs/bootstrap-daterangepicker/bootstrap-daterangepicker.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>

View File

@ -4,14 +4,15 @@
*/
if (
auth()->user()->can('paises.menu') ||
auth()->user()->can('papeles-genericos.menu') ||
auth()->user()->can('papeles-impresion.menu') ||
auth()->user()->can('formas-pago.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') ||
auth()->user()->can('roles-permisos.menu')
) {
?>
?>
<li class="menu-item">
<a href="javascript:void(0);" class="menu-link menu-toggle">
<i class="menu-icon tf-icons ti ti-adjustments-horizontal"></i>
@ -25,14 +26,21 @@ if (
</a>
</li>
<?php } ?>
<?php if (auth()->user()->can('papeles-genericos.menu')) { ?>
<?php if (auth()->user()->can('formas-pago.menu')) { ?>
<li class="menu-item">
<a href="<?= route_to('formasPagoList') ?>" class="menu-link">
<?= lang("App.menu_formas_pago") ?>
</a>
</li>
<?php } ?>
<?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") ?>
@ -40,32 +48,32 @@ if (
</li>
<?php } ?>
<?php if (auth()->user()->can('maquinas.menu')) { ?>
<li class="menu-item">
<a href="<?= site_url("configuracion/maquinas") ?>" class="menu-link">
<?= lang("App.menu_maquina") ?>
</a>
</li>
<li class="menu-item">
<a href="<?= site_url("configuracion/maquinas") ?>" class="menu-link">
<?= lang("App.menu_maquina") ?>
</a>
</li>
<?php } ?>
<?php if (auth()->user()->can('maquinas-defecto.menu')) { ?>
<li class="menu-item">
<a href="<?= site_url("configuracion/maquinasdefecto") ?>" class="menu-link">
<?= lang("App.menu_maquina_defecto") ?>
</a>
</li>
<li class="menu-item">
<a href="<?= site_url("configuracion/maquinasdefecto") ?>" class="menu-link">
<?= lang("App.menu_maquina_defecto") ?>
</a>
</li>
<?php } ?>
<?php if (auth()->user()->can('usuarios.menu')) { ?>
<li class="menu-item">
<a href="<?= site_url("configuracion/users") ?>" class="menu-link">
<?= lang("App.menu_users") ?>
</a>
</li>
<li class="menu-item">
<a href="<?= site_url("configuracion/users") ?>" class="menu-link">
<?= lang("App.menu_users") ?>
</a>
</li>
<?php } ?>
<?php if (auth()->user()->can('roles-permisos.menu')) { ?>
<li class="menu-item">
<a href="<?= site_url("configuracion/group") ?>" class="menu-link">
<?= lang("App.menu_permission_group") ?>
</a>
</li>
<li class="menu-item">
<a href="<?= site_url("configuracion/group") ?>" class="menu-link">
<?= lang("App.menu_permission_group") ?>
</a>
</li>
<?php } ?>
<?php if (auth()->user()->can('ubicaciones.menu')) { ?>
<li class="menu-item">

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