Merge branch 'feat/edit_factura' into 'main'

Feat/edit factura

See merge request jjimenez/safekat!293
This commit is contained in:
2024-07-30 11:32:55 +00:00
27 changed files with 1433 additions and 248 deletions

View File

@ -655,13 +655,22 @@ $routes->group('facturas', ['namespace' => 'App\Controllers\Facturacion'], funct
$routes->get('add', 'Facturas::add', ['as' => 'newFactura']); $routes->get('add', 'Facturas::add', ['as' => 'newFactura']);
$routes->post('add', 'Facturas::add', ['as' => 'createFactura']); $routes->post('add', 'Facturas::add', ['as' => 'createFactura']);
$routes->get('edit/(:any)', 'Facturas::edit/$1', ['as' => 'editarFactura']); $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('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('datatable/(:any)', 'FacturasLineas::datatable/$1', ['as' => 'dataTableOfLineasFacturas']);
$routes->post('menuPedidosPendientes/(:num)', 'Facturas::menuPedidosPendientes/$1', ['as' => 'menuPedidosPendientesImpresion']); $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('addLineaPedidoImpresion/(:num)', 'Facturas::addLineaPedidoImpresion/$1', ['as' => 'addLineaPedidoImpresion2Factura']); $routes->post('addLineaPedidoImpresion/(:num)', 'Facturas::addLineaPedidoImpresion/$1', ['as' => 'addLineaPedidoImpresion2Factura']);
$routes->get('deleteLinea/(:any)', 'FacturasLineas::deleteLinea/$1', ['as' => 'deleteLineaFactura']); $routes->get('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('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']);
}); });

View File

@ -143,6 +143,11 @@ class Facturas extends \App\Controllers\BaseResourceController
helper('form'); 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; $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]); $message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Facturas.factura')), $id]);
return $this->redirect2listView('sweet-error', $message); return $this->redirect2listView('sweet-error', $message);
endif; endif;
$this->obtenerDatosFormulario($factura); $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['facturaEntity'] = $factura;
$this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('Facturas.factura') . ' ' . lang('Basic.global.edit3'); $this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('Facturas.factura') . ' ' . lang('Basic.global.edit3');
@ -313,6 +324,72 @@ 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();
$data = [
'base' => $postData['base'] ?? 0,
'total' => $postData['total'] ?? 0,
'pendiente' => $postData['pendiente'] ?? 0,
'total_pagos' => $postData['total_pagos'] ?? 0,
'user_updated_id' => auth()->user()->id,
'estado_pago' => (intval($postData['pendiente'] ?? 0)==0) ? 'pagada' : 'pendiente',
];
$newTokenHash = csrf_hash();
$csrfTokenName = csrf_token();
$data_ret = [
$csrfTokenName => $newTokenHash
];
if($factura_id == 0){
return $this->respond($data_ret);
}
$data_ret['estado_pago'] = $data['estado_pago'];
$model = model('\App\Models\Facturas\FacturaModel');
$model->update($factura_id, $data);
return $this->respond($data_ret);
}
else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function addLineaPedidoImpresion($factura_id){ public function addLineaPedidoImpresion($factura_id){
@ -386,6 +463,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 * FUNCIONES AUXILIARES
************************************/ ************************************/
@ -407,6 +591,9 @@ class Facturas extends \App\Controllers\BaseResourceController
$serieModel = model('App\Models\Configuracion\SeriesFacturasModel'); $serieModel = model('App\Models\Configuracion\SeriesFacturasModel');
$serie = $serieModel->find($factura->serie_id); $serie = $serieModel->find($factura->serie_id);
$factura->serie_nombre = $serie->nombre; $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)) : ''; $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"); include(APPPATH . "ThirdParty/DatatablesEditor/DataTables.php");
// Build our Editor instance and process the data coming from _POST // 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( ->fields(
Field::inst( 'plantilla_id' ), Field::inst( 'id' ),
Field::inst( 'tipo' ), Field::inst( 'base' ),
Field::inst( 'tipo_maquina' ), Field::inst( 'total_iva' ),
Field::inst( 'tipo_impresion' ), 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( '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) { ->on('preCreate', function ($editor, &$values) {
$session = session(); $totales = $this->generate_totales(
$datetime = (new \CodeIgniter\I18n\Time("now")); $values['factura_id'],
$values['pedido_linea_impresion_id'],
$values['precio_unidad'],
$values['iva'],
$values['cantidad'],
$values['old_cantidad']);
$editor $editor
->field('user_updated_id') ->field('user_updated_id')
->setValue($session->id_user); ->setValue(auth()->user()->id);
$editor $editor
->field('updated_at') ->field('base')
->setValue($datetime->format('Y-m-d H:i:s')); ->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) { ->on('preEdit', function ($editor, $id, &$values) {
$session = session(); $totales = $this->generate_totales(
$datetime = (new \CodeIgniter\I18n\Time("now")); $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 $editor
->field('user_updated_id') ->field('user_updated_id')
->setValue($session->id_user); ->setValue(auth()->user()->id);
$editor $editor
->field('updated_at') ->field('base')
->setValue($datetime->format('Y-m-d H:i:s')); ->setValue($totales['base']);
$editor
->field('total_iva')
->setValue($totales['total_iva']);
$editor
->field('total')
->setValue($totales['total']);
}) })
->debug(true) ->debug(true)
->process($_POST) ->process($_POST)
@ -189,4 +193,36 @@ class FacturasLineas extends \App\Controllers\BaseResourceController
return $this->failUnauthorized('Invalid request', 403); 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

@ -398,7 +398,7 @@ class Presupuestocliente extends \App\Controllers\BaseResourceController
'servicios' => $servicios, 'servicios' => $servicios,
); );
$return_data = $this->calcular_presupuesto($datos_presupuesto, 0, true); //TRUE FOR DEBUG $return_data = $this->calcular_presupuesto($datos_presupuesto, 0, false); //TRUE FOR DEBUG
array_merge($return_data, [$csrfTokenName => $newTokenHash]); array_merge($return_data, [$csrfTokenName => $newTokenHash]);
return $this->respond($return_data); return $this->respond($return_data);

View File

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

View File

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

View File

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

View File

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

View File

@ -22,6 +22,7 @@ return [
'serieFacturacion' => 'Billing Series', 'serieFacturacion' => 'Billing Series',
'creditoAsegurado' => 'Secured Credit', 'creditoAsegurado' => 'Secured Credit',
'facturaRectificada' => 'Rectified Invoice', 'facturaRectificada' => 'Rectified Invoice',
'facturaRectificativa' => 'Rectifying Invoice',
'razonSocial' => 'Business Name', 'razonSocial' => 'Business Name',
'cif' => 'Tax ID', 'cif' => 'Tax ID',
'direccion' => 'Address', 'direccion' => 'Address',
@ -61,8 +62,23 @@ return [
'peiddoImpresion' => 'Print Order', 'peiddoImpresion' => 'Print Order',
'peiddoMaquetacion' => 'Layout Order', 'peiddoMaquetacion' => 'Layout Order',
'nuevaLinea' => 'New Line', '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' => [ 'errors' => [
'requiredFields' => 'Fields marked with * are required', 'requiredFields' => 'Fields marked with * are required',
] ],
'validation' => [
'numerico' => 'Must be numeric',
'requerido' => 'Required',
'decimal' => 'Must be decimal',
],
]; ];

View File

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

View File

@ -22,6 +22,7 @@ return [
'serieFacturacion' => 'Serie facturación', 'serieFacturacion' => 'Serie facturación',
'creditoAsegurado' => 'Crédito asegurado', 'creditoAsegurado' => 'Crédito asegurado',
'facturaRectificada' => 'Factura rectificada', 'facturaRectificada' => 'Factura rectificada',
'facturaRectificativa' => 'Factura rectificativa',
'razonSocial' => 'Razón Social', 'razonSocial' => 'Razón Social',
'cif' => 'CIF', 'cif' => 'CIF',
'direccion' => 'Dirección', 'direccion' => 'Dirección',
@ -61,8 +62,24 @@ return [
'pedidoImpresion' => 'Pedido Impresión', 'pedidoImpresion' => 'Pedido Impresión',
'pedidoMaquetacion' => 'Pedido Maquetación', 'pedidoMaquetacion' => 'Pedido Maquetación',
'nuevaLinea' => 'Nueva Línea', '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' => [ 'errors' => [
'requiredFields' => 'Los campos marcados con * son obligatorios', '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

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

View File

@ -108,4 +108,19 @@ class SeriesFacturasModel extends \App\Models\BaseModel
return $result; 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,8 +38,8 @@ class FacturaLineaModel extends \App\Models\BaseModel {
->select( ->select(
"t1.id AS id, t1.factura_id AS factura_id, "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.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.descripcion AS descripcion, t1.cantidad as cantidad, 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, 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" t3.total_aceptado AS total_aceptado"
) )
->join("pedidos_linea t2", "t2.id = t1.pedido_linea_impresion_id", "left") ->join("pedidos_linea t2", "t2.id = t1.pedido_linea_impresion_id", "left")
@ -68,5 +68,30 @@ class FacturaLineaModel extends \App\Models\BaseModel {
->where("pedido_linea_id", $pedido_linea_id) ->where("pedido_linea_id", $pedido_linea_id)
->where("cantidad", $cantidad) ->where("cantidad", $cantidad)
->delete(); ->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

@ -26,8 +26,8 @@ class FacturaModel extends \App\Models\BaseModel {
// Lista de columnas basada en los campos de la tabla, para asignación masiva // Lista de columnas basada en los campos de la tabla, para asignación masiva
protected $allowedFields = [ protected $allowedFields = [
'pedido_id', 'pedido_id',
'factura_retificada_id', 'factura_rectificada_id',
'factura_retificativa_id', 'factura_rectificativa_id',
'cliente_id', 'cliente_id',
'serie_id', 'serie_id',
'numero', 'numero',
@ -51,7 +51,7 @@ class FacturaModel extends \App\Models\BaseModel {
'updated_at', 'updated_at',
'deleted_at', 'deleted_at',
'user_created_id', 'user_created_id',
'user_update_id' 'user_updated_id'
]; ];
protected $returnType = "App\Entities\Facturas\FacturaEntity"; protected $returnType = "App\Entities\Facturas\FacturaEntity";
@ -72,13 +72,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, "t1.id AS id, t1.numero AS numero, DATE_FORMAT(t1.fecha_factura_at, '%d/%m/%Y') AS fecha_factura_at,
t2.nombre AS cliente, t1.base AS base, t1.total AS total, t1.pendiente AS pendiente, t2.nombre AS cliente, t1.base AS base, t1.total AS total, t1.pendiente AS pendiente,
t1.creditoAsegurado AS creditoAsegurado, t1.estado AS estado, t1.estado_pago AS estado_pago, t1.creditoAsegurado AS creditoAsegurado, t1.estado AS estado, t1.estado_pago AS estado_pago,
t4.nombre AS forma_pago, 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("clientes t2", "t2.id = t1.cliente_id", "left");
$builder->join("facturas_pagos t3", "t3.factura_id = t1.id", "left"); $builder->join("facturas_pagos t3", "t3.factura_id = t1.id", "left");
$builder->join("formas_pago t4", "t3.forma_pago_id = t4.id", "left"); $builder->join("formas_pago t4", "t3.forma_pago_id = t4.id", "left");
$builder->where("t1.deleted_at IS NULL");
$builder->groupBy("t1.id"); // Agrupa por id de la factura
return empty($search) return empty($search)
? $builder ? $builder
@ -98,5 +102,14 @@ class FacturaModel extends \App\Models\BaseModel {
return $builder->get()->getRow()->cantidad; return $builder->get()->getRow()->cantidad;
} }
public function deleteFacturasLineasPedido($factura_id, $pedido_linea_id, $cantidad)
{
$this->db->table("facturas_pedidos_lineas")
->where("factura_id", $factura_id)
->where("pedido_linea_id", $pedido_linea_id)
->where("cantidad", $cantidad)
->delete();
}
} }

View File

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

View File

@ -78,38 +78,39 @@ class PedidoLineaModel extends \App\Models\BaseModel
} }
public function obtenerLineasPedidoSinFacturar($cliente_id){ public function obtenerLineasPedidoSinFacturar($cliente_id) {
$resultaArray = []; $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 $builder = $this->db
->table($this->table . " t1") ->table($this->table . " t1")
->select("t1.id AS id, t1.pedido_id AS pedido_id, t3.titulo AS titulo, t4.codigo AS tipo_impresion"); ->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")
$builder->join("pedidos t2", "t2.id = t1.pedido_id", "left"); ->join("presupuestos t3", "t3.id = t1.presupuesto_id", "left")
$builder->join("presupuestos t3", "t3.id = t1.presupuesto_id", "left"); ->join("tipos_presupuestos t4", "t4.id = t3.tipo_impresion_id", "left")
$builder->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)
$builder->join("facturas_pedidos_lineas fpl", "fpl.pedido_linea_id = t1.id", "left"); ->where("t2.estado", "finalizado")
->where("(t3.tirada > IFNULL(fpl.total_cantidad, 0))");
$builder->where("t3.cliente_id", $cliente_id);
$builder->where("t2.estado", "finalizado");
$builder->where("(`t3`.`tirada` > `fpl`.`cantidad` OR fpl.pedido_linea_id IS NULL)");
// Ejecutar la consulta y devolver resultados // Ejecutar la consulta y devolver resultados
$query = $builder->get(); $query = $builder->get();
$data = $query->getResult(); $data = $query->getResult();
foreach($data as $register){ foreach($data as $register) {
$item = (object)[ $item = (object)[
'id' => $register->id, 'id' => $register->id,
'text' => '['. lang('Pedidos.pedido') . ' ' . $register->pedido_id . '] ' . $register->titulo . ' - ' . lang('Presupuestos.' . $register->tipo_impresion), 'text' => '['. lang('Pedidos.pedido') . ' ' . $register->pedido_id . '] ' . $register->titulo . ' - ' . lang('Presupuestos.' . $register->tipo_impresion),
]; ];
array_push($resultaArray, $item); array_push($resultaArray, $item);
} }
return $resultaArray; return $resultaArray;
} }
} }

View File

@ -117,13 +117,12 @@ $('#addNewPedidoImpresion').on('click', function(){
success: function(response) { success: function(response) {
yeniden(response.<?= csrf_token() ?>); 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 // se ajustan el ancho de las columnas
$('#tableOfLineasFactura').DataTable().columns.adjust().draw(); $('#tableOfLineasFactura').DataTable().columns.adjust().draw();
$('#pedidoImpresion').val(null).trigger('change'); $('#pedidoImpresion').val(null).trigger('change');
// Se actualiza la tabla de lineas de factura
tableLineas.clearPipeline();
tableLineas.draw();
} }
}); });
}); });

View File

@ -11,7 +11,11 @@
<div class="accordion-body"> <div class="accordion-body">
<div class="row"> <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>
<div class="row mb-2"> <div class="row mb-2">
@ -38,7 +42,7 @@
<label for="serie_id" class="form-label"> <label for="serie_id" class="form-label">
<?= lang('Facturas.serieFacturacion') ?> <?= lang('Facturas.serieFacturacion') ?>
</label> </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> <option value="<?= old('serie_id', $facturaEntity->serie_id) ?>" selected><?= old('serie_nombre', $facturaEntity->serie_nombre) ?></option>
</select> </select>
</div> </div>
@ -50,7 +54,7 @@
<label for="creditoAsegurado" class="form-label"> <label for="creditoAsegurado" class="form-label">
<?= lang('Facturas.creditoAsegurado') ?> <?= lang('Facturas.creditoAsegurado') ?>
</label> </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="0" <?= ($facturaEntity->creditoAsegurado == 0)?'selected':'' ?>> <?= lang('Basic.global.no') ?> </option>
<option value="1" <?= ($facturaEntity->creditoAsegurado == 1)?'selected':'' ?>> <?= lang('Basic.global.yes') ?> </option> <option value="1" <?= ($facturaEntity->creditoAsegurado == 1)?'selected':'' ?>> <?= lang('Basic.global.yes') ?> </option>
</select> </select>
@ -63,7 +67,7 @@
<label for="fecha_factura_at" class="form-label"> <label for="fecha_factura_at" class="form-label">
<?= lang('Facturas.fechaFactura') ?> <?= lang('Facturas.fechaFactura') ?>
</label> </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>
</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> <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> </div>
</label> </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> <option value="<?= old('cliente_id', $facturaEntity->cliente_id) ?>" selected><?= old('cliente_alias', $facturaEntity->cliente_alias) ?></option>
</select> </select>
</div> </div>
@ -86,12 +90,29 @@
<div class="row mb-2"> <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"> <div class="mb-1">
<label for="cliente_nombre" class="form-label"> <label for="cliente_nombre" class="form-label">
<?= lang('Facturas.razonSocial') ?> <?= lang('Facturas.razonSocial') ?>
</label> </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>
</div> </div>
@ -100,7 +121,7 @@
<label for="cliente_cif" class="form-label"> <label for="cliente_cif" class="form-label">
<?= lang('Facturas.cif') ?> <?= lang('Facturas.cif') ?>
</label> </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>
</div> </div>
@ -109,7 +130,7 @@
<label for="cliente_pais" class="form-label"> <label for="cliente_pais" class="form-label">
<?= lang('Facturas.pais') ?> <?= lang('Facturas.pais') ?>
</label> </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>
</div> </div>
@ -122,7 +143,7 @@
<label for="cliente_direccion" class="form-label"> <label for="cliente_direccion" class="form-label">
<?= lang('Facturas.direccion') ?> <?= lang('Facturas.direccion') ?>
</label> </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>
</div> </div>
@ -131,7 +152,7 @@
<label for="cliente_cp" class="form-label"> <label for="cliente_cp" class="form-label">
<?= lang('Facturas.cp') ?> <?= lang('Facturas.cp') ?>
</label> </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>
</div> </div>
@ -140,7 +161,7 @@
<label for="cliente_ciudad" class="form-label"> <label for="cliente_ciudad" class="form-label">
<?= lang('Facturas.localidad') ?> <?= lang('Facturas.localidad') ?>
</label> </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>
</div> </div>
@ -149,7 +170,7 @@
<label for="cliente_provincia" class="form-label"> <label for="cliente_provincia" class="form-label">
<?= lang('Facturas.provincia') ?> <?= lang('Facturas.provincia') ?>
</label> </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>
</div> </div>
@ -163,11 +184,11 @@
<?php if ($facturaEntity->estado === 'validada' && (auth()->user()->inGroup('beta') || auth()->user()->inGroup('admin'))) : ?> <?php if ($facturaEntity->estado === 'validada' && (auth()->user()->inGroup('beta') || auth()->user()->inGroup('admin'))) : ?>
<button <button
type="button" type="button"
class="btn btn-label-primary float-start me-sm-3 me-1" class="btn btn-label-danger float-start me-sm-3 me-1"
name="pasarBorrador" name="editarValidada"
id="pasarBorrador" > id="editarValidada" >
<span class="ti-xs ti ti-save me-1"></span> <span class="ti-xs ti ti-save me-1"></span>
<?= lang("Facturas.pasarBorrador") ?> <?= lang("Basic.global.edit") ?>
</button> </button>
<?php endif; ?> <?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() ?> <?=$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;"> <table id="tableOfLineasFactura" class="table table-striped table-hover" style="width: 100%;grid-template-columns: 1fr 1fr 6fr 1fr 1fr 1fr;">
<thead> <thead>
<tr> <tr>
<th></th> <th style="max-width:60px;"></th>
<th>id</th> <th>id</th>
<th></th> <th></th>
<th></th> <th></th>
@ -31,26 +31,26 @@
</tbody> </tbody>
<tfoot> <tfoot>
<tr> <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 id="subtotal-sum"></td>
<td></td> <td></td>
<td></td> <td></td>
</tr> </tr>
<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 id="total-iva-sum"></td>
<td></td> <td></td>
<td></td> <td></td>
</tr> </tr>
<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 id="total-sum"></td>
<td></td> <td></td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td colspan="8" style="text-align:right">Pendiente de 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 id="pendiente-pago"></td> <td <?= ($facturaEntity->serie_id == 7 || $facturaEntity->serie_id == 9)? "style='display:none;'":"" ?> id="pendiente-pago"></td>
<td></td> <td></td>
<td></td> <td></td>
</tr> </tr>
@ -81,33 +81,54 @@
const actionBtns = function(data) { const actionBtns = function(data) {
// se comprueba si data es null // se comprueba si data es null
if (data.pedido_id === null) { <?php if($facturaEntity->estado != 'borrador') :?>
if (data.pedido_id != null) {
return ` return `
<td class="text-right py-0 align-middle"> <div class="text-right py-0 align-middle">
<div class="row mb-2"> <div class="row">
<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> <button type="button" class="btn btn-sm btn-primary btn-view_pedido" data-id="${data.pedido_id}">Ver pedido</button>
<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> </div>
</td>`; </div>
} `;
else{ }
else
{
return ``;
}
<?php else: ?>
if (data.pedido_id === null) {
return ` return `
<td class="text-right py-0 align-middle"> <td class="text-right py-0 align-middle">
<div class="row mb-2"> <div class="row mb-2">
<div class="btn-group btn-group-sm"> <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> <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="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> </div>
<div class="row"> <div class="row">
<button type="button" class="btn btn-sm btn-primary btn-view_pedido" data-id="${data.pedido_id}">Ver pedido</button> <button type="button" class="btn btn-sm btn-primary btn-view_pedido" data-id="${data.pedido_id}">Ver pedido</button>
</div> </div>
</td>`; </div>
`;
} }
<?php endif; ?>
}; };
var editor_lineas = new $.fn.dataTable.Editor( { var editor_lineas = new $.fn.dataTable.Editor( {
ajax: { ajax: {
url: "<?= route_to('editorOfLineasFacturas') ?>", url: "<?= route_to('editorOfLineasFacturas') ?>",
@ -119,23 +140,57 @@ var editor_lineas = new $.fn.dataTable.Editor( {
idSrc: 'id', idSrc: 'id',
fields: [ fields: [
{ {
name: "unidades", name: "cantidad",
}, { }, {
name: "concepto" name: "descripcion",
type: "textarea",
attr: {
rows: 5,
style: "height: 120px;"
}
}, { }, {
name: "precio_unidad", 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 ) { editor_lineas.on( 'preSubmit', function ( e, d, type ) {
if ( type === 'create'){ if ( type === 'create'){
d.data[0]['factura_id'] = <?= $facturaEntity->id ?>; d.data[0]['factura_id'] = <?= $facturaEntity->id ?>;
d.data[0]['old_cantidad'] = null;
} }
else if(type === 'edit' ) { else if(type === 'edit' ) {
for (v in d.data){ for (v in d.data){
d.data[v]['factura_id'] = <?= $facturaEntity->id ?>; 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 // Activate an inline edit on click of a table cell
$('#tableOfLineasFactura').on( 'click', 'tbody span.edit', function (e) { $('#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>', cancelHtml: '<a href="javascript:void(0);"><i class="ti ti-x"></i></a>',
cancelTrigger: 'span.cancel', cancelTrigger: 'span.cancel',
submitHtml: '<a href="javascript:void(0);"><i class="ti ti-device-floppy"></i></a>', submitHtml: '<a href="javascript:void(0);"><i class="ti ti-device-floppy"></i></a>',
@ -175,45 +231,58 @@ var tableLineas = $('#tableOfLineasFactura').DataTable({
responsive: true, responsive: true,
scrollX: true, scrollX: true,
columns: [ columns: [
{data: null, render: actionBtns}, {
data: actionBtns,
className: 'row-edit dt-center'
},
{data: "id"}, {data: "id"},
{data: "pedido_linea_impresion_id"}, {data: "pedido_linea_impresion_id"},
{data: "pedido_maquetacion_id"}, {data: "pedido_maquetacion_id"},
{data: "pedido_id"}, {data: "pedido_id"},
{data: "unidades"}, {data: "cantidad"},
{ {
data: "concepto", data: "descripcion",
render: function (data, type, row, meta) { render: function (data, type, row, meta) {
// se convierten a float data.total_aceptado y subtotal if(row.pedido_linea_impresion_id != null){
var total_aceptado = parseFloat(row.total_aceptado);
var subtotal = parseFloat(row.subtotal); // se convierten a float data.total_aceptado y subtotal
var total_aceptado = parseFloat(row.total_aceptado);
var subtotal = parseFloat(row.base);
var error_text = ''; var error_text = '';
if(total_aceptado != subtotal){ if(total_aceptado != subtotal){
error_text = 'El total del pedido ('+ total_aceptado + '€) no coincide con la línea ('+ subtotal + '€)'; error_text = 'El total del pedido ('+ total_aceptado + '€) no coincide con la línea ('+ subtotal + '€)';
}
return `
<div>
${data}
</div>
<div class="mt-5">
<span style="color: red;" id="error-${meta.row}">${error_text}</span>
</div>
<div class="mt-2">
<label for="input-${meta.row}">Total aceptado</label>
<input readonly type="text" id="input-${meta.row}" value="${row.total_aceptado}">
</div>
`;
}
else{
return `
<div>
${data}
</div>
`;
} }
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: "precio_unidad"},
{data: "iva"}, {data: "iva"},
{data: "subtotal"}, {data: "base"},
{data: "total_iva"}, {data: "total_iva"},
{data: "total"}, {data: "total"},
], ],
@ -241,60 +310,94 @@ var tableLineas = $('#tableOfLineasFactura').DataTable({
], ],
footerCallback: function (row, data, start, end, display) { footerCallback: function (row, data, start, end, display) {
var api = this.api(); updateFooterLineas(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));
} }
}); });
function updateFooterLineas(table){
// Remove the formatting to get integer data for summation
var intVal = function (i) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
// Total over all pages
var totalSubtotal = table
.column(9)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
var totalIVA = table
.column(10)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
var totalTotal = table
.column(11)
.data()
.reduce(function (a, b) {
return intVal(a) + intVal(b);
}, 0);
// Update footer
$('#subtotal-sum').html(totalSubtotal.toFixed(2));
$('#total-iva-sum').html(totalIVA.toFixed(2));
$('#total-sum').html(totalTotal.toFixed(2));
// Assuming pendiente de pago is totalTotal - totalIVA for this example
<?php if($facturaEntity->estado == 'borrador') :?>
var pendientePago = totalTotal ;
var total_pagos = 0;
<?php else: ?>
var total_pagos = parseFloat($('#totalCobrado-sum').html()).toFixed(2);
var pendientePago = totalTotal - total_pagos;
<?php endif; ?>
if(isNaN(pendientePago)){
pendientePago = 0;
}
$('#pendiente-pago').html(pendientePago.toFixed(2));
$.ajax({
url: '<?= route_to('updateFacturaTotales', $facturaEntity->id) ?>',
method: 'POST',
data: {
base: totalSubtotal,
total: totalTotal,
total_pagos: total_pagos,
pendiente: pendientePago
}
}).done((data, textStatus, jqXHR) => {
if(data.estado_pago == 'pagada'){
$('#estado_pago_text').text('<?= lang('Facturas.pagada') ?>');
$('#estado_pago_text').css('color', 'green');
}
else{
$('#estado_pago_text').text('<?= lang('Facturas.pendiente') ?>');
$('#estado_pago_text').css('color', 'red');
}
}).fail((jqXHR, textStatus, errorThrown) => {
popErrorAlert(jqXHR.responseJSON.messages.error)
})
}
// Delete row // Delete row
$(document).on('click', '.btn-delete', function(e) { $(document).on('click', '.btn-delete', function(e) {
//$(".btn-remove").attr('data-id', $(this).attr('data-id'));
const dataId = $(this).attr('data-id'); const dataId = $(this).attr('data-id');
const row = $(this).closest('tr'); const row = $(this).closest('tr');
if ($.isNumeric(dataId)) { if ($.isNumeric(dataId)) {
asyncConfirmDialogWithParams( asyncConfirmDialogWithParams(
"Borrar Linea de Factura", "Borrar Linea de Factura",
"¿Está seguro de borrar la línea? Esta acción no se puede deshacer.", "¿Está seguro de borrar la línea? Esta acción no se puede deshacer.",
deleteConfirmed, null, [dataId, row]) deleteConfirmed, function(){}, [dataId, row])
} }
}); });
@ -302,6 +405,26 @@ $(document).on('click', '.btn-delete', function(e) {
function deleteConfirmed(params){ function deleteConfirmed(params){
var factura_linea_id = params[0]; var factura_linea_id = params[0];
var row = params[1]; var row = params[1];
const row_data = tableLineas.row($(row)).data();
if(row_data.pedido_linea_impresion_id != null){
var url = '<?= route_to('deleteLineaPedidoImpresion') ?>';
$.ajax({
url: url,
method: 'POST',
data: {
factura_id: <?= $facturaEntity->id ?>,
pedido_linea_impresion_id: row_data.pedido_linea_impresion_id,
cantidad: row_data.cantidad
}
}).done((data, textStatus, jqXHR) => {
}).fail((jqXHR, textStatus, errorThrown) => {
popErrorAlert(jqXHR.responseJSON.messages.error)
})
}
var url = '<?= route_to('deleteLineaFactura', ':id') ?>'; var url = '<?= route_to('deleteLineaFactura', ':id') ?>';
url = url.replace(':id', factura_linea_id ); url = url.replace(':id', factura_linea_id );
$.ajax({ $.ajax({
@ -324,4 +447,14 @@ $(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);
});
<?=$this->endSection() ?> <?=$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; ?> <?php endif; ?>
<?= view("themes/vuexy/form/facturas/_facturaLineasItems") ?> <?= 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"> <div class="pt-4">
<input type="submit" <?php if($facturaEntity->estado =='borrador') : ?>
class="btn btn-primary float-start me-sm-3 me-1" <input type="button"
name="save" class="btn btn-success float-start me-sm-3 me-1"
value="<?= lang("Basic.global.Save") ?>" id="validarFactura"
/> name="validarFactura"
<?= anchor(route_to("tarifaAcabadoList"), lang("Basic.global.Cancel"), ["class" => "btn btn-secondary float-start"]) ?> 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 --> </div><!-- /.card-footer -->
</form> </form>
</div><!-- //.card --> </div><!-- //.card -->
@ -41,8 +62,46 @@
<?= $this->endSection() ?> <?= $this->endSection() ?>
<?= $this->section("additionalInlineJs") ?> <?= $this->section("additionalInlineJs") ?>
$("#borrarFactura").on("click", function(){
asyncConfirmDialog(
"Borrar Factura",
"¿Está seguro de borrar la factura? Esta acción no se puede deshacer.",
deleteConfirmed, null)
});
function deleteConfirmed(){
$.ajax({
url: "<?= route_to("borrarFactura", $facturaEntity->id) ?>",
type: 'GET',
success: function(response){
window.location.href = "<?= route_to("facturasList") ?>";
}
});
}
$("#validarFactura").on("click", function(){
asyncConfirmDialog(
"Validar Factura",
"¿Está seguro de pasar la factura a validada? Esta acción no se puede deshacer.",
validatedConfirmed, null)
});
function validatedConfirmed(){
$.ajax({
url: "<?= route_to("validarFactura", $facturaEntity->id) ?>",
type: 'GET',
success: function(response){
window.location.href = "<?= route_to("editarFactura", $facturaEntity->id) ?>";
}
});
}
<?= $this->endSection() ?> <?= $this->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/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/sk-datatables.css') ?>">
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/datatables-editor/editor.dataTables.min.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->endSection() ?>
<?= $this->section('additionalExternalJs') ?> <?= $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/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/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 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() ?> <?=$this->endSection() ?>

View File

@ -27,6 +27,7 @@
<th><?= lang('Facturas.estadoPago') ?></th> <th><?= lang('Facturas.estadoPago') ?></th>
<th><?= lang('Facturas.formaPago') ?></th> <th><?= lang('Facturas.formaPago') ?></th>
<th><?= lang('Facturas.vencimiento') ?></th> <th><?= lang('Facturas.vencimiento') ?></th>
<th><?= lang('Facturas.dias') ?></th>
<th class="text-nowrap"><?= lang('Basic.global.Action') ?></th> <th class="text-nowrap"><?= lang('Basic.global.Action') ?></th>
</tr> </tr>
</thead> </thead>
@ -110,7 +111,24 @@
{ 'data': 'base' }, { 'data': 'base' },
{ 'data': 'total' }, { 'data': 'total' },
{ 'data': 'pendiente' }, { 'data': 'pendiente' },
{ 'data': 'creditoAsegurado' }, { 'data': 'creditoAsegurado' ,
render: function(data, type, row, meta) {
switch(data){
case "0":
return '<?= lang('Basic.global.no') ?>';
break;
case "1":
return '<?= lang('Basic.global.yes') ?>';
break;
default:
return '--'; // Debug
break;
}
},
},
{ 'data': 'estado', { 'data': 'estado',
render: function(data, type, row, meta) { render: function(data, type, row, meta) {
switch(data){ switch(data){
@ -179,13 +197,14 @@
break; break;
default: default:
return '--'; // Debug return data; // Debug
break; break;
} }
} }
}, },
{ 'data': 'vencimiento' }, { 'data': 'vencimiento' },
{ 'data': 'dias_vencimiento' },
{ 'data': actionBtns } { 'data': actionBtns }
] ]
}); });

View File

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

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