Un módulo de ventas con facturación electrónica es un software que permite a las empresas realizar ventas y emitir facturas electrónicas de manera automatizada. Este tipo de módulos suele incluir las siguientes funcionalidades:
- Gestión de clientes: permite crear y gestionar una base de datos de clientes, incluyendo sus datos de contacto, información de facturación, etc.
- Gestión de productos: permite crear y gestionar una base de datos de productos, incluyendo sus datos de inventario, precios, etc.
- Módulo de ventas: permite realizar ventas, incluyendo la selección de productos, la aplicación de descuentos, etc.
- Módulo de facturación electrónica: permite emitir facturas electrónicas, incluyendo la generación del XML y el envío a la autoridad fiscal.
Los módulos de ventas con facturación electrónica ofrecen a las empresas una serie de ventajas, entre las que se incluyen:
- Automatización de los procesos: la automatización de los procesos de ventas y facturación permite a las empresas ahorrar tiempo y recursos.
- Mejora de la precisión: la automatización de los procesos ayuda a reducir los errores humanos, lo que mejora la precisión de las facturas.
- Cumplimiento normativo: los módulos de ventas con facturación electrónica ayudan a las empresas a cumplir con la normativa fiscal vigente.
En México, la facturación electrónica es obligatoria para todas las empresas que realicen ventas a clientes ubicados en el país. Por lo tanto, los módulos de ventas con facturación electrónica son una herramienta indispensable para las empresas mexicanas.
A continuación, se detallan algunas de las funcionalidades específicas que puede incluir un módulo de ventas con facturación electrónica:
- Creación de facturas electrónicas: el módulo debe permitir crear facturas electrónicas de acuerdo con la normativa fiscal vigente. Esto incluye la información obligatoria que debe incluirse en la factura, como los datos del emisor y del receptor, los datos de los productos o servicios, el importe de la factura, etc.
- Envío de facturas electrónicas: el módulo debe permitir enviar las facturas electrónicas a los clientes de forma segura y eficiente. Esto puede hacerse a través de correo electrónico, mensajería instantánea, etc.
- Archivado de facturas electrónicas: el módulo debe permitir archivar las facturas electrónicas de forma segura y organizada. Esto facilitará su consulta y recuperación en el futuro.
- Generación de informes: el módulo debe permitir generar informes sobre las ventas y la facturación electrónica. Estos informes pueden ser útiles para la toma de decisiones estratégicas.
Elegir un módulo de ventas con facturación electrónica adecuado para su empresa dependerá de una serie de factores, como el tamaño de su empresa, su volumen de ventas, sus necesidades específicas, etc. Es importante comparar diferentes módulos antes de tomar una decisión.
A continuación, se ofrecen algunos consejos para elegir un módulo de ventas con facturación electrónica:
- Considere sus necesidades específicas: antes de empezar a buscar un módulo, es importante tener claro cuáles son sus necesidades específicas. ¿Qué funcionalidades necesita? ¿Qué tipo de informe necesita generar?
- Compare diferentes módulos: compare diferentes módulos para encontrar el que mejor se adapte a sus necesidades. Tenga en cuenta el precio, las funcionalidades, el soporte técnico, etc.
- Lea las opiniones de otros usuarios: leer las opiniones de otros usuarios puede ser una buena forma de conocer las ventajas y desventajas de un módulo concreto.
- Pruebe el módulo antes de comprarlo: si es posible, pruebe el módulo antes de comprarlo. Esto le permitirá comprobar que cumple con sus expectativas.
Vamos a crear el archivo de migración para la tabla principal en App/Database/Migrations/2023-05-12-021155_Sells.php con el siguiente codigo
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class Sells extends Migration {
public function up() {
// Quotes
$this->forge->addField([
'id' => ['type' => 'bigint', 'constraint' => 20, 'unsigned' => true, 'auto_increment' => true],
'idEmpresa' => ['type' => 'bigint', 'constraint' => 20, 'unsigned' => true, 'null' => true],
'idSucursal' => ['type' => 'bigint', 'constraint' => 20, 'unsigned' => true, 'null' => true],
'idCustumer' => ['type' => 'bigint', 'constraint' => 20, 'unsigned' => true, 'null' => true],
'folio' => ['type' => 'bigint', 'constraint' => 20, 'unsigned' => true, 'null' => true],
'idUser' => ['type' => 'bigint', 'constraint' => 20, 'null' => true],
'listProducts' => ['type' => 'text', 'null' => true],
'taxes' => ['type' => 'decimal', 'constraint' => '18,2', 'null' => true],
'IVARetenido' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'ISRRetenido' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'subTotal' => ['type' => 'decimal', 'constraint' => '18,2', 'null' => true],
'total' => ['type' => 'decimal', 'constraint' => '18,2', 'null' => true],
'balance' => ['type' => 'decimal', 'constraint' => '18,2', 'null' => true],
'date' => ['type' => 'date', 'null' => true],
'dateVen' => ['type' => 'date', 'null' => true],
'quoteTo' => ['type' => 'varchar', 'constraint' => 512, 'null' => true],
'delivaryTime' => ['type' => 'varchar', 'constraint' => 512, 'null' => true],
'generalObservations' => ['type' => 'varchar', 'constraint' => 512, 'null' => true],
'UUID' => ['type' => 'varchar', 'constraint' => 36, 'null' => true],
'idQuote' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'null' => true],
'tipoComprobanteRD' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'null' => true],
'folioCombrobanteRD' => ['type' => 'bigint', 'constraint' => 11, 'unsigned' => true, 'null' => true],
'RFCReceptor' => ['type' => 'varchar', 'constraint' => 15, 'null' => true],
'usoCFDI' => ['type' => 'varchar', 'constraint' => 32, 'null' => true],
'metodoPago' => ['type' => 'varchar', 'constraint' => 32, 'null' => true],
'formaPago' => ['type' => 'varchar', 'constraint' => 32, 'null' => true],
'razonSocialReceptor' => ['type' => 'varchar', 'constraint' => 1024, 'null' => true],
'codigoPostalReceptor' => ['type' => 'varchar', 'constraint' => 5, 'null' => true],
'regimenFiscalReceptor' => ['type' => 'varchar', 'constraint' => 1024, 'null' => true],
'idVehiculo' => ['type' => 'bigint', 'constraint' => 20, 'unsigned' => true, 'null' => true],
'idChofer' => ['type' => 'bigint', 'constraint' => 20, 'unsigned' => true, 'null' => true],
'tipoVehiculo' => ['type' => 'bigint', 'constraint' => 20, 'unsigned' => true, 'null' => true],
'idArqueoCaja' => ['type' => 'bigint', 'constraint' => 20, 'unsigned' => true, 'null' => true],
'created_at' => ['type' => 'datetime', 'null' => true],
'updated_at' => ['type' => 'datetime', 'null' => true],
'deleted_at' => ['type' => 'datetime', 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey('UUID', 'UQ_UUID');
$this->forge->createTable('sells', true);
}
public function down() {
$this->forge->dropTable('sells', true);
}
}
Creamos el archivo de migración para el detalle de ventas App/Database/Migrations/2023-06-01052347_SellsDetails con el siguiente código
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class SellsDetails extends Migration
{
public function up()
{
// QuotesDetails
$this->forge->addField([
'id' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
'idSell' => ['type' => 'int', 'constraint' => 11, 'null' => true],
'idProduct' => ['type' => 'int', 'constraint' => 11, 'null' => true],
'description' => ['type' => 'varchar', 'constraint' => 512, 'null' => true],
'unidad' => ['type' => 'varchar', 'constraint' => 64, 'null' => true],
'claveProductoSAT' => ['type' => 'varchar', 'constraint' => 64, 'null' => true],
'claveUnidadSAT' => ['type' => 'varchar', 'constraint' => 64, 'null' => true],
'codeProduct' => ['type' => 'varchar', 'constraint' => 32, 'null' => true],
'cant' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'price' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'lote' => ['type' => 'varchar', 'constraint' => 64, 'null' => true],
'porcentTax' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'porcentIVARetenido' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'IVARetenido' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'porcentISRRetenido' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'ISRRetenido' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'tax' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'neto' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'total' => ['type' => 'decimal', 'constraint' => '18,4', 'null' => true],
'created_at' => ['type' => 'datetime', 'null' => true],
'updated_at' => ['type' => 'datetime', 'null' => true],
'deleted_at' => ['type' => 'datetime', 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->createTable('sellsdetails', true);
}
public function down()
{
$this->forge->dropTable('sellsdetails', true);
}
}
Creamos el archivo de migración para los pagos en App/Database/Migrations/2023-06-09040832_Payments.php con el siguiente código
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class Payments extends Migration {
public function up() {
// Payments
$this->forge->addField([
'id' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
'idSell' => ['type' => 'bigint', 'constraint' => 20, 'null' => false],
'importPayment' => ['type' => 'decimal(18,2)', 'constraint' => 18, 'null' => false],
'importBack' => ['type' => 'decimal(18,2)', 'constraint' => 18, 'null' => false],
'datePayment' => ['type' => 'datetime', 'null' => false],
'metodPayment' => ['type' => 'varchar', 'constraint' => 32, 'null' => false],
'idComplemento' => ['type' => 'bigint', 'constraint' => 20, 'null' => false],
'created_at' => ['type' => 'datetime', 'null' => true],
'updated_at' => ['type' => 'datetime', 'null' => true],
'deleted_at' => ['type' => 'datetime', 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->createTable('payments', true);
}
public function down() {
$this->forge->dropTable('payments', true);
}
}
Creamos el archivo de migración para los XML en App/Database/Migrations/2023-05-29063550_Xml.php con el siguiente código
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class Xml extends Migration {
public function up() {
// Xml
$this->forge->addField([
'id' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
'idEmpresa' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true],
'uuidTimbre' => ['type' => 'varchar', 'constraint' => 36, 'null' => true],
'archivoXML' => ['type' => 'text', 'null' => true],
'serie' => ['type' => 'varchar', 'constraint' => 256, 'null' => true],
'folio' => ['type' => 'varchar', 'constraint' => 256, 'null' => true],
'rfcEmisor' => ['type' => 'varchar', 'constraint' => 16, 'null' => true],
'rfcReceptor' => ['type' => 'varchar', 'constraint' => 16, 'null' => true],
'nombreEmisor' => ['type' => 'varchar', 'constraint' => 512, 'null' => true],
'nombreReceptor' => ['type' => 'varchar', 'constraint' => 512, 'null' => true],
'tipoComprobante' => ['type' => 'varchar', 'constraint' => 18, 'null' => true],
'fecha' => ['type' => 'datetime', 'null' => true],
'fechaTimbrado' => ['type' => 'datetime', 'null' => true],
'total' => ['type' => 'decimal', 'constraint' => '18,2', 'null' => true],
'uuidPaquete' => ['type' => 'varchar', 'constraint' => 36, 'null' => false],
'status' => ['type' => 'varchar', 'constraint' => 36, 'null' => false],
'metodoPago' => ['type' => 'varchar', 'constraint' => 8, 'null' => false],
'formaPago' => ['type' => 'varchar', 'constraint' => 8, 'null' => false],
'usoCFDI' => ['type' => 'varchar', 'constraint' => 8, 'null' => false],
'exportacion' => ['type' => 'varchar', 'constraint' => 4, 'null' => false],
'emitidoRecibido' => ['type' => 'varchar', 'constraint' => 32, 'null' => false],
'base16' => ['type' => 'decimal', 'constraint' => '18,2', 'null' => true],
'totalImpuestos16' => ['type' => 'decimal', 'constraint' => '18,2', 'null' => true],
'base8' => ['type' => 'decimal', 'constraint' => '18,2', 'null' => true],
'totalImpuestos8' => ['type' => 'decimal', 'constraint' => '18,2', 'null' => true],
'status' => ['type' => 'varchar', 'constraint' => 128, 'null' => false],
'created_at' => ['type' => 'datetime', 'null' => true],
'updated_at' => ['type' => 'datetime', 'null' => true],
'deleted_at' => ['type' => 'datetime', 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->createTable('xml', true);
}
public function down() {
$this->forge->dropTable('xml', true);
}
}
Creamos el archivo de migración para la tabla enlace XML App/Database/Migrations/2023-10-17085510_Enlacexml.php con el siguiente código
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class Enlacexml extends Migration {
public function up() {
// Enlacexml
$this->forge->addField([
'id' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
'idDocumento' => ['type' => 'bigint', 'constraint' => 20, 'null' => false],
'uuidXML' => ['type' => 'varchar', 'constraint' => 36, 'null' => false],
'tipo' => ['type' => 'varchar', 'constraint' => 16, 'null' => false],
'importe' => ['type' => 'decimal', 'constraint' => 18, 'null' => false],
'created_at' => ['type' => 'datetime', 'null' => true],
'updated_at' => ['type' => 'datetime', 'null' => true],
'deleted_at' => ['type' => 'datetime', 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->createTable('enlacexml', true);
}
public function down() {
$this->forge->dropTable('enlacexml', true);
}
}
Creamos el archivo de modelo para el encabezado en App/Models/SellsModel.php con el siguiente código.
<?php
namespace App\Models;
use CodeIgniter\Model;
class SellsModel extends Model {
protected $table = 'sells';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $useSoftDeletes = true;
protected $allowedFields = [
'id',
'idEmpresa',
'folio',
'idUser',
'idCustumer',
'listProducts',
'taxes',
'IVARetenido',
'ISRRetenido',
'subTotal',
'total',
'balance',
'date',
'dateVen',
'generalObservations',
'quoteTo',
'delivaryTime',
'created_at',
'updated_at',
'idQuote',
'tipoComprobanteRD',
'folioComprobanteRD',
'RFCReceptor',
'usoCFDI',
'metodoPago',
'formaPago',
'razonSocialReceptor',
'codigoPostalReceptor',
'regimenFiscalReceptor',
'idVehiculo',
'idChofer',
'idSucursal',
'idArqueoCaja',
'tipoVehiculo',
'UUID'
];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [
'idCustumer' => 'required|',
];
protected $validationMessages = [];
protected $skipValidation = false;
public function mdlGetSells($empresas) {
$result = $this->db->table('sells a, custumers b, empresas c')
->select('a.UUID,a.id,concat(b.firstname,\' \',b.lastname) as nameCustumer
,a.idCustumer
,a.folio
,a.date
,b.email as correoCliente
,a.dateVen
,a.total
,a.taxes
,a.subTotal
,a.balance
,a.delivaryTime
,a.generalObservations
,a.idQuote
,a.IVARetenido
,a.ISRRetenido
,a.tipoComprobanteRD
,a.folioComprobanteRD
,a.idSucursal
,a.RFCReceptor
,a.usoCFDI
,a.metodoPago
,a.formaPago
,a.razonSocialReceptor
,a.codigoPostalReceptor
,a.regimenFiscalReceptor
,a.idVehiculo
,a.idChofer
,a.tipoVehiculo
,a.idArqueoCaja
,a.created_at
,a.updated_at
,a.deleted_at')
->where('a.idCustumer', 'b.id', FALSE)
->where('a.idEmpresa', 'c.id', FALSE)
->whereIn('a.idEmpresa', $empresas);
return $result;
}
/**
* Search by filters
*/
public function mdlGetSellsFilters($empresas
, $from
, $to
, $allSells
, $empresa =0
, $sucursal =0
, $cliente = 0
) {
$result = $this->db->table('sells a, custumers b, empresas c')
->select('a.UUID,a.id,concat(b.firstname,\' \',b.lastname) as nameCustumer
,a.idCustumer
,a.folio
,a.date
,b.email as correoCliente
,a.dateVen
,a.total
,a.taxes
,a.subTotal
,a.balance
,a.delivaryTime
,a.generalObservations
,a.idQuote
,a.IVARetenido
,a.ISRRetenido
,a.tipoComprobanteRD
,a.folioComprobanteRD
,a.idSucursal
,a.RFCReceptor
,a.usoCFDI
,a.metodoPago
,a.formaPago
,a.razonSocialReceptor
,a.codigoPostalReceptor
,a.regimenFiscalReceptor
,a.idVehiculo
,a.idChofer
,a.tipoVehiculo
,a.idArqueoCaja
,a.created_at
,a.updated_at
,a.deleted_at')
->where('a.idCustumer', 'b.id', FALSE)
->where('a.idEmpresa', 'c.id', FALSE)
->where('a.date >=', $from . ' 00:00:00')
->where('a.date <=', $to . ' 23:59:59')
->groupStart()
->where('\'true\'', $allSells, true)
->orWhere('a.balance>', '0')
->groupEnd()
->groupStart()
->where('0', $empresa)
->orWhere('a.idEmpresa', $empresa)
->groupEnd()
->groupStart()
->where('0', $sucursal)
->orWhere('a.idSucursal', $sucursal)
->groupEnd()
->groupStart()
->where('0', $cliente)
->orWhere('a.idCustumer', $cliente)
->groupEnd()
->whereIn('a.idEmpresa', $empresas);
return $result;
}
/**
* Obtener Cotización por UUID
*/
public function mdlGetSellUUID($uuid, $empresas) {
$result = $this->db->table('sells a, custumers b, empresas c')
->select('a.idCustumer
,a.folio
,a.quoteTo
,a.UUID
,a.idUser
,a.id
,concat(b.firstname,\' \',b.lastname) as nameCustumer
,a.idEmpresa
,c.nombre as nombreEmpresa
,a.listProducts
,a.date
,a.dateVen
,a.total
,a.taxes
,a.IVARetenido
,a.ISRRetenido
,a.subTotal
,a.tipoComprobanteRD
,a.folioComprobanteRD
,a.idQuote
,a.delivaryTime
,a.generalObservations
,a.RFCReceptor
,a.usoCFDI
,a.metodoPago
,a.formaPago
,a.razonSocialReceptor
,a.codigoPostalReceptor
,a.regimenFiscalReceptor
,a.idSucursal
,a.idVehiculo
,a.idChofer
,a.tipoVehiculo
,a.idArqueoCaja
,a.created_at
,a.updated_at,
a.deleted_at')
->where('a.idCustumer', 'b.id', FALSE)
->where('a.idEmpresa', 'c.id', FALSE)
->where('UUID', $uuid)
->whereIn('a.idEmpresa', $empresas)
->get()->getRowArray();
return $result;
}
/**
*
* @param type $idEmpresa
* @param type $idSucursal
* @param type $idProducto
* Ventas Filtradas por Empresas, Sucursales y productos
*/
public function mdlVentasPorProductos($idEmpresa = 0
, $idSucursal = 0
, $idProducto = 0
, $from
, $to
, $idEmpresas
, $idSucursales
, $idCliente
) {
$result = $this->db->table('sells a
, sellsdetails b
, empresas c
, branchoffices d
, custumers e
')
->select('a.id
,a.idEmpresa
,a.idSucursal
,c.nombre as nombreEmpresa
,d.name as nombreSucursal
,e.firstname as nombreCliente
,e.lastname as apellidoCliente
,e.razonSocial as razonSocialCliente
,a.folio
,a.date
,b.idProduct
,b.description
,b.codeProduct
,b.cant
,b.price
,b.porcentTax
,b.tax as impuestoProducto
,b.total as totalProducto
,a.taxes
,a.subTotal
,b.neto')
->where('a.id', 'b.idSell', FALSE)
->where('a.idEmpresa', 'c.id', FALSE)
->where('a.idSucursal', 'd.id', FALSE)
->groupStart()
->where('0', $idEmpresa)
->orWhere('a.idEmpresa', $idEmpresa)
->groupEnd()
->groupStart()
->where('0', $idSucursal)
->orWhere('a.idSucursal', $idSucursal)
->groupEnd()
->groupStart()
->where('0', $idCliente)
->orWhere('a.idCustumer', $idCliente)
->groupEnd()
->groupStart()
->where('0', $idProducto)
->orWhere('b.idProduct', $idProducto)
->groupEnd()
->where('a.date >=', $from . ' 00:00:00')
->where('a.date <=', $to . ' 23:59:59')
->whereIn('a.idEmpresa', $idEmpresas)
->whereIn('a.idSucursal', $idSucursales)
->where('a.idCustumer', 'e.id', false);
return $result;
}
}
Creamos el archivo modelo para el detalle de la venta en App/Models/SellsDetailsModel.php con el siguiente código
<?php
namespace App\Models;
use CodeIgniter\Model;
class SellsDetailsModel extends Model {
protected $table = 'sellsdetails';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $useSoftDeletes = true;
protected $allowedFields = ['id'
, 'idSell'
, 'idProduct'
, 'description'
, 'idAlmacen'
, 'lote'
, 'claveProductoSAT'
, 'claveUnidadSAT'
, 'unidad'
, 'codeProduct'
, 'cant'
, 'price'
, 'porcentTax'
, 'tax'
, 'porcentIVARetenido'
, 'IVARetenido'
, 'porcentISRRetenido'
, 'ISRRetenido'
, 'neto'
, 'total'
, 'created_at'
, 'updated_at'
, 'deleted_at'];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [
];
protected $validationMessages = [];
protected $skipValidation = false;
}
Creamos el archivo del modelo de pagos App/Models/PaymentsModel.php con el siguiente código
<?php
namespace App\Models;
use CodeIgniter\Model;
class PaymentsModel extends Model {
protected $table = 'payments';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $useSoftDeletes = true;
protected $allowedFields = ['id'
, 'idSell'
, 'importPayment'
, 'importBack'
, 'datePayment'
, 'metodPayment'
, 'idComplemento'
, 'created_at'
, 'updated_at'
, 'deleted_at'];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [
];
protected $validationMessages = [];
protected $skipValidation = false;
}
Creamos el archivo del modelos para los XML App/Models/XmlModel.php con el siguiente código
<?php
namespace App\Models;
use CodeIgniter\Model;
class XmlModel extends Model {
protected $table = 'xml';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $useSoftDeletes = true;
protected $allowedFields = [
'id'
, 'uuidTimbre'
, 'archivoXML'
, 'serie'
, 'folio'
, 'rfcEmisor'
, 'rfcReceptor'
, 'nombreEmisor'
, 'nombreReceptor'
, 'tipoComprobante'
, 'fecha'
, 'fechaTimbrado'
, 'total'
, 'created_at'
, 'deleted_at'
, 'updated_at'
, 'idEmpresa'
, 'metodoPago'
, 'formaPago'
, 'usoCFDI'
, 'exportacion'
, 'idEmpresa'
, 'base16'
, 'totalImpuestos16'
, 'base8'
, 'totalImpuestos8'
, 'emitidoRecibido'
, 'status'
, 'uuidPaquete'
];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [];
protected $validationMessages = [];
protected $skipValidation = false;
public function getIngresosXMLGrafica($empresas, $RFCEmpresas, $desdeFecha, $hastaFecha) {
if (count($RFCEmpresas) > 1) {
$coma = "";
} else {
$coma = "'";
}
$rfcImplode = implode("',", $RFCEmpresas);
$result = $this->db->table('xml')
->select('date_format(fecha,\'%Y%m\') as periodo
,sum(case when
(rfcEmisor in(\'' . $rfcImplode . $coma . ') and tipoComprobante=\'I\') or ( rfcReceptor in(\'' . $rfcImplode . $coma . ') and tipoComprobante=\'N\')
or ( rfcReceptor in (\'' . $rfcImplode . $coma . ') and tipoComprobante=\'E\')
then total
else 0
end) as ingreso,sum(case when
(rfcEmisor in (\'' . $rfcImplode . $coma . ') and tipoComprobante=\'E\') or ( rfcReceptor not in(\'' . $rfcImplode . $coma . ') and tipoComprobante=\'N\')
or ( rfcReceptor in (\'' . $rfcImplode . $coma . ') and tipoComprobante=\'I\')
then total
else 0
end) as egreso')
->whereIn('idEmpresa', $empresas)
->where('fechaTimbrado >=', $desdeFecha . ' 00:00:00')
->where('fechaTimbrado <=', $hastaFecha . ' 23:59:59')
->groupBy('date_format(fecha,\'%Y%m\')')
->get();
return $result;
}
public function getEgresosXMLGrafica($empresas, $RFCEmpresas, $desdeFecha, $hastaFecha) {
$result = $this->db->table('xml')
->select('date_format(fecha,\'%Y%m\') as periodo,sum(total) as total')
->whereIn('tipoComprobante', array('i'))
->whereIn('rfcReceptor', $RFCEmpresas)
->groupStart()
->where('tipoComprobante', 'i')
->orWhereIn('idEmpresa', $empresas)
->groupend()
->where('fechaTimbrado >=', $desdeFecha . ' 00:00:00')
->where('fechaTimbrado <=', $hastaFecha . ' 23:59:59')
->groupBy('date_format(fecha,\'%Y%m\')')
->get();
return $result;
}
public function mdlGetRFCReceptor($idEmpresa, $searchTerm) {
$resultado = $this->db->table('xml')
->select('rfcReceptor')
->where('idEmpresa', $idEmpresa)
->like("rfcReceptor", $searchTerm)
->groupBy('rfcReceptor')
->limit(100)
->get()->getResultArray();
return $resultado;
}
public function mdlGetRFCEmisor($idEmpresa, $searchTerm) {
$resultado = $this->db->table('xml')
->select('rfcEmisor')
->where('idEmpresa', $idEmpresa)
->like("rfcEmisor", $searchTerm)
->groupBy('rfcEmisor')
->limit(100)
->get()->getResultArray();
return $resultado;
}
public function mdlGetXMLFilter() {
$resultado = $this->db->table('xml')
->groupStart()
->where('rfcReceptor', 'CGU840103SZ5')
->orWhere("'0'='CGU840103SZ5' ")
->groupEnd();
return $resultado;
}
public function mdlXMLSinAsignar($empresas, $tipoComprobante) {
$resultado = $this->db->table('xml a')
->select('a.id,a.uuidTimbre,serie,folio,rfcReceptor,rfcEmisor,nombreReceptor,total,fecha,tipoComprobante')
->where("not exists (select * from enlacexml b where a.uuidTimbre=b.uuidXML)", '', FALSE)
->where("a.tipoComprobante", $tipoComprobante)
->whereIn(' idEmpresa', $empresas);
return $resultado;
}
/**
* Buscar parcialidad
*/
public function mdlParcialidadVenta($idVenta, $idPago) {
return $this->db->table('payments a, sells b, enlacexml c, pagos d, xml e')
->select('*')
->where('a.idSell', 'b.id', FALSE)
->where('a.idComplemento', 'd.id', FALSE)
->where('d.id', 'c.idDocumento', FALSE)
->where('e.uuidTimbre', 'c.uuidXML', FALSE)
->where('e.status', 'vigente')
->where('b.id', $idVenta)
->where('d.id <>', $idPago)->countAllResults();
}
/**
* Buscar parcialidad
*/
public function mdlSaldo($idVenta, $idPago) {
$importeAPagar = $this->db->table('payments a, sells b, enlacexml c, pagos d, xml e')
->selectSum("a.importPayment")
->where('a.idSell', 'b.id', FALSE)
->where('a.idComplemento', 'd.id', FALSE)
->where('d.id', 'c.idDocumento', FALSE)
->where('e.uuidTimbre', 'c.uuidXML', FALSE)
->where('e.status', 'vigente')
->where('b.id', $idVenta)
->where('d.id <>', $idPago)->get()->getResultArray();
$importeDevuelto = $this->db->table('payments a, sells b, enlacexml c, pagos d, xml e')
->selectSum("a.importBack")
->where('a.idSell', 'b.id', FALSE)
->where('a.idComplemento', 'd.id', FALSE)
->where('d.id', 'c.idDocumento', FALSE)
->where('e.uuidTimbre', 'c.uuidXML', FALSE)
->where('e.status', 'vigente')
->where('b.id', $idVenta)
->where('d.id <>', $idPago)->get()->getResultArray();
if (!isset($importeAPagar["importPayment"])) {
$importeAPagar["importPayment"] = 0;
}
if (!isset($importeDevuelto["importBack"])) {
$importeDevuelto["importBack"] = 0;
}
return $importeAPagar["importPayment"] - $importeDevuelto["importBack"];
}
}
Creamos el archivo de modelo App/Models/EnlacexmlModel.php con el siguiente código
<?php
namespace App\Models;
use CodeIgniter\Model;
class EnlacexmlModel extends Model{
protected $table = 'enlacexml';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $useSoftDeletes = true;
protected $allowedFields = ['id','idDocumento','uuidXML','tipo','importe','created_at','updated_at','deleted_at'];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [
];
protected $validationMessages = [];
protected $skipValidation = false;
public function mdlGetEnlacexml($idEmpresas){
$result = $this->db->table('enlacexml a, empresas b')
->select('a.id,a.idDocumento,a.uuidXML,a.tipo,a.importe,a.created_at,a.updated_at,a.deleted_at ,b.nombre as nombreEmpresa')
->where('a.idEmpresa', 'b.id', FALSE)
->whereIn('a.idEmpresa',$idEmpresas);
return $result;
}
}
Creamos el archivo de controlador para la ventas en App/Controllers/SellsController.php con el siguiente código
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
use App\Database\Migrations\Storages;
use App\Models\ProductsModel;
use \App\Models\UserModel;
use App\Models\LogModel;
use App\Models\QuotesModel;
use App\Models\SellsModel;
use App\Models\CompaniesModel;
use App\Models\StoragesModel;
use App\Models\SellsDetailsModel;
use CodeIgniter\API\ResponseTrait;
use App\Models\EmpresasModel;
use App\Models\CustumersModel;
use App\Models\PaymentsModel;
use App\Models\Comprobantes_rdModel;
use App\Models\VehiculosModel;
use App\Models\ChoferesModel;
use App\Models\TipovehiculoModel;
use App\Models\BranchofficesModel;
use App\Models\ArqueoCajaModel;
use App\Models\SaldosModel;
use App\Models\EnlacexmlModel;
class SellsController extends BaseController {
use ResponseTrait;
protected $log;
protected $sells;
protected $storages;
protected $sellsDetail;
protected $sucursales;
protected $empresa;
protected $user;
protected $custumer;
protected $payments;
protected $products;
protected $quotes;
protected $comprobantesRD;
protected $vehiculos;
protected $choferes;
protected $tiposVehiculo;
protected $arqueoCaja;
protected $saldos;
protected $xmlEnlace;
public function __construct() {
$this->log = new LogModel();
$this->sells = new SellsModel();
$this->sellsDetail = new SellsDetailsModel();
$this->empresa = new EmpresasModel();
$this->user = new UserModel();
$this->custumer = new CustumersModel();
$this->payments = new PaymentsModel();
$this->products = new ProductsModel();
$this->quotes = new QuotesModel();
$this->comprobantesRD = new Comprobantes_rdModel();
$this->vehiculos = new VehiculosModel();
$this->choferes = new ChoferesModel();
$this->tiposVehiculo = new TipovehiculoModel();
$this->sucursales = new BranchofficesModel();
$this->arqueoCaja = new ArqueoCajaModel();
$this->saldos = new SaldosModel();
$this->xmlEnlace = new EnlacexmlModel();
helper('menu');
helper('utilerias');
}
public function index() {
$auth = service('authentication');
if (!$auth->check()) {
return redirect()->route('admin');
}
helper('auth');
$idUser = user()->id;
$titulos["empresas"] = $this->empresa->mdlEmpresasPorUsuario($idUser);
if (count($titulos["empresas"]) == "0") {
$empresasID[0] = "0";
} else {
$empresasID = array_column($titulos["empresas"], "id");
}
if ($this->request->isAJAX()) {
$datos = $this->sells->mdlGetSells($empresasID);
return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
}
$tiposVehiculo = $this->tiposVehiculo->mdlGetTipovehiculoArray($empresasID);
$titulos["tiposVehiculo"] = $tiposVehiculo;
$titulos["listaTitle"] = "Administracion de ventas";
$titulos["listaSubtitle"] = "Muestra la lista de ventas";
//$data["data"] = $datos;
return view('sells', $titulos);
}
public function sellsFilters($desdeFecha, $hastaFecha, $todas, $empresa, $sucursal, $cliente) {
$auth = service('authentication');
if (!$auth->check()) {
return redirect()->route('admin');
}
helper('auth');
$idUser = user()->id;
$titulos["empresas"] = $this->empresa->mdlEmpresasPorUsuario($idUser);
if (count($titulos["empresas"]) == "0") {
$empresasID[0] = "0";
} else {
$empresasID = array_column($titulos["empresas"], "id");
}
if ($this->request->isAJAX()) {
$datos = $this->sells->mdlGetSellsFilters($empresasID, $desdeFecha, $hastaFecha, $todas, $empresa, $sucursal, $cliente);
return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
}
}
/**
*
* @param type $desdeFecha
* @param type $hastaFecha
* @param type $todas
* @return type
*
* Get Report Sells per products
*/
public function sellsReport($idEmpresa = 0
, $idSucursal = 0
, $idProducto = 0
, $from
, $to
, $cliente) {
$auth = service('authentication');
if (!$auth->check()) {
return redirect()->route('admin');
}
helper('auth');
$idUser = user()->id;
/**
* Vemos las Empresa a la que tiene acceso
*/
$titulos["empresas"] = $this->empresa->mdlEmpresasPorUsuario($idUser);
if (count($titulos["empresas"]) == "0") {
$empresasID[0] = "0";
} else {
$empresasID = array_column($titulos["empresas"], "id");
}
/**
* Vemos a las sucursales a las que tiene accesio
*/
$sucursales = $this->sucursales->mdlSucursalesPorUsuario($idUser);
if (count($sucursales) == "0") {
$sucursalesID[0] = "0";
} else {
$sucursalesID = array_column($sucursales, "id");
}
if ($this->request->isAJAX()) {
$datos = $this->sells->mdlVentasPorProductos($idEmpresa
, $idSucursal
, $idProducto
, $from
, $to
, $empresasID
, $sucursalesID
, $cliente);
return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
}
}
public function newSell() {
$auth = service('authentication');
if (!$auth->check()) {
return redirect()->route('admin');
}
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$titulos["empresas"] = $this->empresa->mdlEmpresasPorUsuario($idUser);
if (count($titulos["empresas"]) == "0") {
$empresasID[0] = "0";
} else {
$empresasID = array_column($titulos["empresas"], "id");
}
$fechaActual = fechaMySQLADateHTML5(fechaHoraActual());
$idMax = "0";
$titulos["idMax"] = $idMax;
$titulos["idSell"] = $idMax;
$titulos["folio"] = "0";
$titulos["fecha"] = $fechaActual;
$titulos["userName"] = $userName;
$titulos["idUser"] = $idUser;
$titulos["contact"] = "";
$titulos["idQuote"] = "0";
$titulos["codeCustumer"] = "";
$titulos["observations"] = "";
$titulos["taxes"] = "0.00";
$titulos["IVARetenido"] = "0.00";
$titulos["ISRRetenido"] = "0.00";
$titulos["subTotal"] = "0.00";
$titulos["total"] = "0.00";
$titulos["formaPago"] = $this->catalogosSAT->formasDePago40()->searchByField("texto", "%%", 99999);
$titulos["usoCFDI"] = $this->catalogosSAT->usosCfdi40()->searchByField("texto", "%%", 99999);
$titulos["metodoPago"] = $this->catalogosSAT->metodosDePago40()->searchByField("texto", "%%", 99999);
$titulos["regimenFiscal"] = $this->catalogosSAT->regimenesFiscales40()->searchByField("texto", "%%", 99999);
$titulos["RFCReceptor"] = "";
$titulos["regimenFiscalReceptor"] = "";
$titulos["usoCFDIReceptor"] = "";
$titulos["metodoPagoReceptor"] = "";
$titulos["formaPagoReceptor"] = "";
$titulos["razonSocialReceptor"] = "";
$titulos["codigoPostalReceptor"] = "";
$titulos["folioComprobanteRD"] = "0";
$titulos["uuid"] = generaUUID();
$tiposVehiculo = $this->tiposVehiculo->mdlGetTipovehiculoArray($empresasID);
$titulos["title"] = "Nueva Venta"; //lang('registerNew.title');
$titulos["subtitle"] = "Captura de Ventas"; // lang('registerNew.subtitle');
$titulos["tiposVehiculo"] = $tiposVehiculo;
return view('newSell', $titulos);
}
public function reportSellsProducts() {
$auth = service('authentication');
if (!$auth->check()) {
return redirect()->route('admin');
}
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$titulos["empresas"] = $this->empresa->mdlEmpresasPorUsuario($idUser);
if (count($titulos["empresas"]) == "0") {
$empresasID[0] = "0";
} else {
$empresasID = array_column($titulos["empresas"], "id");
}
$titulos["title"] = "Reporte de Ventas"; //lang('registerNew.title');
$titulos["subtitle"] = "Ventas por Empresa, Sucursal, Producto";
return view('reportSellsProducts', $titulos);
}
/**
* Get Last Code
*/
public function getLastCode() {
$idEmpresa = $this->request->getPost("idEmpresa");
$idSucursal = $this->request->getPost("idSucursal");
$result = $this->sells->selectMax("folio")
->where("idEmpresa", $idEmpresa)
->where("idSucursal", $idSucursal)
->first();
if ($result["folio"] == null) {
$result["folio"] = 1;
} else {
$result["folio"] = $result["folio"] + 1;
}
echo json_encode($result);
}
/**
* Get Last Code
*/
public function getLastCodeInterno($idEmpresa, $idSucursal) {
$result = $this->sells->selectMax("folio")
->where("idEmpresa", $idEmpresa)
->where("idSucursal", $idSucursal)
->first();
if ($result["folio"] == null) {
$result["folio"] = 1;
} else {
$result["folio"] = $result["folio"] + 1;
}
return $result["folio"];
}
/*
* Editar Cotizacion
*/
public function editSell($uuid) {
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$auth = service('authentication');
if (!$auth->check()) {
return redirect()->route('admin');
}
$auth = service('authentication');
if (!$auth->check()) {
return redirect()->route('admin');
}
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$titulos["empresas"] = $this->empresa->mdlEmpresasPorUsuario($idUser);
if (count($titulos["empresas"]) == "0") {
$empresasID[0] = "0";
} else {
$empresasID = array_column($titulos["empresas"], "id");
}
$sell = $this->sells->mdlGetSellUUID($uuid, $empresasID);
$listProducts = json_decode($sell["listProducts"], true);
$titulos["idSell"] = $sell["id"];
$titulos["folio"] = $sell["folio"];
$titulos["idCustumer"] = $sell["idCustumer"];
$titulos["nameCustumer"] = $sell["nameCustumer"];
$titulos["idEmpresa"] = $sell["idEmpresa"];
$titulos["nombreEmpresa"] = $sell["nombreEmpresa"];
$titulos["idUser"] = $idUser;
$titulos["userName"] = $userName;
$titulos["listProducts"] = $listProducts;
$titulos["taxes"] = number_format($sell["taxes"], 2, ".");
$titulos["IVARetenido"] = number_format($sell["IVARetenido"], 2, ".");
$titulos["ISRRetenido"] = number_format($sell["ISRRetenido"], 2, ".");
$titulos["subTotal"] = number_format($sell["subTotal"], 2, ".");
$titulos["total"] = number_format($sell["total"], 2, ".");
$titulos["fecha"] = $sell["date"];
$titulos["dateVen"] = $sell["dateVen"];
$titulos["quoteTo"] = $sell["quoteTo"];
$titulos["observations"] = $sell["generalObservations"];
$titulos["uuid"] = $sell["UUID"];
$titulos["idQuote"] = $sell["idQuote"];
$titulos["formaPago"] = $this->catalogosSAT->formasDePago40()->searchByField("texto", "%%", 99999);
$titulos["usoCFDI"] = $this->catalogosSAT->usosCfdi40()->searchByField("texto", "%%", 99999);
$titulos["metodoPago"] = $this->catalogosSAT->metodosDePago40()->searchByField("texto", "%%", 99999);
$titulos["regimenFiscal"] = $this->catalogosSAT->regimenesFiscales40()->searchByField("texto", "%%", 99999);
$titulos["RFCReceptor"] = $sell["RFCReceptor"];
$titulos["regimenFiscalReceptor"] = $sell["regimenFiscalReceptor"];
$titulos["usoCFDIReceptor"] = $sell["usoCFDI"];
$titulos["metodoPagoReceptor"] = $sell["metodoPago"];
$titulos["formaPagoReceptor"] = $sell["formaPago"];
$titulos["razonSocialReceptor"] = $sell["razonSocialReceptor"];
$titulos["codigoPostalReceptor"] = $sell["codigoPostalReceptor"];
$titulos["idVehiculo"] = $sell["idVehiculo"];
$datosVehiculo = $this->vehiculos->select("*")->where("id", $sell["idVehiculo"])->first();
$titulos["vehiculoNombre"] = $sell["idVehiculo"];
$datosVehiculo = $this->vehiculos->select("*")->where("id", $sell["idVehiculo"])->first();
if (isset($datosVehiculo["descripcion"])) {
$titulos["vehiculoNombre"] = $sell["tipoVehiculo"] . " " . $datosVehiculo["placas"] . " " . $datosVehiculo["descripcion"];
} else {
$titulos["vehiculoNombre"] = "Seleccione Vehiculo";
}
$titulos["idChofer"] = $sell["idChofer"];
$datosChofer = $this->choferes->select("*")->where("id", $sell["idChofer"])->first();
if (isset($datosChofer["nombre"])) {
$titulos["choferNombre"] = $datosChofer["nombre"] . " " . $datosChofer["Apellido"];
} else {
$titulos["choferNombre"] = "Seleccione Chofer";
}
$titulos["tipoVehiculo"] = $sell["tipoVehiculo"];
$tiposVehiculo = $this->tiposVehiculo->mdlGetTipovehiculoArray($empresasID);
$titulos["tiposVehiculo"] = $tiposVehiculo;
$titulos["idSucursal"] = $sell["idSucursal"];
$sucursal = $this->sucursales->select("*")->where("id", $titulos["idSucursal"])->first();
$titulos["nombreSucursal"] = $sucursal["key"] . " " . $sucursal["name"];
if ($sell["tipoComprobanteRD"] > 0) {
$comprobante = $this->comprobantesRD->find($sell["tipoComprobanteRD"]);
$titulos["folioComprobanteRD"] = $sell["folioComprobanteRD"];
$titulos["tipoComprobanteRDID"] = $comprobante["id"];
$titulos["tipoComprobanteRDNombre"] = $comprobante["nombre"];
$titulos["tipoComprobanteRDPrefijo"] = $comprobante["prefijo"];
} else {
$titulos["folioComprobanteRD"] = "0";
$titulos["tipoComprobanteRDID"] = "0";
$titulos["tipoComprobanteRDNombre"] = "0";
$titulos["tipoComprobanteRDPrefijo"] = "0";
}
$titulos["title"] = "Editar Venta";
$titulos["subtitle"] = "Edición de Ventas";
return view('newSell', $titulos);
}
/*
* Save or Update
*/
public function save() {
$auth = service('authentication');
if (!$auth->check()) {
$this->session->set('redirect_url', current_url());
return redirect()->route('admin');
}
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$datos = $this->request->getPost();
$this->sells->db->transBegin();
$existsSell = $this->sells->where("UUID", $datos["UUID"])->countAllResults();
$listProducts = json_decode($datos["listProducts"], true);
$datosSucursal = $this->sucursales->find($datos["idSucursal"]);
$datos["idArqueoCaja"] = 0;
if ($datosSucursal["arqueoCaja"] == "on") {
$datosArqueoCaja = $this->arqueoCaja->mdlObtenerIdArqueo($datos["idEmpresa"], $datos["idSucursal"], $datos["date"]);
if (!isset($datosArqueoCaja["id"])) {
$this->sells->db->transRollback();
echo "No hay habilitado arqueo de caja";
return;
} else {
$datos["idArqueoCaja"] = $datosArqueoCaja["id"];
}
}
/**
* if is new sell
*/
if ($existsSell == 0) {
$ultimoFolio = $this->getLastCodeInterno($datos["idEmpresa"], $datos["idSucursal"]);
$empresa = $this->empresa->find($datos["idEmpresa"]);
$comprobante = $this->comprobantesRD->find($datos["tipoComprobanteRD"]);
if ($empresa["facturacionRD"] == "on") {
if ($datos["tipoComprobanteRD"] == "") {
$this->sells->db->transRollback();
echo "No se selecciono tipo comprobante";
return;
}
if ($datos["folioComprobanteRD"] == "") {
$this->sells->db->transRollback();
echo "No hay folio Comprobante";
return;
}
if ($datos["folioComprobanteRD"] > $comprobante["folioFinal"]) {
$this->sells->db->transRollback();
echo "Se agotaron los folio son hasta $comprobante[folioFinal] y van en $datos[folioComprobanteRD]";
return;
}
if ($datos["folioComprobanteRD"] < $comprobante["folioInicial"]) {
$this->sells->db->transRollback();
echo "Folio fuera de rango $comprobante[folioInicial] y van en $datos[folioComprobanteRD]";
return;
}
if ($datos["date"] < $comprobante["desdeFecha"]) {
$this->sells->db->transRollback();
echo "fecha fuera de rango limite inferior $comprobante[desdeFecha] fecha venta $datos[date]";
return;
}
if ($datos["date"] > $comprobante["hastaFecha"]) {
$this->sells->db->transRollback();
echo "fecha fuera de rango, limite superior $comprobante[desdeFecha] fecha venta $datos[date]";
return;
}
}
$datos["folio"] = $ultimoFolio;
$datos["balance"] = $datos["total"] - ($datos["importPayment"] - $datos["importBack"]);
try {
if ($this->sells->save($datos) === false) {
$errores = $this->sells->errors();
$listErrors = "";
foreach ($errores as $field => $error) {
$listErrors .= $error . " ";
}
echo $listErrors;
return;
}
$idSellInserted = $this->sells->getInsertID();
// save datail
foreach ($listProducts as $key => $value) {
$datosDetalle["idSell"] = $idSellInserted;
$datosDetalle["idProduct"] = $value["idProduct"];
$datosDetalle["description"] = $value["description"];
$datosDetalle["unidad"] = $value["unidad"];
$datosDetalle["codeProduct"] = $value["codeProduct"];
$datosDetalle["cant"] = $value["cant"];
$datosDetalle["price"] = $value["price"];
$datosDetalle["porcentTax"] = $value["porcentTax"];
$datosDetalle["porcentIVARetenido"] = $value["porcentIVARetenido"];
$datosDetalle["porcentISRRetenido"] = $value["porcentISRRetenido"];
$datosDetalle["IVARetenido"] = $value["IVARetenido"];
$datosDetalle["ISRRetenido"] = $value["ISRRetenido"];
$datosDetalle["claveProductoSAT"] = $value["claveProductoSAT"];
$datosDetalle["claveUnidadSAT"] = $value["claveUnidadSAT"];
$datosDetalle["lote"] = $value["lote"];
$datosDetalle["idAlmacen"] = $value["idAlmacen"];
$datosDetalle["tax"] = $value["tax"];
$datosDetalle["total"] = $value["total"];
$datosDetalle["neto"] = $value["neto"];
//Valida Stock
$products = $this->products->find($datosDetalle["idProduct"]);
if ($products["validateStock"] == "on") {
if ($products["stock"] < $datosDetalle["cant"]) {
echo "Stock agotado en el producto " . $datosDetalle["description"];
$this->sellsDetail->db->transRollback();
return;
}
}
if ($products["inventarioRiguroso"] == "on") {
$datosSaldo["idEmpresa"] = $datos["idEmpresa"];
$datosSaldo["idAlmacen"] = $datosDetalle["idAlmacen"];
$datosSaldo["idProducto"] = $datosDetalle["idProduct"];
$datosSaldo["lote"] = $datosDetalle["lote"];
/**
* Verificamos saldo
*/
$datosNuevosSaldo = $this->saldos->select("*")->where($datosSaldo)->first();
if ($datosNuevosSaldo["cantidad"] < $datosDetalle["cant"]) {
echo "Stock agotado en el producto " . $datosDetalle["description"];
$this->inventory->db->transRollback();
return;
}
$datosNuevosSaldo["cantidad"] = $datosNuevosSaldo["cantidad"] - $datosDetalle["cant"];
$existenciaProducto["stock"] = $products["stock"] - $datosDetalle["cant"];
if ($this->products->update($products["id"], $existenciaProducto) === false) {
echo "error al actualizar el saldo $datosDetalle[idProduct]";
$this->inventory->db->transRollback();
return;
}
if ($this->saldos->update($datosNuevosSaldo["id"], $datosNuevosSaldo) === false) {
$errores = $this->inventory->errors();
$listErrors = "";
foreach ($errores as $field => $error) {
$listErrors .= $error . " ";
}
echo $listErrors . " error al actualizar el saldo $datosDetalle[idProduct]";
;
$this->inventory->db->transRollback();
return;
}
}
if ($this->sellsDetail->save($datosDetalle) === false) {
echo "error al insertar el producto $datosDetalle[idProducto]";
$this->sellsDetail->db->transRollback();
return;
} else {
if ($products["validateStock"] == "on") {
// ACTUALIZA STOCK
$newStock = $products["stock"] - $datosDetalle["cant"];
$updateDataStock["stock"] = $newStock;
if ($this->products->update($datosDetalle["idProduct"], $updateDataStock) === false) {
echo "error al actualizar el stock del producto $datosDetalle[idProducto]";
$this->sellsDetail->db->transRollback();
return;
}
}
}
}
if ($datos["idQuote"] > 0) {
echo "Inserted" . $idSellInserted;
$newSellQuote["idSell"] = $idSellInserted;
if ($this->quotes->update($datos["idQuote"], $newSellQuote) === false) {
echo "error al actualizar el stock del producto $datosDetalle[idProducto]";
$this->sellsDetail->db->transRollback();
return;
}
}
/**
* if Payments i mayor to cero
*/
if ($datos["importPayment"] > 0) {
$dataPayment["idSell"] = $idSellInserted;
$dataPayment["importPayment"] = $datos["importPayment"];
$dataPayment["importBack"] = $datos["importBack"];
$dataPayment["datePayment"] = $datos["datePayment"];
$dataPayment["metodPayment"] = $datos["metodoPago"];
try {
if ($this->payments->save($dataPayment) === false) {
echo "error al insertar el pago ";
$this->sellsDetail->db->transRollback();
return;
}
} catch (\Exception $e) {
$this->sellsDetail->db->transRollback();
echo $e->getMessage();
return;
}
}
//ACTUALIZAMOS FOLIO ACTUAL COMPROBANTE
if ($empresa["facturacionRD"] == "on") {
$comprobante = $this->comprobantesRD->find($datos["tipoComprobanteRD"]);
$folio = $comprobante["folioActual"] + 1;
$datosComprobante["folioActual"] = $folio;
if ($this->comprobantesRD->update($datos["tipoComprobanteRD"], $datosComprobante))
;
}
$datosBitacora["description"] = "Se guardo la cotizacion con los siguientes datos" . json_encode($datos);
$datosBitacora["user"] = $userName;
$this->log->save($datosBitacora);
$this->sellsDetail->db->transCommit();
echo "Guardado Correctamente";
} catch (\PHPUnit\Framework\Exception $ex) {
echo "Error al guardar " . $ex->getMessage();
}
} else {
$backSell = $this->sells->where("UUID", $datos["UUID"])->first();
$listProductsBack = json_decode($backSell["listProducts"], true);
$datos["folio"] = $backSell["folio"];
if ($this->sells->update($backSell["id"], $datos) == false) {
$errores = $this->sells->errors();
$listError = "";
foreach ($errores as $field => $error) {
$listError .= $error . " ";
}
echo $listError;
return;
} else {
//DEJAMOS EL STOCK COMO ESTABA ANTES
foreach ($listProductsBack as $key => $value) {
//BUSCAMOS STOCK DEL PRODUCTO
$products = $this->products->find($value["idProduct"]);
if ($products["validateStock"] == "on") {
// ACTUALIZA STOCK
$newStock = $products["stock"] + $value["cant"];
$updateDataStock["stock"] = $newStock;
if ($this->products->update($value["idProduct"], $updateDataStock) === false) {
echo "error al actualizar el stock del producto $value[idProducto]";
$this->sellsDetail->db->transRollback();
return;
}
}
/**
* Devolvemos el saldo
*/
if ($products["inventarioRiguroso"] == "on") {
//DEVOLVEMOS EL SALDO
$datosSaldo["idEmpresa"] = $backSell["idEmpresa"];
$datosSaldo["idAlmacen"] = $value["idAlmacen"];
$datosSaldo["idProducto"] = $value["idProduct"];
$datosSaldo["lote"] = $value["lote"];
$datosNuevosSaldo = $this->saldos->select("*")->where($datosSaldo)->first();
$datosNuevosSaldo["cantidad"] = $datosNuevosSaldo["cantidad"] + $value["cant"];
if ($this->saldos->update($datosNuevosSaldo["id"], $datosNuevosSaldo) === false) {
echo "error al actualizar el saldo $value[idProducto]";
$this->inventory->db->transRollback();
return;
}
}
}
$this->sellsDetail->select("*")->where("idSell", $backSell["id"])->delete();
$this->sellsDetail->purgeDeleted();
foreach ($listProducts as $key => $value) {
$datosDetalle["idSell"] = $backSell["id"];
$datosDetalle["idProduct"] = $value["idProduct"];
$datosDetalle["description"] = $value["description"];
$datosDetalle["unidad"] = $value["unidad"];
$datosDetalle["codeProduct"] = $value["codeProduct"];
$datosDetalle["cant"] = $value["cant"];
$datosDetalle["price"] = $value["price"];
$datosDetalle["porcentTax"] = $value["porcentTax"];
$datosDetalle["porcentIVARetenido"] = $value["porcentIVARetenido"];
$datosDetalle["porcentISRRetenido"] = $value["porcentISRRetenido"];
$datosDetalle["IVARetenido"] = $value["IVARetenido"];
$datosDetalle["ISRRetenido"] = $value["ISRRetenido"];
$datosDetalle["claveProductoSAT"] = $value["claveProductoSAT"];
$datosDetalle["claveUnidadSAT"] = $value["claveUnidadSAT"];
$datosDetalle["lote"] = $value["lote"];
$datosDetalle["idAlmacen"] = $value["idAlmacen"];
$datosDetalle["tax"] = $value["tax"];
$datosDetalle["total"] = $value["total"];
$datosDetalle["neto"] = $value["neto"];
if ($this->sellsDetail->save($datosDetalle) === false) {
$errores = $this->sellsDetail->errors();
$listError = "";
foreach ($errores as $field => $error) {
$listError .= $error . " ";
}
echo "error al insertar el producto $datosDetalle[idProduct] $errores";
$this->sells->db->transRollback();
return;
} else {
if ($products["validateStock"] == "on") {
$products = $this->products->find($value["idProduct"]);
if ($products["stock"] < $datosDetalle["cant"]) {
echo "Stock agotado en el producto " . $datosDetalle["description"];
$this->sellsDetail->db->transRollback();
return;
}
//BUSCAMOS STOCK DEL PRODUCTO
$products = $this->products->find($value["idProduct"]);
// ACTUALIZA STOCK
$newStock = $products["stock"] - $datosDetalle["cant"];
$updateDataStock["stock"] = $newStock;
if ($this->products->update($datosDetalle["idProduct"], $updateDataStock) === false) {
echo "error al actualizar el stock del producto $datosDetalle[idProducto]";
$this->sellsDetail->db->transRollback();
return;
}
}
/**
* Devolvemos el saldo
*/
if ($products["inventarioRiguroso"] == "on") {
//DEVOLVEMOS EL SALDO
$datosSaldo["idEmpresa"] = $datos["idEmpresa"];
$datosSaldo["idAlmacen"] = $datosDetalle["idAlmacen"];
$datosSaldo["idProducto"] = $datosDetalle["idProduct"];
$datosSaldo["lote"] = $datosDetalle["lote"];
$datosNuevosSaldo = $this->saldos->select("*")->where($datosSaldo)->first();
if ($datosNuevosSaldo["cantidad"] < $datosDetalle["cant"]) {
echo "No hay stock suficiente en el producto $datosSaldo[idProduct]";
$this->inventory->db->transRollback();
return;
}
$datosNuevosSaldo["cantidad"] = $datosNuevosSaldo["cantidad"] - $datosDetalle["cant"];
if ($this->saldos->update($datosNuevosSaldo["id"], $datosNuevosSaldo) === false) {
echo "error al actualizar el saldo $value[idProducto]";
$this->inventory->db->transRollback();
return;
}
}
}
}
$datosBitacora["description"] = "Se actualizo" . json_encode($datos) .
" Los datos anteriores son" . json_encode($backSell);
$datosBitacora["user"] = $userName;
$this->log->save($datosBitacora);
echo "Actualizado Correctamente";
$this->sells->db->transCommit();
return;
}
}
return;
}
public function delete($id) {
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$auth = service('authentication');
if (!$auth->check()) {
return redirect()->route('admin');
}
$auth = service('authentication');
if (!$auth->check()) {
return redirect()->route('admin');
}
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$titulos["empresas"] = $this->empresa->mdlEmpresasPorUsuario($idUser);
if (count($titulos["empresas"]) == "0") {
$empresasID[0] = "0";
} else {
$empresasID = array_column($titulos["empresas"], "id");
}
/**
*
*/
if ($this->sells->select("*")->whereIn("idEmpresa", $empresasID)->where("id", $id)->countAllResults() == 0) {
return $this->failNotFound('Acceso Prohibido');
}
$this->sells->db->transBegin();
$infoSell = $this->sells->find($id);
/**
* Verificamos que no tenga enlazado XML
*/
if ($this->xmlEnlace->select("*")->where("idDocumento", $infoSell["id"])->countAllResults() > 0) {
$this->sells->db->transRollback();
return $this->failNotFound('La Venta no se puede eliminar por que ya tiene timbre enlazado');
}
/**
* Verificamos que no tenga Pagos Enlazados
*/
if ($this->payments->select("*")->where("idSell", $infoSell["id"])->countAllResults() > 0) {
$this->sells->db->transRollback();
return $this->failNotFound('La Venta no se puede eliminar por que ya tiene pagos ');
}
if (!$found = $this->sells->delete($id)) {
$this->sells->db->transRollback();
return $this->failNotFound('Error al eliminar');
}
//Borramos quotesdetails
if ($this->sellsDetail->select("*")->where("idSell", $id)->delete() === false) {
$this->sellsDetail->db->transRollback();
return $this->failNotFound('Error al eliminar el detalle');
}
$this->sellsDetail->purgeDeleted();
$listProducts = json_decode($infoSell["listProducts"], true);
$this->sells->purgeDeleted();
//Devolvemos el Stock
foreach ($listProducts as $key => $value) {
$product = $this->products->find($value["idProduct"]);
$stock = $product["stock"] + $value["cant"];
$newStock["stock"] = $stock;
if ($this->products->update($value["idProduct"], $newStock) === false) {
$this->sells->db->transRollback();
return $this->failNotFound('Error al actualizar el Stock');
}
/**
* Devolvemos el saldo
*/
if ($product["inventarioRiguroso"] == "on") {
//DEVOLVEMOS EL SALDO
$datosSaldo["idEmpresa"] = $infoSell["idEmpresa"];
$datosSaldo["idAlmacen"] = $value["idAlmacen"];
$datosSaldo["idProducto"] = $value["idProduct"];
$datosSaldo["lote"] = $value["lote"];
$datosNuevosSaldo = $this->saldos->select("*")->where($datosSaldo)->first();
$datosNuevosSaldo["cantidad"] = $datosNuevosSaldo["cantidad"] + $value["cant"];
if ($this->saldos->update($datosNuevosSaldo["id"], $datosNuevosSaldo) === false) {
echo "error al actualizar el saldo $value[idProducto]";
$this->inventory->db->transRollback();
return;
}
}
}
$datosBitacora["description"] = 'Se elimino el Registro' . json_encode($infoSell);
$this->log->save($datosBitacora);
$this->sells->db->transCommit();
return $this->respondDeleted($found, 'Eliminado Correctamente');
}
/*
public function delete($id) {
if (!$found = $this->register->delete($id)) {
return $this->failNotFound('Error al eliminar');
}
$infoConsukta = $this->register->find($id);
$this->register->purgeDeleted();
$datosBitacora["description"] = 'Se elimino el Registro' . json_encode($infoConsukta);
$this->log->save($datosBitacora);
return $this->respondDeleted($found, 'Eliminado Correctamente');
}
/**
* Trae en formato JSON los pacientes para el select2
* @return type
*/
/*
public function traerPacientesAjax() {
$request = service('request');
$postData = $request->getPost();
$response = array();
// Read new token and assign in $response['token']
$response['token'] = csrf_hash();
if (!isset($postData['searchTerm'])) {
// Fetch record
$pacientes = new PacientesModel();
$listaPacientes = $pacientes->select('id,nombres,apellidos')
->orderBy('nombres')
->findAll(10);
} else {
$searchTerm = $postData['searchTerm'];
// Fetch record
$pacientes = new PacientesModel();
$listaPacientes = $pacientes->select('id,nombres,apellidos')
->where("deleted_at", null)
->like('nombres', $searchTerm)
->orLike('apellidos', $searchTerm)
->orderBy('nombres')
->findAll(10);
}
$data = array();
foreach ($listaPacientes as $paciente) {
$data[] = array(
"id" => $paciente['id'],
"text" => $paciente['nombres'] . ' ' . $paciente['apellidos'],
);
}
$response['data'] = $data;
return $this->response->setJSON($response);
} */
/**
* Reporte Consulta
*/
public function report($uuid, $isMail = 0) {
$pdf = new PDFLayout(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$dataSells = $this->sells->where("uuid", $uuid)->first();
$listProducts = json_decode($dataSells["listProducts"], true);
$user = $this->user->where("id", $dataSells["idUser"])->first()->toArray();
$custumer = $this->custumer->where("id", $dataSells["idCustumer"])->where("deleted_at", null)->first();
$datosEmpresa = $this->empresa->select("*")->where("id", $dataSells["idEmpresa"])->first();
$datosEmpresaObj = $this->empresa->select("*")->where("id", $dataSells["idEmpresa"])->asObject()->first();
$pdf->nombreDocumento = "Nota De Venta";
$pdf->direccion = $datosEmpresaObj->direccion;
if ($datosEmpresaObj->logo == NULL || $datosEmpresaObj->logo == "") {
$pdf->logo = ROOTPATH . "public/images/logo/default.png";
} else {
$pdf->logo = ROOTPATH . "public/images/logo/" . $datosEmpresaObj->logo;
}
$pdf->folio = str_pad($dataSells["folio"], 5, "0", STR_PAD_LEFT);
$folioConsulta = "Folio Consulta";
$fecha = " Fecha: ";
// set document information
$pdf->nombreEmpresa = $datosEmpresa["nombre"];
$pdf->direccion = $datosEmpresa["direccion"];
$pdf->usuario = $user["firstname"] . " " . $user["lastname"];
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor($user["username"]);
$pdf->SetTitle('CI4JCPOS');
$pdf->SetSubject('CI4JCPOS');
$pdf->SetKeywords('CI4JCPOS, PDF, PHP, CodeIgniter, CESARSYSTEMS.COM.MX');
// set default header data
$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE, PDF_HEADER_STRING);
// set header and footer fonts
$pdf->setHeaderFont(array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
// set margins
$pdf->SetMargins(PDF_MARGIN_LEFT, 35, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
// set auto page breaks
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
// set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
// ---------------------------------------------------------
// add a page
$pdf->AddPage();
$pdf->SetY(45);
//ETIQUETAS
$cliente = "Cliente: ";
$folioRegistro = " Folio: ";
$fecha = " Fecha:";
$pdf->SetY(45);
//ETIQUETAS
$cliente = "Cliente: ";
$folioRegistro = " Folio: ";
$fecha = " Fecha:";
// set font
//$pdf->SetFont('times', '', 12);
if ($datosEmpresa["facturacionRD"] == "on" && $dataSells["folioComprobanteRD"] > 0) {
$comprobante = $this->comprobantesRD->find($dataSells["tipoComprobanteRD"]);
if ($comprobante["tipoDocumento"] == "COF") {
$tipoDocumento = "FACTURA PARA CONSUMIDOR FINAL";
}
if ($comprobante["tipoDocumento"] == "CF") {
$tipoDocumento = "FACTURA PARA CREDITO FISCAL";
}
$comprobanteFactura = $comprobante["prefijo"] . str_pad($dataSells["folioComprobanteRD"], 10, "0", STR_PAD_LEFT);
$fechaVencimiento = "AUTORIZADO POR DGII :" . $comprobante["hastaFecha"];
} else {
$tipoDocumento = "";
$comprobanteFactura = "";
$fechaVencimiento = "";
}
$bloque2 = <<<EOF
<table style="font-size:10px; padding:0px 10px;">
<tr>
<td style="width: 50%; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white;">ATENCION A
</td>
<td style="width: 50%; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white;">OBSERVACIONES
</td>
</tr>
<tr>
<td >
Cliente: $custumer[firstname] $custumer[lastname]
<br>
Telefono: 000
<br>
E-Mail: $custumer[email]
<br>
</td>
<td >
$dataSells[generalObservations]
$tipoDocumento <br>
$comprobanteFactura <br>
$fechaVencimiento <br>
</td>
</tr>
<tr>
<td style="width: 25%; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white;">VENDEDOR
</td>
<td style="width: 24%; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white;">FECHA
</td>
<td style="width: 30%; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white;">FECHA DE VENCIMIENTO
</td>
<td style="width: 21%; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white;">VIGENCIA
</td>
</tr>
<tr>
<td>
$user[firstname] $user[lastname]
</td>
<td>
$dataSells[date]
</td>
<td>
$dataSells[dateVen]
</td>
<td>
$dataSells[delivaryTime]
</td>
</tr>
<tr>
<td style="border-bottom: 1px solid #666; background-color:white; width:640px"></td>
</tr>
</table>
EOF;
$pdf->writeHTML($bloque2, false, false, false, false, '');
$bloque3 = <<<EOF
<table style="font-size:10px; padding:5px 10px;">
<tr>
<td style="width: 100px; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white; text-align:center">Código</td>
<td style="width: 200px; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white; text-align:center">Descripción</td>
<td style="width: 60px; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white; text-align:center">Cant</td>
<td style="width: 80px; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white; text-align:center">Precio</td>
<td style="width: 100px; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white; text-align:center">SubTotal</td>
<td style="width: 100px; background-color:#2c3e50; padding: 4px 4px 4px; font-weight:bold; color:white; text-align:center">Total</td>
</tr>
</table>
EOF;
$pdf->writeHTML($bloque3, false, false, false, false, '');
$contador = 0;
foreach ($listProducts as $key => $value) {
if ($contador % 2 == 0) {
$clase = 'style=" background-color:#ecf0f1; padding: 3px 4px 3px; ';
} else {
$clase = 'style="background-color:white; padding: 3px 4px 3px; ';
}
$precio = number_format($value["price"], 2, ".");
$subTotal = number_format($value["total"], 2, ".");
$total = number_format($value["neto"], 2, ".");
$bloque4 = <<<EOF
<table style="font-size:10px; padding:5px 10px;">
<tr>
<td $clase width:100px; text-align:center">
$value[codeProduct]
</td>
<td $clase width:200px; text-align:center">
$value[description]
</td>
<td $clase width:60px; text-align:center">
$value[cant]
</td>
<td $clase width:80px; text-align:right">
$precio
</td>
<td $clase width:100px; text-align:center">
$subTotal
</td>
<td $clase width:100px; text-align:right">
$total
</td>
</tr>
</table>
EOF;
$contador++;
$pdf->writeHTML($bloque4, false, false, false, false, '');
}
/**
* TOTALES
*/
$pdf->Setx(43);
$subTotal = number_format($dataSells["subTotal"], 2, ".");
$impuestos = number_format($dataSells["taxes"], 2, ".");
$total = number_format($dataSells["total"], 2, ".");
$IVARetenido = number_format($dataSells["IVARetenido"], 2, ".");
$ISRRetenido = number_format($dataSells["ISRRetenido"], 2, ".");
if ($IVARetenido > 0) {
$bloqueIVARetenido = <<<EOF
<tr>
<td style="border-right: 0px solid #666; color:#333; background-color:white; width:340px; text-align:right"></td>
<td style="border: 0px solid #666; background-color:white; width:100px; text-align:right">
IVA Retenido:
</td>
<td style="border: 0px solid #666; color:#333; background-color:white; width:100px; text-align:right">
$IVARetenido
</td>
</tr>
EOF;
} else {
$bloqueIVARetenido = "";
}
if ($ISRRetenido > 0) {
$bloqueISRRetenido = <<<EOF
<tr>
<td style="border-right: 0px solid #666; color:#333; background-color:white; width:340px; text-align:right"></td>
<td style="border: 0px solid #666; background-color:white; width:100px; text-align:right">
ISR Retenido:
</td>
<td style="border: 0px solid #666; color:#333; background-color:white; width:100px; text-align:right">
$ISRRetenido
</td>
</tr>
EOF;
} else {
$bloqueISRRetenido = "";
}
$bloque5 = <<<EOF
<table style="font-size:10px; padding:5px 10px;">
<tr>
<td style="color:#333; background-color:white; width:340px; text-align:right"></td>
<td style="border-bottom: 0px solid #666; background-color:white; width:100px; text-align:right"></td>
<td style="border-bottom: 0px solid #666; color:#333; background-color:white; width:100px; text-align:right"></td>
</tr>
<tr>
<td style="border-right: 0px solid #666; color:#333; background-color:white; width:340px; text-align:right"></td>
<td style="border: 0px solid #666; background-color:white; width:100px; text-align:right">
Subtotal:
</td>
<td style="border: 0px solid #666; color:#333; background-color:white; width:100px; text-align:right">
$subTotal
</td>
</tr>
<tr>
<td style="border-right: 0px solid #666; color:#333; background-color:white; width:340px; text-align:right"></td>
<td style="border: 0px solid #666; background-color:white; width:100px; text-align:right">
IVA:
</td>
<td style="border: 0px solid #666; color:#333; background-color:white; width:100px; text-align:right">
$impuestos
</td>
</tr>
$bloqueIVARetenido
$bloqueISRRetenido
<tr>
<td style="border-right: 0px solid #666; color:#333; background-color:white; width:340px; text-align:right"></td>
<td style="border: 0px solid #666; background-color:white; width:100px; text-align:right">
Total:
</td>
<td style="border: 0px solid #666; color:#333; background-color:white; width:100px; text-align:right">
$ $total
</td>
</tr>
</table>
<br>
<div style="font-size:11pt;text-align:center;font-weight:bold">Gracias por su compra!</div>
<br><br>
<div style="font-size:8.5pt;text-align:left;font-weight:ligth">UUID DOCUMENTO: $dataSells[UUID]</div>
<div style="font-size:8.5pt;text-align:left;font-weight:ligth">ES RESPONSABILIDAD DEL CLIENTE REVISAR A DETALLE ESTA COTIZACION PARA SU POSTERIOR SURTIDO, UNA VEZ CONFIRMADA, NO HAY CAMBIOS NI DEVOLUCIONES.</div>
EOF;
$pdf->writeHTML($bloque5, false, false, false, false, 'R');
if ($isMail == 0) {
ob_end_clean();
$this->response->setHeader("Content-Type", "application/pdf");
$pdf->Output('notaVenta.pdf', 'I');
} else {
$attachment = $pdf->Output('notaVenta.pdf', 'S');
return $attachment;
}
//============================================================+
// END OF FILE
//============================================================+
}
}
Creamos el archivo de controlador de pagos en App/controllers/PaymentsController.php con el siguiente código
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
use \App\Models\{
PaymentsModel
};
use App\Models\LogModel;
use CodeIgniter\API\ResponseTrait;
use App\Models\SellsModel;
use Exception;
class PaymentsController extends BaseController {
use ResponseTrait;
protected $log;
protected $payments;
protected $sells;
public function __construct() {
$this->payments = new PaymentsModel();
$this->log = new LogModel();
$this->sells = new SellsModel();
helper('menu');
}
public function index() {
if ($this->request->isAJAX()) {
$datos = $this->payments->select('id,idSell,importPayment,importBack,datePayment,metodPayment,created_at,updated_at,deleted_at')->where('deleted_at', null);
return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
}
$titulos["title"] = lang('payments.title');
$titulos["subtitle"] = lang('payments.subtitle');
return view('payments', $titulos);
}
/**
* Read Payments
*/
public function getPayments() {
$idPayments = $this->request->getPost("idPayments");
$datosPayments = $this->payments->find($idPayments);
echo json_encode($datosPayments);
}
/**
* Save or update Payments
*/
public function save() {
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$datos = $this->request->getPost();
$auth = service('authentication');
if (!$auth->check()) {
echo "No ha iniciado Session";
return;
}
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$this->payments->db->transBegin();
$datosVenta = $this->sells->select("*")->where("UUID", $datos["UUID"])->asArray()->first();
$datos["idSell"] = $datosVenta["id"];
try {
if ($this->payments->save($datos) === false) {
$errores = $this->payments->errors();
foreach ($errores as $field => $error) {
echo $error . " ";
}
$this->payments->DB::rollback();
return;
}
$dateLog["description"] = lang("vehicles.logDescription") . json_encode($datos);
$dateLog["user"] = $userName;
$this->log->save($dateLog);
try {
$datosVenta["balance"] = $datosVenta["balance"] - ($datos["importPayment"] - $datos["importBack"]);
echo $datosVenta["balance"];
$this->sells->update($datosVenta["id"], $datosVenta);
$this->payments->transCommit();
} catch (Exception $e) {
}
echo "Guardado Correctamente";
} catch (\PHPUnit\Framework\Exception $ex) {
echo "Error al guardar " . $ex->getMessage();
$this->payments->DB::rollback();
}
return;
}
public function ctrGetPayments($uuid) {
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$datos = $this->request->getPost();
$auth = service('authentication');
if (!$auth->check()) {
echo "No ha iniciado Session";
return;
}
$sell = $this->sells->select("*")->where("UUID", $uuid)->first();
if (!isset($sell["id"])) {
$sell["id"] = 0;
}
$datos = $this->payments
->select('id,idSell,importPayment,importBack,datePayment,metodPayment,created_at,updated_at,deleted_at')
->where('deleted_at', null)
->where('idSell', $sell["id"]);
return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
}
/**
* Delete Payments
* @param type $id
* @return type
*/
public function delete($id) {
$infoPayments = $this->payments->find($id);
$dataSell = $this->sells->find($infoPayments["idSell"]);
$totalPago = $infoPayments["importPayment"] - $infoPayments["importBack"];
$dataSellSave["balance"] = $dataSell["balance"] + $totalPago;
helper('auth');
$auth = service('authentication');
if (!$auth->check()) {
echo "no conectado";
return redirect()->route('login');
}
$userName = user()->username;
if (!$found = $this->payments->delete($id)) {
return $this->failNotFound(lang('payments.msg.msg_get_fail'));
}
/**
* Actualizamos saldo
*/
$resultVenta = $this->sells->update($dataSell["id"],$dataSellSave);
$this->payments->purgeDeleted();
$logData["description"] = lang("payments.logDeleted") . json_encode($infoPayments);
$logData["user"] = $userName;
$this->log->save($logData);
return $this->respondDeleted($found, lang('payments.msg_delete'));
}
}
Creamos el archivo controlador para la factura electrónica App/Controllers/FacturaElectronicaController.php con el siguiente código
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
use App\Database\Migrations\Storages;
use \App\Models\UserModel;
use App\Models\LogModel;
use App\Models\QuotesModel;
use App\Models\CompaniesModel;
use App\Models\StoragesModel;
use App\Models\QuotesDetailsModel;
use CfdiUtils\Elements\Cfdi40\Concepto;
use CodeIgniter\API\ResponseTrait;
use App\Models\EmpresasModel;
use App\Models\CustumersModel;
use App\Models\SellsModel;
use PhpParser\Node\Stmt\Foreach_;
use PhpCfdi\Credentials\Credential;
use App\Models\XmlModel;
use CURLFile;
use App\Models\EnlacexmlModel;
use App\Models\SeriesfacturaelectronicaModel;
use CfdiUtils\Elements\Pagos20\Pago;
use App\Models\PagosModel;
use App\Models\PaymentsModel;
use \CfdiUtils\SumasPagos20\Calculator;
use \CfdiUtils\SumasPagos20\Currencies;
use \CfdiUtils\SumasPagos20\PagosWriter;
class FacturaElectronicaController extends BaseController {
protected $sells;
protected $empresa;
protected $xml;
protected $xmlEnlace;
protected $serieElectronica;
protected $pagos;
protected $payments;
public function __construct() {
$this->sells = new SellsModel();
$this->empresa = new EmpresasModel();
$this->xml = new XmlModel();
$this->xmlEnlace = new EnlacexmlModel();
$this->serieElectronica = new SeriesfacturaelectronicaModel();
$this->pagos = new PagosModel();
$this->payments = new PaymentsModel();
helper('menu');
helper('utilerias');
}
public function timbrar($uuidVenta) {
$venta = $this->sells->select("*")->where("UUID ", $uuidVenta)->first();
$facturaExistentes = $this->xmlEnlace->select("id")->where("idDocumento", $venta["id"])->countAllResults();
if ($facturaExistentes > 0) {
echo "success";
return;
}
$serie = $this->serieElectronica->select("*")
->where("idEmpresa", $venta["idEmpresa"])
->where("tipoSerie", "ven")
->where("sucursal", $venta["idSucursal"])
->where("desdeFolio <=", $venta["folio"])
->where("hastaFolio >=", $venta["folio"])->first();
// VERIFICAMOS SI YA TIENE VENTA
if (!isset($serie)) {
echo "No hay serie electronica configurada";
return;
}
$empresa = $this->empresa->find($venta["idEmpresa"]);
if (file_exists(ROOTPATH . "writable/uploads/certificates/$empresa[certificadoCSD]")) {
try {
$certificado = new \CfdiUtils\Certificado\Certificado(ROOTPATH . "writable/uploads/certificates/$empresa[certificadoCSD]");
} catch (Exception $e) {
echo $e->getMessage();
return;
} finally {
if (!isset($certificado)) {
echo "No se encontro el certificado";
return;
}
}
} else {
echo "No se ha cargado certificado";
return;
}
if ($venta["usoCFDI"] == "" || $venta["usoCFDI"] == "NULL") {
echo "Falta capturar el uso del CFDI";
return;
}
$cerfile = ROOTPATH . "writable/uploads/certificates/$empresa[certificadoCSD]";
$keyfile = ROOTPATH . "writable/uploads/certificates/$empresa[archivoKeyCSD]";
$passPhrase = $empresa["contraCertificadoCSD"];
if (!file_exists($keyfile)) {
echo "No se ha cargado certificado el archivo key";
return;
}
$csd = Credential::openFiles($cerfile, $keyfile, $passPhrase);
$comprobanteAtributos = [
'Serie' => $serie["serie"],
'Folio' => $venta["folio"],
'Fecha' => fechaMySQLADateTimeHTML5(fechaHoraActual()),
'FormaPago' => $venta["formaPago"],
'SubTotal' => $venta["subTotal"],
'Total' => $venta["total"],
'Moneda' => 'MXN',
'TipoDeComprobante' => 'I',
'MetodoPago' => $venta["metodoPago"],
'LugarExpedicion' => $empresa["codigoPostal"],
'Exportacion' => '01',
'Sello' => '',
];
$creator = new \CfdiUtils\CfdiCreator40($comprobanteAtributos, $certificado);
$comprobante = $creator->comprobante();
/*
$comprobante->addInformacionGlobal([
'Periodicidad' => '01',
'Meses' => '06',
'Año' => '2023',
]);
*/
// No agrego (aunque puedo) el Rfc y Nombre porque uso los que están establecidos en el certificado
$comprobante->addEmisor([
'RegimenFiscal' => $empresa["regimenFiscal"], // General de Ley Personas Morales
'Nombre' => $empresa["razonSocial"], // Agregamos el Nombre por que en el certificado viene SA DE CV
]);
//$comprobante->addReceptor([/* Atributos del receptor */]);
$comprobante->addReceptor([
'Rfc' => $venta["RFCReceptor"],
'Nombre' => $venta["razonSocialReceptor"],
'DomicilioFiscalReceptor' => $venta["codigoPostalReceptor"],
'RegimenFiscalReceptor' => $venta["regimenFiscalReceptor"],
'UsoCFDI' => $venta["usoCFDI"],
]);
$listProducts = json_decode($venta["listProducts"], true);
foreach ($listProducts as $key => $value) {
$concepto = null;
if ($value["unidad"] == "" || $value["unidad"] == "NULL") {
echo "Falta capturar la unidad del producto" . $value["description"];
return;
}
if ($value["claveProductoSAT"] == "" || $value["claveProductoSAT"] == "NULL") {
echo "Falta capturar la clave del producto o servicio del producto" . $value["description"];
return;
}
if ($value["claveUnidadSAT"] == "" || $value["claveUnidadSAT"] == "NULL") {
echo "Falta capturar la clave de la unidad del producto" . $value["description"];
return;
}
// Verificamos si lleva Impuesto
$objetoImpuesto = "01";
if ($value["porcentTax"] > 0) {
$objetoImpuesto = "02";
}
if ($value["porcentIVARetenido"] > 0) {
$objetoImpuesto = "02";
}
if ($value["porcentISRRetenido"] > 0) {
$objetoImpuesto = "02";
}
$concepto = $comprobante->addConcepto([
'ClaveProdServ' => $value["claveProductoSAT"],
'Cantidad' => $value["cant"],
'ClaveUnidad' => $value["claveUnidadSAT"],
'Unidad' => $value["unidad"],
'Descripcion' => $value["description"],
'ValorUnitario' => $value["price"],
'Importe' => number_format($value["total"], 2, "."),
'ObjetoImp' => $objetoImpuesto,
]);
if ($value["porcentTax"] > 0) {
$porc = number_format(($value["porcentTax"] / 100), 6, ".");
$importeImpuesto = number_format($value["total"], 2, ".") * $porc;
$concepto->addTraslado([
'Base' => number_format($value["total"], 2, "."),
'Impuesto' => '002',
'TipoFactor' => 'Tasa',
'TasaOCuota' => $porc,
'Importe' => number_format($importeImpuesto, 2, "."),
]);
}
if ($value["porcentIVARetenido"] > 0) {
$porc = number_format(($value["porcentIVARetenido"] / 100), 6, ".");
$importeImpuesto = number_format($value["total"], 2, ".") * $porc;
$concepto->addRetencion([
'Base' => number_format($value["total"], 2, "."),
'Impuesto' => '002',
'TipoFactor' => 'Tasa',
'TasaOCuota' => $porc,
'Importe' => number_format($importeImpuesto, 2, "."),
]);
}
if ($value["porcentISRRetenido"] > 0) {
$porc = number_format(($value["porcentISRRetenido"] / 100), 6, ".");
$importeImpuesto = number_format($value["total"], 2, ".") * $porc;
$concepto->addRetencion([
'Base' => number_format($value["total"], 2, "."),
'Impuesto' => '001',
'TipoFactor' => 'Tasa',
'TasaOCuota' => $porc,
'Importe' => number_format($importeImpuesto, 2, "."),
]);
}
}
$creator->addSumasConceptos(null, 2);
// método de ayuda para mover las declaraciones de espacios de nombre al nodo raíz
$creator->moveSatDefinitionsToComprobante();
// método de ayuda para validar usando las validaciones estándar de creación de la librería
$asserts = $creator->validate();
if ($asserts->hasErrors()) { // contiene si hay o no errores
print_r(['errors' => $asserts->errors()]);
return;
}
// método de ayuda para generar el xml y retornarlo como un string
$creator->addSello($csd->privateKey()->pem(), $csd->privateKey()->passPhrase());
$xml = $creator->asXml();
if ($serie["ambienteTimbrado"] == "on") {
$url = "https://services.sw.com.mx/v4/cfdi33/issue/v4";
$token = $serie["tokenProduccion"];
} else {
$url = "https://services.test.sw.com.mx/v4/cfdi33/issue/v4";
$token = $serie["tokenPruebas"];
}
$archivoDestino = $xml;
$nombreXML = $uuidVenta . ".xml";
file_put_contents($nombreXML, $archivoDestino);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => array('xml' => new CURLFILE($nombreXML)),
CURLOPT_HTTPHEADER => array(
'Authorization: Bearer ' . $token . '',
'customid: ' . $uuidVenta . fechaHoraActual() . '',
),
));
$response = curl_exec($curl);
curl_close($curl);
$respuesta = json_decode($response, true);
if ($respuesta["status"] != "success") {
echo "error al timbrar " . $response;
return;
}
unlink($nombreXML);
// iniciamos transacccion
$this->xml->db->transBegin();
//file_put_contents("xmlTimbrado.xml", $respuesta["data"]["cfdi"]);
// Si se timbro correctamente extraemos los datos y lo guardamos
$xml = \PhpCfdi\CfdiCleaner\Cleaner::staticClean($respuesta["data"]["cfdi"]);
// create the main node structure
$comprobante = \CfdiUtils\Nodes\XmlNodeUtils::nodeFromXmlString($xml);
// create the CfdiData object, it contains all the required information
$cfdiData = (new \PhpCfdi\CfdiToPdf\CfdiDataBuilder())
->build($comprobante);
$tfd = $cfdiData->timbreFiscalDigital();
$emisor = $cfdiData->emisor();
$receptor = $cfdiData->receptor();
$datosXML["base16"] = "0.00";
$datosXML["totalImpuestos16"] = "0.00";
$datosXML["base8"] = "0.00";
$datosXML["totalImpuestos8"] = "0.00";
$impuestos = $comprobante->searchNode('cfdi:Impuestos');
if (isset($impuestos)) {
$traslados = $impuestos->searchNodes('cfdi:Traslados', 'cfdi:Traslado');
foreach ($traslados as $key) {
if ($key["TasaOCuota"] == 0.16) {
$datosXML["base16"] = $datosXML["base16"] + $key["Base"];
$datosXML["totalImpuestos16"] = $datosXML["totalImpuestos16"] + $key["Importe"];
}
if ($key["TasaOCuota"] == 0.08) {
$datosXML["base8"] = $datosXML["base8"] + $key["Base"];
$datosXML["totalImpuestos8"] = $datosXML["totalImpuestos8"] + $key["Importe"];
}
}
}
//$tfd['UUID']
$datosXML["uuidTimbre"] = $tfd['UUID'];
$datosXML["uuidPaquete"] = "SISTEMA";
$datosXML["idEmpresa"] = $venta["idEmpresa"];
$datosXML["archivoXML"] = $respuesta["data"]["cfdi"];
// $jsonXML = JsonConverter::convertToJson($content);
// $arregloXML = json_decode($jsonXML, true);
$datosXML["fecha"] = $comprobante["Fecha"];
$datosXML["fechaTimbrado"] = $tfd['FechaTimbrado'];
$datosXML["total"] = $comprobante["Total"];
$datosXML["tipoComprobante"] = $comprobante["TipoDeComprobante"];
$datosXML["rfcEmisor"] = $emisor['Rfc'];
$datosXML["rfcReceptor"] = $receptor['Rfc'];
$datosXML["nombreEmisor"] = $emisor['Nombre'];
$datosXML["nombreReceptor"] = $receptor['Nombre'];
$datosXML["metodoPago"] = $comprobante['MetodoPago'];
$datosXML["formaPago"] = $comprobante['FormaPago'];
$datosXML["usoCFDI"] = $receptor['UsoCFDI'];
$datosXML["exportacion"] = $comprobante['Exportacion'];
$datosXML["emitidoRecibido"] = "emitido";
if (isset($comprobante["Serie"])) {
$datosXML["serie"] = $comprobante["Serie"];
} else {
$datosXML["serie"] = "";
}
if (isset($comprobante["Folio"])) {
$datosXML["folio"] = $comprobante["Folio"];
} else {
$datosXML["folio"] = "";
}
$totalRen = $this->xml->selectCount("id")->where("uuidTimbre", $datosXML["uuidTimbre"])->first();
$totalRen = $totalRen["id"];
if ($totalRen == 0) {
if ($this->xml->insert($datosXML) === false) {
$errores = $this->xml->errors();
$listErrors = "";
foreach ($errores as $field => $error) {
$listErrors .= $error . " ";
}
$this->xml->db->transRollback();
echo $listErrors;
return;
}
}
/*
* Insertamos en enlace
*/
$datosEnlace["idDocumento"] = $venta["id"];
$datosEnlace["uuidXML"] = $datosXML["uuidTimbre"];
$datosEnlace["tipo"] = "ven";
$datosEnlace["importe"] = $comprobante["Total"];
if ($this->xmlEnlace->insert($datosEnlace) === false) {
$errores = $this->xmlEnlace->errors();
$listErrors = "";
foreach ($errores as $field => $error) {
$listErrors .= $error . " ";
}
$this->xml->db->transRollback();
echo $listErrors;
return;
}
$this->xml->db->transCommit();
echo "success";
}
public function timbrarCartaPorte($uuidCartaPorte) {
$venta = $this->sells->select("*")->where("UUID ", $uuidVenta)->first();
$facturaExistentes = $this->xmlEnlace->select("id")->where("idDocumento", $venta["id"])->countAllResults();
if ($facturaExistentes > 0) {
echo "success";
return;
}
$serie = $this->serieElectronica->select("*")
->where("idEmpresa", $venta["idEmpresa"])
->where("tipoSerie", "ven")
->where("sucursal", $venta["idSucursal"])
->where("desdeFolio <=", $venta["folio"])
->where("hastaFolio >=", $venta["folio"])->first();
// VERIFICAMOS SI YA TIENE VENTA
if (!isset($serie)) {
echo "No hay serie electronica configurada";
return;
}
$empresa = $this->empresa->find($venta["idEmpresa"]);
if (file_exists(ROOTPATH . "writable/uploads/certificates/$empresa[certificadoCSD]")) {
try {
$certificado = new \CfdiUtils\Certificado\Certificado(ROOTPATH . "writable/uploads/certificates/$empresa[certificadoCSD]");
} catch (Exception $e) {
echo $e->getMessage();
return;
} finally {
if (!isset($certificado)) {
echo "No se encontro el certificado";
return;
}
}
} else {
echo "No se ha cargado certificado";
return;
}
if ($venta["usoCFDI"] == "" || $venta["usoCFDI"] == "NULL") {
echo "Falta capturar el uso del CFDI";
return;
}
$cerfile = ROOTPATH . "writable/uploads/certificates/$empresa[certificadoCSD]";
$keyfile = ROOTPATH . "writable/uploads/certificates/$empresa[archivoKeyCSD]";
$passPhrase = $empresa["contraCertificadoCSD"];
if (!file_exists($keyfile)) {
echo "No se ha cargado certificado el archivo key";
return;
}
$csd = Credential::openFiles($cerfile, $keyfile, $passPhrase);
$comprobanteAtributos = [
'Serie' => $serie["serie"],
'Folio' => $venta["folio"],
'Fecha' => fechaMySQLADateTimeHTML5(fechaHoraActual()),
'FormaPago' => $venta["formaPago"],
'SubTotal' => $venta["subTotal"],
'Total' => $venta["total"],
'Moneda' => 'MXN',
'TipoDeComprobante' => 'I',
'MetodoPago' => $venta["metodoPago"],
'LugarExpedicion' => $empresa["codigoPostal"],
'Exportacion' => '01',
'Sello' => '',
];
$creator = new \CfdiUtils\CfdiCreator40($comprobanteAtributos, $certificado);
$comprobante = $creator->comprobante();
/*
$comprobante->addInformacionGlobal([
'Periodicidad' => '01',
'Meses' => '06',
'Año' => '2023',
]);
*/
// No agrego (aunque puedo) el Rfc y Nombre porque uso los que están establecidos en el certificado
$comprobante->addEmisor([
'RegimenFiscal' => $empresa["regimenFiscal"], // General de Ley Personas Morales
'Nombre' => $empresa["razonSocial"], // Agregamos el Nombre por que en el certificado viene SA DE CV
]);
//$comprobante->addReceptor([/* Atributos del receptor */]);
$comprobante->addReceptor([
'Rfc' => $venta["RFCReceptor"],
'Nombre' => $venta["razonSocialReceptor"],
'DomicilioFiscalReceptor' => $venta["codigoPostalReceptor"],
'RegimenFiscalReceptor' => $venta["regimenFiscalReceptor"],
'UsoCFDI' => $venta["usoCFDI"],
]);
$listProducts = json_decode($venta["listProducts"], true);
foreach ($listProducts as $key => $value) {
$concepto = null;
if ($value["unidad"] == "" || $value["unidad"] == "NULL") {
echo "Falta capturar la unidad del producto" . $value["description"];
return;
}
if ($value["claveProductoSAT"] == "" || $value["claveProductoSAT"] == "NULL") {
echo "Falta capturar la clave del producto o servicio del producto" . $value["description"];
return;
}
if ($value["claveUnidadSAT"] == "" || $value["claveUnidadSAT"] == "NULL") {
echo "Falta capturar la clave de la unidad del producto" . $value["description"];
return;
}
// Verificamos si lleva Impuesto
$objetoImpuesto = "01";
if ($value["porcentTax"] > 0) {
$objetoImpuesto = "02";
}
if ($value["porcentIVARetenido"] > 0) {
$objetoImpuesto = "02";
}
if ($value["porcentISRRetenido"] > 0) {
$objetoImpuesto = "02";
}
$concepto = $comprobante->addConcepto([
'ClaveProdServ' => $value["claveProductoSAT"],
'Cantidad' => $value["cant"],
'ClaveUnidad' => $value["claveUnidadSAT"],
'Unidad' => $value["unidad"],
'Descripcion' => $value["description"],
'ValorUnitario' => $value["price"],
'Importe' => number_format($value["total"], 2, "."),
'ObjetoImp' => $objetoImpuesto,
]);
if ($value["porcentTax"] > 0) {
$porc = number_format(($value["porcentTax"] / 100), 6, ".");
$importeImpuesto = number_format($value["total"], 2, ".") * $porc;
$concepto->addTraslado([
'Base' => number_format($value["total"], 2, "."),
'Impuesto' => '002',
'TipoFactor' => 'Tasa',
'TasaOCuota' => $porc,
'Importe' => number_format($importeImpuesto, 2, "."),
]);
}
if ($value["porcentIVARetenido"] > 0) {
$porc = number_format(($value["porcentIVARetenido"] / 100), 6, ".");
$importeImpuesto = number_format($value["total"], 2, ".") * $porc;
$concepto->addRetencion([
'Base' => number_format($value["total"], 2, "."),
'Impuesto' => '002',
'TipoFactor' => 'Tasa',
'TasaOCuota' => $porc,
'Importe' => number_format($importeImpuesto, 2, "."),
]);
}
if ($value["porcentISRRetenido"] > 0) {
$porc = number_format(($value["porcentISRRetenido"] / 100), 6, ".");
$importeImpuesto = number_format($value["total"], 2, ".") * $porc;
$concepto->addRetencion([
'Base' => number_format($value["total"], 2, "."),
'Impuesto' => '001',
'TipoFactor' => 'Tasa',
'TasaOCuota' => $porc,
'Importe' => number_format($importeImpuesto, 2, "."),
]);
}
}
$creator->addSumasConceptos(null, 2);
// método de ayuda para mover las declaraciones de espacios de nombre al nodo raíz
$creator->moveSatDefinitionsToComprobante();
// método de ayuda para validar usando las validaciones estándar de creación de la librería
$asserts = $creator->validate();
if ($asserts->hasErrors()) { // contiene si hay o no errores
print_r(['errors' => $asserts->errors()]);
return;
}
// método de ayuda para generar el xml y retornarlo como un string
$creator->addSello($csd->privateKey()->pem(), $csd->privateKey()->passPhrase());
$xml = $creator->asXml();
if ($serie["ambienteTimbrado"] == "on") {
$url = "https://services.sw.com.mx/v4/cfdi33/issue/v4";
$token = $serie["tokenProduccion"];
} else {
$url = "https://services.test.sw.com.mx/v4/cfdi33/issue/v4";
$token = $serie["tokenPruebas"];
}
$archivoDestino = $xml;
$nombreXML = $uuidVenta . ".xml";
file_put_contents($nombreXML, $archivoDestino);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => array('xml' => new CURLFILE($nombreXML)),
CURLOPT_HTTPHEADER => array(
'Authorization: Bearer ' . $token . '',
'customid: ' . $uuidVenta . fechaHoraActual() . '',
),
));
$response = curl_exec($curl);
curl_close($curl);
$respuesta = json_decode($response, true);
if ($respuesta["status"] != "success") {
echo "error al timbrar " . $response;
return;
}
unlink($nombreXML);
// iniciamos transacccion
$this->xml->db->transBegin();
//file_put_contents("xmlTimbrado.xml", $respuesta["data"]["cfdi"]);
// Si se timbro correctamente extraemos los datos y lo guardamos
$xml = \PhpCfdi\CfdiCleaner\Cleaner::staticClean($respuesta["data"]["cfdi"]);
// create the main node structure
$comprobante = \CfdiUtils\Nodes\XmlNodeUtils::nodeFromXmlString($xml);
// create the CfdiData object, it contains all the required information
$cfdiData = (new \PhpCfdi\CfdiToPdf\CfdiDataBuilder())
->build($comprobante);
$tfd = $cfdiData->timbreFiscalDigital();
$emisor = $cfdiData->emisor();
$receptor = $cfdiData->receptor();
$datosXML["base16"] = "0.00";
$datosXML["totalImpuestos16"] = "0.00";
$datosXML["base8"] = "0.00";
$datosXML["totalImpuestos8"] = "0.00";
$impuestos = $comprobante->searchNode('cfdi:Impuestos');
if (isset($impuestos)) {
$traslados = $impuestos->searchNodes('cfdi:Traslados', 'cfdi:Traslado');
foreach ($traslados as $key) {
if ($key["TasaOCuota"] == 0.16) {
$datosXML["base16"] = $datosXML["base16"] + $key["Base"];
$datosXML["totalImpuestos16"] = $datosXML["totalImpuestos16"] + $key["Importe"];
}
if ($key["TasaOCuota"] == 0.08) {
$datosXML["base8"] = $datosXML["base8"] + $key["Base"];
$datosXML["totalImpuestos8"] = $datosXML["totalImpuestos8"] + $key["Importe"];
}
}
}
//$tfd['UUID']
$datosXML["uuidTimbre"] = $tfd['UUID'];
$datosXML["uuidPaquete"] = "SISTEMA";
$datosXML["idEmpresa"] = $venta["idEmpresa"];
$datosXML["archivoXML"] = $respuesta["data"]["cfdi"];
// $jsonXML = JsonConverter::convertToJson($content);
// $arregloXML = json_decode($jsonXML, true);
$datosXML["fecha"] = $comprobante["Fecha"];
$datosXML["fechaTimbrado"] = $tfd['FechaTimbrado'];
$datosXML["total"] = $comprobante["Total"];
$datosXML["tipoComprobante"] = $comprobante["TipoDeComprobante"];
$datosXML["rfcEmisor"] = $emisor['Rfc'];
$datosXML["rfcReceptor"] = $receptor['Rfc'];
$datosXML["nombreEmisor"] = $emisor['Nombre'];
$datosXML["nombreReceptor"] = $receptor['Nombre'];
$datosXML["metodoPago"] = $comprobante['MetodoPago'];
$datosXML["formaPago"] = $comprobante['FormaPago'];
$datosXML["usoCFDI"] = $receptor['UsoCFDI'];
$datosXML["exportacion"] = $comprobante['Exportacion'];
$datosXML["emitidoRecibido"] = "emitido";
if (isset($comprobante["Serie"])) {
$datosXML["serie"] = $comprobante["Serie"];
} else {
$datosXML["serie"] = "";
}
if (isset($comprobante["Folio"])) {
$datosXML["folio"] = $comprobante["Folio"];
} else {
$datosXML["folio"] = "";
}
$totalRen = $this->xml->selectCount("id")->where("uuidTimbre", $datosXML["uuidTimbre"])->first();
$totalRen = $totalRen["id"];
if ($totalRen == 0) {
if ($this->xml->insert($datosXML) === false) {
$errores = $this->xml->errors();
$listErrors = "";
foreach ($errores as $field => $error) {
$listErrors .= $error . " ";
}
$this->xml->db->transRollback();
echo $listErrors;
return;
}
}
/*
* Insertamos en enlace
*/
$datosEnlace["idDocumento"] = $venta["id"];
$datosEnlace["uuidXML"] = $datosXML["uuidTimbre"];
$datosEnlace["tipo"] = "ven";
$datosEnlace["importe"] = $comprobante["Total"];
if ($this->xmlEnlace->insert($datosEnlace) === false) {
$errores = $this->xmlEnlace->errors();
$listErrors = "";
foreach ($errores as $field => $error) {
$listErrors .= $error . " ";
}
$this->xml->db->transRollback();
echo $listErrors;
return;
}
$this->xml->db->transCommit();
echo "success";
}
public function timbrarPago($uuidPago) {
$pago = $this->pagos->select("*")->where("UUID ", $uuidPago)->first();
$facturaExistentes = $this->xmlEnlace->select("id")
->where("idDocumento", $pago["id"])
->where("tipo", "pag")
->countAllResults();
if ($facturaExistentes > 0) {
echo "success";
return;
}
$serie = $this->serieElectronica->select("*")
->where("idEmpresa", $pago["idEmpresa"])
->where("tipoSerie", "pag")
->where("sucursal", $pago["idSucursal"])
->where("desdeFolio <=", $pago["folio"])
->where("hastaFolio >=", $pago["folio"])->first();
// VERIFICAMOS SI YA TIENE VENTA
if (!isset($serie)) {
echo "No hay serie electronica configurada";
return;
}
$empresa = $this->empresa->find($pago["idEmpresa"]);
$certificado = new \CfdiUtils\Certificado\Certificado(ROOTPATH . "writable/uploads/certificates/$empresa[certificadoCSD]");
if ($pago["usoCFDI"] == "" || $pago["usoCFDI"] == "NULL") {
echo "Falta capturar el uso del CFDI";
return;
}
$cerfile = ROOTPATH . "writable/uploads/certificates/$empresa[certificadoCSD]";
$keyfile = ROOTPATH . "writable/uploads/certificates/$empresa[archivoKeyCSD]";
$passPhrase = $empresa["contraCertificadoCSD"];
$csd = Credential::openFiles($cerfile, $keyfile, $passPhrase);
$comprobanteAtributos = [
'Serie' => $serie["serie"],
'Folio' => $pago["folio"],
'Fecha' => fechaMySQLADateTimeHTML5(fechaMySQLADateHTML5(fechaHoraActual())),
'SubTotal' => "0",
'Total' => "0",
'Moneda' => 'XXX',
'TipoDeComprobante' => 'P',
'LugarExpedicion' => $empresa["codigoPostal"],
'Exportacion' => '01',
'Sello' => '',
];
$creator = new \CfdiUtils\CfdiCreator40($comprobanteAtributos, $certificado);
$comprobante = $creator->comprobante();
/*
$comprobante->addInformacionGlobal([
'Periodicidad' => '01',
'Meses' => '06',
'Año' => '2023',
]);
*/
// No agrego (aunque puedo) el Rfc y Nombre porque uso los que están establecidos en el certificado
$comprobante->addEmisor([
'RegimenFiscal' => $empresa["regimenFiscal"], // General de Ley Personas Morales
'Nombre' => $empresa["razonSocial"], // Agregamos el Nombre por que en el certificado viene SA DE CV
]);
//$comprobante->addReceptor([/* Atributos del receptor */]);
$comprobante->addReceptor([
'Rfc' => $pago["RFCReceptor"],
'Nombre' => $pago["razonSocialReceptor"],
'DomicilioFiscalReceptor' => $pago["codigoPostalReceptor"],
'RegimenFiscalReceptor' => $pago["regimenFiscalReceptor"],
'UsoCFDI' => $pago["usoCFDI"],
]);
$ventasPagadas = $this->payments->select("*")->where("idComplemento", $pago["id"])->findAll();
$concepto = $comprobante->addConcepto([
'ClaveProdServ' => "84111506",
'Cantidad' => "1",
'ClaveUnidad' => "ACT",
'Descripcion' => "Pago",
'ValorUnitario' => "0",
'Importe' => "0",
'ObjetoImp' => "01",
]);
$pagosElemento = new \CfdiUtils\Elements\Pagos20\Pagos();
$montoAPagar = $pago["total"];
$pagoDocto = $pagosElemento->addPago([
'Monto' => number_format($montoAPagar, 2),
'MonedaP' => "MXN",
'TipoCambioP' => "1",
'FormaDePagoP' => "02",
'FechaPago' => fechaMySQLADateTimeHTML5(fechaMySQLADateTimeHTML5(fechaHoraActual()))
]);
$creator->hasXmlResolver();
foreach ($ventasPagadas as $key => $value) {
$venta = $this->sells->select("*")->where("id", $value["idSell"])->first();
$enlace = $this->xmlEnlace->select("*")->where("idDocumento", $venta["id"])->first();
$xmlVenta = $this->xml->select("*")->where("uuidTimbre", $enlace["uuidXML"])->first();
$parcialidad = $this->xml->mdlParcialidadVenta($venta["id"], $pago["id"]) + 1;
$saldo = $this->xml->mdlSaldo($venta["id"], $pago["id"]);
//Objeto de impuestos documento relacionado
$ObjetoImpDR = "01";
if ($xmlVenta["base16"] > 0) {
$ObjetoImpDR = "02";
$porcBase16 = $xmlVenta["totalImpuestos16"] / $xmlVenta["total"];
$montoPagoIVA16 = number_format($montoAPagar * $porcBase16, 6);
$basePago16 = number_format($montoAPagar - $montoPagoIVA16, 6);
$trastalado["ImporteDR"] = $montoPagoIVA16;
$trastalado["TasaOCuotaDR"] = "0.160000";
$trastalado["TipoFactorDR"] = "Tasa";
$trastalado["ImpuestoDR"] = "002";
$trastalado["BaseDR"] = $basePago16;
}
$doctumentoRelacionado = $pagoDocto->addDoctoRelacionado([
'Folio' => $xmlVenta["folio"],
'Serie' => $xmlVenta["serie"],
'IdDocumento' => $xmlVenta["uuidTimbre"],
'MonedaDR' => "MXN",
'ObjetoImpDR' => $ObjetoImpDR,
'EquivalenciaDR' => "1",
'NumParcialidad' => $parcialidad,
'ImpSaldoAnt' => $venta["total"] - $saldo,
'ImpSaldoInsoluto' => ($venta["total"] - $saldo) - $montoAPagar,
'ImpPagado' => number_format($montoAPagar, 2),
]);
if ($xmlVenta["base16"] > 0) {
$doctumentoRelacionado->addImpuestosDR()->addTrasladosDR()->addTrasladoDR($trastalado);
}
}
PagosWriter::calculateAndPut($pagosElemento);
/*
// Se puede calcular y mandar a escribir
$pagosCalculator = new Calculator(
2, // Decimales a usar en los impuestos de los pagos
new Currencies(['MXN' => 2, 'USD' => '2', 'EUR' => 2]) // Monedas con decimales
);
$result = $pagosCalculator->calculate($pagosElemento);
$pagosWriter = new PagosWriter($pagosElemento);
$pagosWriter->writePago($pagosElemento);
*/
// $creator->addSumasConceptos(null, 2);
// método de ayuda para mover las declaraciones de espacios de nombre al nodo raíz
$comprobante->addComplemento($pagosElemento);
$creator->moveSatDefinitionsToComprobante();
$xml = $creator->asXml();
$archivoDestino = $xml;
$nombreXML = $uuidPago . ".xml";
file_put_contents($nombreXML, $archivoDestino);
// método de ayuda para validar usando las validaciones estándar de creación de la librería
$asserts = $creator->validate();
if ($asserts->hasErrors()) { // contiene si hay o no errores
print_r(['errors' => $asserts->errors()]);
return;
}
// método de ayuda para generar el xml y retornarlo como un string
$creator->addSello($csd->privateKey()->pem(), $csd->privateKey()->passPhrase());
if ($serie["ambienteTimbrado"] == "on") {
$url = "https://services.sw.com.mx/v4/cfdi33/issue/v4";
$token = $serie["tokenProduccion"];
} else {
$url = "https://services.test.sw.com.mx/v4/cfdi33/issue/v4";
$token = $serie["tokenPruebas"];
}
$archivoDestino = $xml;
$nombreXML = $uuidPago . ".xml";
file_put_contents($nombreXML, $archivoDestino);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => array('xml' => new CURLFILE($nombreXML)),
CURLOPT_HTTPHEADER => array(
'Authorization: Bearer ' . $token . '',
'customid: ' . $uuidPago . fechaHoraActual() . '',
),
));
$response = curl_exec($curl);
curl_close($curl);
$respuesta = json_decode($response, true);
if ($respuesta["status"] != "success") {
echo "error al timbrar " . $response;
return;
}
unlink($nombreXML);
// iniciamos transacccion
$this->xml->db->transBegin();
//file_put_contents("xmlTimbrado.xml", $respuesta["data"]["cfdi"]);
// Si se timbro correctamente extraemos los datos y lo guardamos
$xml = \PhpCfdi\CfdiCleaner\Cleaner::staticClean($respuesta["data"]["cfdi"]);
// create the main node structure
$comprobante = \CfdiUtils\Nodes\XmlNodeUtils::nodeFromXmlString($xml);
// create the CfdiData object, it contains all the required information
$cfdiData = (new \PhpCfdi\CfdiToPdf\CfdiDataBuilder())
->build($comprobante);
$tfd = $cfdiData->timbreFiscalDigital();
$emisor = $cfdiData->emisor();
$receptor = $cfdiData->receptor();
$datosXML["base16"] = "0.00";
$datosXML["totalImpuestos16"] = "0.00";
$datosXML["base8"] = "0.00";
$datosXML["totalImpuestos8"] = "0.00";
$impuestos = $comprobante->searchNode('cfdi:Impuestos');
if (isset($impuestos)) {
$traslados = $impuestos->searchNodes('cfdi:Traslados', 'cfdi:Traslado');
foreach ($traslados as $key) {
if ($key["TasaOCuota"] == 0.16) {
$datosXML["base16"] = $datosXML["base16"] + $key["Base"];
$datosXML["totalImpuestos16"] = $datosXML["totalImpuestos16"] + $key["Importe"];
}
if ($key["TasaOCuota"] == 0.08) {
$datosXML["base8"] = $datosXML["base8"] + $key["Base"];
$datosXML["totalImpuestos8"] = $datosXML["totalImpuestos8"] + $key["Importe"];
}
}
}
//$tfd['UUID']
$datosXML["uuidTimbre"] = $tfd['UUID'];
$datosXML["uuidPaquete"] = "SISTEMA";
$datosXML["idEmpresa"] = $venta["idEmpresa"];
$datosXML["archivoXML"] = $respuesta["data"]["cfdi"];
// $jsonXML = JsonConverter::convertToJson($content);
// $arregloXML = json_decode($jsonXML, true);
$datosXML["fecha"] = $comprobante["Fecha"];
$datosXML["fechaTimbrado"] = $tfd['FechaTimbrado'];
$datosXML["total"] = $comprobante["Total"];
$datosXML["tipoComprobante"] = $comprobante["TipoDeComprobante"];
$datosXML["rfcEmisor"] = $emisor['Rfc'];
$datosXML["rfcReceptor"] = $receptor['Rfc'];
$datosXML["nombreEmisor"] = $emisor['Nombre'];
$datosXML["nombreReceptor"] = $receptor['Nombre'];
$datosXML["metodoPago"] = $comprobante['MetodoPago'];
$datosXML["formaPago"] = $comprobante['FormaPago'];
$datosXML["usoCFDI"] = $receptor['UsoCFDI'];
$datosXML["exportacion"] = $comprobante['Exportacion'];
$datosXML["emitidoRecibido"] = "emitido";
if (isset($comprobante["Serie"])) {
$datosXML["serie"] = $comprobante["Serie"];
} else {
$datosXML["serie"] = "";
}
if (isset($comprobante["Folio"])) {
$datosXML["folio"] = $comprobante["Folio"];
} else {
$datosXML["folio"] = "";
}
$totalRen = $this->xml->selectCount("id")->where("uuidTimbre", $datosXML["uuidTimbre"])->first();
$totalRen = $totalRen["id"];
if ($totalRen == 0) {
if ($this->xml->insert($datosXML) === false) {
$errores = $this->xml->errors();
$listErrors = "";
foreach ($errores as $field => $error) {
$listErrors .= $error . " ";
}
$this->xml->db->transRollback();
echo $listErrors;
return;
}
}
/*
* Insertamos en enlace
*/
$datosEnlace["idDocumento"] = $pago["id"];
$datosEnlace["uuidXML"] = $datosXML["uuidTimbre"];
$datosEnlace["tipo"] = "pag";
$datosEnlace["importe"] = $comprobante["Total"];
if ($this->xmlEnlace->insert($datosEnlace) === false) {
$errores = $this->xmlEnlace->errors();
$listErrors = "";
foreach ($errores as $field => $error) {
$listErrors .= $error . " ";
}
$this->xml->db->transRollback();
echo $listErrors;
return;
}
$this->xml->db->transCommit();
echo "success";
}
}
Creamos el archivo de controlador App/Controllers/EnlacexmlController.php
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
use \App\Models\{
EnlacexmlModel
};
use App\Models\LogModel;
use CodeIgniter\API\ResponseTrait;
use App\Models\EmpresasModel;
class EnlacexmlController extends BaseController {
use ResponseTrait;
protected $log;
protected $enlacexml;
public function __construct() {
$this->enlacexml = new EnlacexmlModel();
$this->log = new LogModel();
$this->empresa = new EmpresasModel();
helper('menu');
helper('utilerias');
}
public function index() {
helper('auth');
$idUser = user()->id;
$titulos["empresas"] = $this->empresa->mdlEmpresasPorUsuario($idUser);
if (count($titulos["empresas"]) == "0") {
$empresasID[0] = "0";
} else {
$empresasID = array_column($titulos["empresas"], "id");
}
if ($this->request->isAJAX()) {
$datos = $this->enlacexml->mdlGetEnlacexml($empresasID);
return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
}
$titulos["title"] = lang('enlacexml.title');
$titulos["subtitle"] = lang('enlacexml.subtitle');
return view('enlacexml', $titulos);
}
/**
* Read Enlacexml
*/
public function getEnlacexml() {
helper('auth');
$idUser = user()->id;
$titulos["empresas"] = $this->empresa->mdlEmpresasPorUsuario($idUser);
if (count($titulos["empresas"]) == "0") {
$empresasID[0] = "0";
} else {
$empresasID = array_column($titulos["empresas"], "id");
}
$idEnlacexml = $this->request->getPost("idEnlacexml");
$datosEnlacexml = $this->enlacexml->whereIn('idEmpresa', $empresasID)
->where("id", $idEnlacexml)->first();
echo json_encode($datosEnlacexml);
}
/**
* Save or update Enlacexml
*/
public function save() {
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$datos = $this->request->getPost();
if ($datos["idEnlacexml"] == 0) {
try {
if ($this->enlacexml->save($datos) === false) {
$errores = $this->enlacexml->errors();
foreach ($errores as $field => $error) {
echo $error . " ";
}
return;
}
$dateLog["description"] = lang("vehicles.logDescription") . json_encode($datos);
$dateLog["user"] = $userName;
$this->log->save($dateLog);
echo "Guardado Correctamente";
} catch (\PHPUnit\Framework\Exception $ex) {
echo "Error al guardar " . $ex->getMessage();
}
} else {
if ($this->enlacexml->update($datos["idEnlacexml"], $datos) == false) {
$errores = $this->enlacexml->errors();
foreach ($errores as $field => $error) {
echo $error . " ";
}
return;
} else {
$dateLog["description"] = lang("enlacexml.logUpdated") . json_encode($datos);
$dateLog["user"] = $userName;
$this->log->save($dateLog);
echo "Actualizado Correctamente";
return;
}
}
return;
}
/**
* Delete Enlacexml
* @param type $id
* @return type
*/
public function delete($id) {
$infoEnlacexml = $this->enlacexml->find($id);
helper('auth');
$userName = user()->username;
if (!$found = $this->enlacexml->delete($id)) {
return $this->failNotFound(lang('enlacexml.msg.msg_get_fail'));
}
$this->enlacexml->purgeDeleted();
$logData["description"] = lang("enlacexml.logDeleted") . json_encode($infoEnlacexml);
$logData["user"] = $userName;
$this->log->save($logData);
return $this->respondDeleted($found, lang('enlacexml.msg_delete'));
}
}
Creamos el archivo de la vista en App/Views/newSell.php con el siguiente código
<?= $this->include('load/toggle') ?>
<?= $this->include('julio101290\boilerplate\Views\load\select2') ?>
<?= $this->include('julio101290\boilerplate\Views\load\datatables') ?>
<?= $this->include('julio101290\boilerplate\Views\load\nestable') ?>
<!-- Extend from layout index -->
<?= $this->extend('julio101290\boilerplate\Views\layout\index') ?>
<!-- Section content -->
<?= $this->section('content') ?>
<?= $this->include('modulesSells/dataHeadSells') ?>
<?= $this->include('modulesSells/productosModalSells') ?>
<?= $this->include('modulesSells/modalPayment') ?>
<?= $this->include('modulesSells/moreInfoRow') ?>
<?= $this->include('modulesProducts/modalCaptureProducts') ?>
<?= $this->include('modulesCustumers/modalCaptureCustumers') ?>
<?= $this->include('modulesChoferes/modalCaptureChoferes') ?>
<?= $this->include('modulesVehiculos/modalCaptureVehiculos') ?>
<?= $this->endSection() ?>
Creamos el archivo para el encabezado de la venta App/Views/modulesSells/dataHeadSells.php con el siguiente código
<div class="row">
<div class="col-12">
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">Encabezado</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse">
<i class="fas fa-minus"></i>
</button>
</div>
</div>
<div class="card-body">
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="generales-tab" data-toggle="tab" data-target="#generales" type="button" role="tab" aria-controls="generales" aria-selected="true">Generales</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="profile-tab" data-toggle="tab" data-target="#otrosDatos" type="button" role="tab" aria-controls="otrosDatos" aria-selected="false">Otros
Datos</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="profile-tab" data-toggle="tab" data-target="#datosExtraVehiculo" type="button" role="tab" aria-controls="datosExtraVehiculo" aria-selected="false">
Datos Extra Vehiculo
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="profile-tab" data-toggle="tab" data-target="#facturacionMX" type="button" role="tab" aria-controls="facturacionMX" aria-selected="false">
Facturación MX
</button>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="generales" role="tabpanel" aria-labelledby="generales">
<?= $this->include('modulesSells/generalSells') ?>
</div>
<div class="tab-pane fade" id="otrosDatos" role="tabpanel" aria-labelledby="otrosDatos">
<?= $this->include('modulesSells/otrosDatos') ?>
</div>
<div class="tab-pane fade" id="datosExtraVehiculo" role="tabpanel" aria-labelledby="datosExtraVehiculo">
<?= $this->include('modulesSells/datosExtrasVehiculos') ?>
</div>
<div class="tab-pane fade" id="facturacionMX" role="tabpanel" aria-labelledby="otrosDatos">
<?= $this->include('modulesSells/facturacionMX') ?>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="card card-default">
<div class="card-header">
<h3 class="card-title">Detalle de la venta</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse">
<i class="fas fa-minus"></i>
</button>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-12">
<div class="box-body">
<div class="box" style="overflow-y: scroll; height:250px;">
<div class="row">
<!--=====================================
ENCABEZADO
======================================-->
<div class="col-1"> # </div>
<div class="col-1"> Codigo </div>
<div class="col-7"> Descripción </div>
<div class="col-1">Cantidad </div>
<div class="col-1">Precio </div>
<div class="col-1">Total </div>
</div>
<hr class="hr" />
<!--=====================================
ENTRADA PARA AGREGAR PRODUCTO
======================================-->
<div class="rowProducts">
<?php
if (isset($listProducts)) {
$list = "";
foreach ($listProducts as $key => $value) {
if (!isset($value["porcentIVARetenido"])) {
$value["porcentIVARetenido"] = "0.00";
}
if (!isset($value["IVARetenido"])) {
$value["IVARetenido"] = "0.00";
}
if (!isset($value["porcentISRRetenido"])) {
$value["porcentISRRetenido"] = "0.00";
}
if (!isset($value["ISRRetenido"])) {
$value["ISRRetenido"] = "0.00";
}
if (!isset($value["claveProductoSAT"])) {
$value["claveProductoSAT"] = "";
}
if (!isset($value["claveUnidadSAT"])) {
$value["claveUnidadSAT"] = "";
}
if (!isset($value["unidad"])) {
$value["unidad"] = "";
}
if (!isset($value["lote"])) {
$value["lote"] = "";
}
if (!isset($value["idAlmacen"])) {
$value["idAlmacen"] = "";
}
$list .= <<<EOF
<div class="form-group row nuevoProduct"><div class="col-1"> <button type="button" class="btn btn-danger quitProduct"><span class="far fa-trash-alt"></button>
<button type="button" data-toggle="modal" data-target="#modelMoreInfoRow" class="btn btn-primary btnInfo" ><span class="fa fa-fw fa-pencil-alt"></span></button>
</div>
<div class="col-1"> <input type="text" id="codeProduct" class="form-control codeProduct" name="codeProduct" value="$value[codeProduct]" required="">
<input type="hidden" id="claveProductoSATR" class="form-control claveProductoSATR" name="claveProductoSATR" value="$value[claveProductoSAT]" required="">
<input type="hidden" id="claveUnidadSatR" class="form-control claveUnidadSatR" name="claveUnidadSatR" value="$value[claveUnidadSAT]" required="">
<input type="hidden" id="unidad" class="form-control unidad" name="unidad" value="$value[unidad]" required="">
<input type="hidden" id="lote" class="form-control lote" name="lote" value="$value[lote]" required="">
<input type="hidden" id="idAlmacen" class="form-control idAlmacen" name="idAlmacen" value="$value[idAlmacen]" required="">
</div>
<div class="col-7"> <input type="text" id="description" class="form-control description" idproducto="$value[idProduct]" name="description" value="$value[description]" required=""> </div>
<div class="col-1"> <input type="number" id="cant" class="form-control cant" name="cant" value="$value[cant]" required="">
<input type="hidden" id="porcentIVARetenido" class="form-control porcentIVARetenido" name="porcentIVARetenido" value="$value[porcentIVARetenido]" required="">
<input type="hidden" id="porcentISRRetenido" class="form-control porcentISRRetenido" name="porcentISRRetenido" value="$value[porcentISRRetenido]" required="">
<input type="hidden" id="porcentTax" class="form-control porcentTax" name="porcentTax" value="$value[porcentTax]" required=""></div>
<div class="col-1"> <input type="number" id="price" class="form-control price" name="price" value="$value[price]" required="">
<input type="hidden" id="IVARetenido" class="form-control IVARetenido" name="IVARetenido" value="$value[IVARetenido]" required="">
<input type="hidden" id="ISRRetenido" class="form-control ISRRetenido" name="ISRRetenido" value="$value[ISRRetenido]" required="">
<input type="hidden" id="tax" class="form-control tax" name="tax" value="$value[tax]" required=""> </div>
<div class="col-1"> <input readonly="" type="number" id="total" class="form-control total" name="total" value="$value[total]" required="">
<input type="hidden" id="neto" class="form-control neto" name="neto" value="$value[neto]" required="">
</div></div>
EOF;
}
echo $list;
}
?>
</div>
<input type="hidden" id="listProducts" name="listProducts" value="[]">
<!--=====================================
BOTÓN PARA AGREGAR PRODUCTO
======================================-->
<hr>
</div>
</div>
<div class="box-footer" style="
text-align: right;
">
<div class="row form-group">
<div class="col-7">
</div>
<div class="col-3" style="
vertical-align: middle;
">
<label style="vertical-align: sub;margin-bottom: 0px;">Sub Total:</label>
</div>
<div class="col-2">
<input readonly="" type="text" id="subTotal" class="form-control subTotal" name="subTotal" value="<?= $subTotal ?>" style="
text-align: right;
">
</div>
</div>
<div class="row form-group">
<div class="col-7">
</div>
<div class="col-3" style="
vertical-align: middle;
">
<label style="
vertical-align: sub;
">Impuesto:</label>
</div>
<div class="col-2">
<input readonly="" type="text" id="totalImpuesto" class="form-control totalImpuesto" name="totalImpuesto" value="<?= $taxes ?>" style="
text-align: right;
">
</div>
</div>
<div class="row form-group grupoTotalRetencionIVA" hidden>
<div class="col-7">
</div>
<div class="col-3" style="
vertical-align: middle;
">
<label style="
vertical-align: sub;
">Retencion IVA:</label>
</div>
<div class="col-2">
<input readonly="" type="text" id="totalRetencionIVA" class="form-control totalRetencionIVA" name="totalRetencionIVA" value="<?= $IVARetenido ?>" style="
text-align: right;
">
</div>
</div>
<div class="row form-group grupoTotalRetencionISR" hidden>
<div class="col-7">
</div>
<div class="col-3" style="
vertical-align: middle;
">
<label style="
vertical-align: sub;
">Retencion ISR:</label>
</div>
<div class="col-2">
<input readonly="" type="text" id="totalRetencionISR" class="form-control totalRetencionISR" name="totalRetencionISR" value="<?= $ISRRetenido ?>" style="
text-align: right;
">
</div>
</div>
<div class="row form-group">
<div class="col-7">
</div>
<div class="col-3" style="
vertical-align: middle;
">
<label style="
vertical-align: sub;
">Total:</label>
</div>
<div class="col-2">
<input readonly="" type="text" id="granTotal" class="form-control granTotal" name="granTotal" value="<?= $total ?>" style="
text-align: right;
">
</div>
</div>
<button type="button" class="btn btn-primary pull-right btnSaveSells" data-toggle="modal">
<i class="fa far fa-save"> </i>Guardar</button>
<button type="button" class="btn bg-maroon btnPrint" data-toggle="modal" required="" data-placement="top" title="Imprimir">
<i class="fa fa-print"> </i> Guardar, Imprimir y cerrar
</button>
<button type="button" class="btn bg-maroon btnTimbrar" data-toggle="modal" required="" data-placement="top" title="Timbrar">
<i class="fas fa-qrcode"> </i> Timbrar
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?= $this->section('js') ?>
<script>
$("#metodoPagoVenta").select2();
$("#usoCFDIVenta").select2();
$("#formaPagoVenta").select2();
$("#regimenFiscalReceptor").select2();
/**
* Obtiene el ultimo folio por almacen
*/
$("#idEmpresaSells").on("change", function () {
var idEmpresa = $(this).val();
var idSucursal = $("#idSucursal").val();
var datos = new FormData();
datos.append("idEmpresa", idEmpresa);
// TRAE ULTIMO FOLIO
$.ajax({
url: "<?= base_url('admin/sells/getLastCode') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function (respuesta) {
console.log(respuesta);
$("#codeSell").val(respuesta["folio"]);
}
});
//TRAE DATOS EMPRESA
$.ajax({
url: "<?= base_url('admin/empresas/obtenerEmpresa') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function (respuesta) {
console.log(respuesta);
if (respuesta["facturacionRD"] == "on") {
$(".comprobantesRD").removeAttr("hidden");
} else {
$(".comprobantesRD").attr("hidden", true);
}
}
});
});
$("#idSucursal").on("change", function () {
var idEmpresa = $("#idEmpresaSells").val();
var idSucursal = $(this).val();
console.log("idSucursal", idSucursal);
var datos = new FormData();
datos.append("idEmpresa", idEmpresa);
datos.append("idSucursal", idSucursal);
// TRAE ULTIMO FOLIO
$.ajax({
url: "<?= base_url('admin/sells/getLastCode') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function (respuesta) {
console.log(respuesta);
$("#codeSell").val(respuesta["folio"]);
}
});
});
$(document).on('click', '#btnSaveChoferes', function (e) {
var idChoferes = $("#idChoferes").val();
var idEmpresa = $("#idEmpresaChoferes").val();
var nombre = $("#nombre").val();
var Apellido = $("#Apellido").val();
if (idEmpresa == 0 || idEmpresa == null) {
Toast.fire({
icon: 'error',
title: "Tiene que seleccionar la empresa"
});
return;
}
$("#btnSaveChoferes").attr("disabled", true);
var datos = new FormData();
datos.append("idChoferes", idChoferes);
datos.append("idEmpresa", idEmpresa);
datos.append("nombre", nombre);
datos.append("Apellido", Apellido);
$.ajax({
url: "<?= base_url('admin/choferes/save') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
success: function (respuesta) {
if (respuesta.match(/Correctamente.*/)) {
Toast.fire({
icon: 'success',
title: "Guardado Correctamente"
});
tableChoferes.ajax.reload();
$("#btnSaveChoferes").removeAttr("disabled");
$('#modalAddChoferes').modal('hide');
} else {
Toast.fire({
icon: 'error',
title: respuesta
});
$("#btnSaveChoferes").removeAttr("disabled");
}
}
}
)
});
/**
* Obtiene el ultimo folio por almacen
*/
$("#idEmpresaSells").on("change", function () {
var idEmpresa = $(this).val();
var idSucursal = $("#idSucursal").val();
var datos = new FormData();
datos.append("idEmpresa", idEmpresa);
datos.append("idSucursal", idSucursal);
// TRAE ULTIMO FOLIO
$.ajax({
url: "<?= base_url('admin/sells/getLastCode') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function (respuesta) {
console.log(respuesta);
$("#codeSell").val(respuesta["folio"]);
}
});
$("#idSucursal").select2({
ajax: {
url: "<?= site_url('admin/sucursales/getSucursalesAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresaSells').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
//TRAE DATOS EMPRESA
$.ajax({
url: "<?= base_url('admin/empresas/obtenerEmpresa') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function (respuesta) {
console.log(respuesta);
if (respuesta["facturacionRD"] == "on") {
$(".comprobantesRD").removeAttr("hidden");
} else {
$(".comprobantesRD").attr("hidden", true);
}
}
});
});
/**
* Obtiene el ultimo folio por almacen
*/
$("#tipoComprobanteRD").on("change", function () {
var idComprobantes_rd = $(this).val();
var datos = new FormData();
datos.append("idComprobantes_rd", idComprobantes_rd);
// TRAE ULTIMO FOLIO
$.ajax({
url: "<?= base_url('admin/comprobantes_rd/getComprobantes_rd') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function (respuesta) {
console.log(respuesta);
$("#folioComprobanteRD").val(respuesta["folioActual"]);
}
});
});
$("#idEmpresaSells").select2();
// Initialize select2 storages
$("#custumerSell").select2({
ajax: {
url: "<?= site_url('admin/custumers/getCustumersAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresaSells').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
// Initialize select2 storages
$("#idSucursal").select2({
ajax: {
url: "<?= site_url('admin/sucursales/getSucursalAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresaSells').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
/**
* Get data Custumer on change
*/
$("#custumerSell").on("change", function () {
var idCustumer = $(this).val();
var datos = new FormData();
datos.append("idCustumers", idCustumer);
// TRAE ULTIMO FOLIO
$.ajax({
url: "<?= base_url('admin/custumers/getCustumers') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function (respuesta) {
console.log(respuesta);
$("#RFCReceptor").val(respuesta["taxID"]);
$("#razonSocialReceptor").val(respuesta["razonSocial"]);
$("#codigoPostalReceptor").val(respuesta["codigoPostal"]);
$("#usoCFDIVenta").val(respuesta["usoCFDI"]);
$("#usoCFDIVenta").trigger("change");
$("#metodoPagoVenta").val(respuesta["metodoPago"]);
$("#metodoPagoVenta").trigger("change");
$("#formaPagoVenta").val(respuesta["formaPago"]);
$("#formaPagoVenta").trigger("change");
$("#regimenFiscalReceptor").val(respuesta["regimenFiscal"]);
$("#regimenFiscalReceptor").trigger("change");
}
});
});
$("#idEmpresaVehiculos").select2();
// Initialize select2 storages
$("#idChoferSell").select2({
ajax: {
url: "<?= site_url('admin/choferes/getChoferesAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresaSells').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
$("#idTipoVehiculo").select2({
ajax: {
url: "<?= site_url('admin/vehiculos/getTipoVehiculoAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresaVehiculos').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
// Initialize select2 storages
$("#idVehiculoSell").select2({
ajax: {
url: "<?= site_url('admin/vehiculos/getVehiculossAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresaSells').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
/**
* Get data Custumer on change
*/
$("#idVehiculoSell").on("change", function () {
var idVehiculo = $(this).val();
var datos = new FormData();
datos.append("idVehiculos", idVehiculo);
// TRAE ULTIMO FOLIO
$.ajax({
url: "<?= base_url('admin/vehiculos/getVehiculos') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function (respuesta) {
console.log(respuesta);
$("#tipoVehiculo").val(respuesta["descripcionTipo"]);
}
});
});
$(document).on('click', '#btnSaveVehiculos', function (e) {
var idVehiculos = $("#idVehiculos").val();
var idEmpresa = $("#idEmpresaVehiculos").val();
var idTipoVehiculo = $("#idTipoVehiculo").val();
var descripcion = $("#descripcion").val();
var placas = $("#placas").val();
if (idEmpresa == 0 || idEmpresa == null) {
Toast.fire({
icon: 'error',
title: "Tiene que seleccionar la empresa"
});
return;
}
if (idTipoVehiculo == 0 || idTipoVehiculo == null) {
Toast.fire({
icon: 'error',
title: "Tiene que seleccionar el tipo de vehiculo"
});
return;
}
$("#btnSaveVehiculos").attr("disabled", true);
var datos = new FormData();
datos.append("idVehiculos", idVehiculos);
datos.append("idEmpresa", idEmpresa);
datos.append("idTipoVehiculo", idTipoVehiculo);
datos.append("descripcion", descripcion);
datos.append("placas", placas);
$.ajax({
url: "<?= base_url('admin/vehiculos/save') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
success: function (respuesta) {
if (respuesta.match(/Correctamente.*/)) {
Toast.fire({
icon: 'success',
title: "Guardado Correctamente"
});
tableVehiculos.ajax.reload();
$("#btnSaveVehiculos").removeAttr("disabled");
$('#modalAddVehiculos').modal('hide');
} else {
Toast.fire({
icon: 'error',
title: respuesta
});
$("#btnSaveVehiculos").removeAttr("disabled");
}
}
}
)
});
// Initialize select2 storages
$("#tipoComprobanteRD").select2({
ajax: {
url: "<?= site_url('admin/comprobantes_rd/getTiposComprobanteAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresaSells').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
$(".btnSavePayment").on("click", function () {
var titulo = $("#titulo").val();
listProducts();
if (titulo == "Editar Cotizacion") {
saveSell();
} else {
$("#modalPayment").modal("toggle");
saveSell();
}
});
/**
* Save Quote
*/
$(".btnSaveSells").on("click", function () {
listProducts();
var titulo = $("#titulo").val();
if (titulo == "Editar Cotizacion") {
saveSell();
} else {
$("#modalPayment").modal("toggle");
}
});
function timbrarVenta() {
var UUID = $("#uuid").val();
$(".btnTimbrar").attr("disabled", true);
$.ajax({
url: "<?= base_url('admin/facturar/') ?>" + UUID,
method: "GET",
cache: false,
contentType: false,
processData: false,
//dataType:"json",
success: function (respuesta) {
if (respuesta.match(/success.*/)) {
Toast.fire({
icon: 'success',
title: "Timbrada Correctamente"
});
$(".btnTimbrar").removeAttr("disabled");
window.open("<?= base_url('admin/xml/generarPDFDesdeVenta') ?>" + "/" + UUID, "_blank");
return true;
} else {
Toast.fire({
icon: 'error',
title: respuesta
});
$(".btnTimbrar").removeAttr("disabled");
return false;
}
}
}
)
return true;
}
function saveSell() {
var UUID = $("#uuid").val();
var folio = $("#folio").val();
var idQuote = $("#idQuote").val();
var idEmpresa = $("#idEmpresaSells").val();
var custumerSell = $("#custumerSell").val();
var date = $("#date").val();
var dateVen = $("#dateVen").val()
var idUser = $("#idUser").val();
var generalObservations = $("#obsevations").val();
var listProducts = $("#listProducts").val();
var quoteTo = $("#quoteTo").val();
var delivaryTime = $("#delivaryTime").val();
var subTotal = $("#subTotal").val();
var taxes = $("#totalImpuesto").val();
var IVARetenido = $("#totalRetencionIVA").val();
var ISRRetenido = $("#totalRetencionISR").val();
var total = $("#granTotal").val();
var datePayment = $("#datePayment").val();
var metodoPago = $("#metodoPago").val();
var pago = $("#pago").val();
var cambio = $("#cambio").val();
var tipoComprobanteRD = $("#tipoComprobanteRD").val();
var folioComprobanteRD = $("#folioComprobanteRD").val();
var RFCReceptor = $("#RFCReceptor").val();
var usoCFDIVenta = $("#usoCFDIVenta").val();
var metodoPagoVenta = $("#metodoPagoVenta").val();
var formaPagoVenta = $("#formaPagoVenta").val();
var razonSocialReceptor = $("#razonSocialReceptor").val();
var codigoPostalReceptor = $("#codigoPostalReceptor").val();
var regimenFiscalReceptor = $("#regimenFiscalReceptor").val();
var idVehiculo = $("#idVehiculoSell").val();
var idChofer = $("#idChoferSell").val();
var tipoVehiculo = $("#tipoVehiculo").val();
var idSucursal = $("#idSucursal").val();
var ajaxGuardarConsulta = "ajaxGuardarConsulta";
/**
* Validaciones
*
*/
if (idEmpresa == 0 || idEmpresa == "") {
Toast.fire({
icon: 'error',
title: "Tiene que seleccionar la empresa"
});
return false;
}
if (custumerSell == 0 || custumerSell == "") {
Toast.fire({
icon: 'error',
title: "Tiene que seleccionar un cliente"
});
return false;
}
if (idSucursal == 0 || idSucursal == "") {
Toast.fire({
icon: 'error',
title: "Tiene que seleccionar una sucursal"
});
return false;
}
if (listProducts == "[]") {
Toast.fire({
icon: 'error',
title: "Tiene que agregar al menos un producto"
});
return false;
}
$(".btnSaveSells").attr("disabled", true);
var datos = new FormData();
datos.append("idCustumer", custumerSell);
datos.append("idEmpresa", idEmpresa);
datos.append("idQuote", idQuote);
datos.append("folio", folio);
datos.append("date", date);
datos.append("idUser", idUser);
datos.append("listProducts", listProducts);
datos.append("generalObservations", generalObservations);
datos.append("dateVen", dateVen);
datos.append("quoteTo", quoteTo);
datos.append("delivaryTime", delivaryTime);
datos.append("subTotal", subTotal);
datos.append("taxes", taxes);
datos.append("IVARetenido", IVARetenido);
datos.append("ISRRetenido", ISRRetenido);
datos.append("total", total);
datos.append("importPayment", pago);
datos.append("importBack", cambio);
datos.append("datePayment", datePayment);
datos.append("metodoPago", metodoPago);
datos.append("tipoComprobanteRD", tipoComprobanteRD);
datos.append("folioComprobanteRD", folioComprobanteRD);
datos.append("RFCReceptor", RFCReceptor);
datos.append("usoCFDI", usoCFDIVenta);
datos.append("metodoPago", metodoPagoVenta);
datos.append("formaPago", formaPagoVenta);
datos.append("razonSocialReceptor", razonSocialReceptor);
datos.append("codigoPostalReceptor", codigoPostalReceptor);
datos.append("regimenFiscalReceptor", regimenFiscalReceptor);
datos.append("idVehiculo", idVehiculo);
datos.append("idChofer", idChofer);
datos.append("tipoVehiculo", tipoVehiculo);
datos.append("idSucursal", idSucursal);
datos.append("UUID", UUID);
$.ajax({
url: "<?= base_url('admin/sells/save') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
//dataType:"json",
success: function (respuesta) {
if (respuesta.match(/Correctamente.*/)) {
Toast.fire({
icon: 'success',
title: "Guardado Correctamente"
});
$(".btnSaveSells").removeAttr("disabled");
return true;
} else {
Toast.fire({
icon: 'error',
title: respuesta
});
$(".btnSaveSells").removeAttr("disabled");
return false;
}
}
}
)
return true;
}
function listProducts() {
var listProducts = [];
var description = $(".description");
var codeProduct = $(".codeProduct");
var cant = $(".cant");
var price = $(".price");
var total = $(".total");
var porcentTax = $(".porcentTax");
var tax = $(".tax");
var IVARetenidoRenglon = $(".IVARetenido");
var porcentIVARetenido = $(".porcentIVARetenido");
var porcentISRRetenido = $(".porcentISRRetenido");
var ISRRetenidoRenglon = $(".ISRRetenido");
var neto = $(".neto");
var unidad = $(".unidad");
var lote = $(".lote");
var idAlmacen = $(".idAlmacen");
var claveProductoSATR = $(".claveProductoSATR");
var claveUnidadSatR = $(".claveUnidadSatR");
var subTotal = 0;
var impuesto = 0;
var netoTotal = 0;
var IVARetenido = 0;
var ISRRetenido = 0;
for (var i = 0; i < description.length; i++) {
listProducts.push({
"idProduct": $(description[i]).attr("idProducto"),
"description": $(description[i]).val(),
"codeProduct": $(codeProduct[i]).val(),
"cant": $(cant[i]).val(),
"price": $(price[i]).val(),
"porcentTax": $(porcentTax[i]).val(),
"tax": $(tax[i]).val(),
"porcentIVARetenido": $(porcentIVARetenido[i]).val(),
"porcentISRRetenido": $(porcentISRRetenido[i]).val(),
"IVARetenido": $(IVARetenidoRenglon[i]).val(),
"ISRRetenido": $(ISRRetenidoRenglon[i]).val(),
"claveProductoSAT": $(claveProductoSATR[i]).val(),
"claveUnidadSAT": $(claveUnidadSatR[i]).val(),
"lote": $(lote[i]).val(),
"idAlmacen": $(idAlmacen[i]).val(),
"neto": $(neto[i]).val(),
"unidad": $(unidad[i]).val(),
"total": $(total[i]).val()
});
subTotal = Number(Number(subTotal) + Number($(total[i]).val())).toFixed(2);
impuesto = Number(Number(impuesto) + Number($(tax[i]).val())).toFixed(2);
IVARetenido = Number(Number(IVARetenido) + Number($(IVARetenidoRenglon[i]).val())).toFixed(2);
ISRRetenido = Number(Number(ISRRetenido) + Number($(ISRRetenidoRenglon[i]).val())).toFixed(2);
netoTotal = Number(Number(netoTotal) + Number($(neto[i]).val())).toFixed(2);
}
$("#subTotal").val(subTotal);
$("#totalImpuesto").val(impuesto);
$("#granTotal").val(netoTotal);
$("#totalRetencionIVA").val(IVARetenido);
$("#totalRetencionISR").val(ISRRetenido);
//Asignamos el JSON en el input
$("#listProducts").val(JSON.stringify(listProducts));
}
/*=============================================
IMPRIMIR CONSULTA
=============================================*/
$(".btnPrint").on("click", function () {
var saved = saveSell();
var uuid = $("#uuid").val();
if (saved == true) {
var uuid = $("#uuid").val();
window.open("<?= base_url('admin/sells/report') ?>" + "/" + uuid, "_blank");
window.location = "<?= base_url('admin/sells') ?>";
}
})
$(".btnTimbrar").on("click", function () {
timbrarVenta();
});
//CARGA CONSULTAS ANTERIORES
$(".btnAddArticle").on("click", function () {
cargaProductos();
});
document.addEventListener("keydown", function (event) {
console.log(event.code);
if (event.altKey && event.code === "KeyA") {
cargaProductos();
$("#modalAddbtnAddArticle").modal('show');
event.preventDefault();
}
});
function cargaProductos() {
var empresa = $("#idEmpresaSells").val();
if (empresa == "") {
empresa = 0;
}
console.log("empresa:", empresa);
tableProducts.ajax.url(`<?= base_url('admin/products/getAllProducts') ?>/` + empresa).load();
}
$("#idSucursal").select2();
<?php
if ($folioComprobanteRD > 0) {
echo '$(".comprobantesRD").removeAttr("hidden")';
}
echo '$("#usoCFDIVenta").val("' . $usoCFDIReceptor . '"); ';
echo '$("#usoCFDIVenta").trigger("change"); ';
echo '$("#metodoPagoVenta").val("' . $metodoPagoReceptor . '"); ';
echo '$("#metodoPagoVenta").trigger("change"); ';
echo '$("#formaPagoVenta").val("' . $formaPagoReceptor . '"); ';
echo '$("#formaPagoVenta").trigger("change"); ';
echo '$("#regimenFiscalReceptor").val("' . $regimenFiscalReceptor . '"); ';
echo '$("#regimenFiscalReceptor").trigger("change"); ';
?>
</script>
<?= $this->endSection() ?>
Agregamos la vista para el modal de los productos App/Views/modulesSells/productosModalSells.php con el siguiente código
<!-- Modal Pacientes -->
<div class="modal fade" id="modalAddbtnAddArticle" tabindex="-1" role="dialog" aria-labelledby="modalAddbtnAddArticle" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Seleccione Articulo</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table id="table-products" class="table table-striped table-hover va-middle tableProducts">
<thead>
<tr>
<th>#</th>
<th>Descripcion</th>
<th>Lote</th>
<th>Almacen</th>
<th>Stock</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">
<?= lang('boilerplate.global.close') ?>
</button>
</div>
</div>
</div>
</div>
<?= $this->section('js') ?>
<script>
var tableProducts = $('#table-products').DataTable({
processing: true,
serverSide: true,
autoWidth: false,
order: [
[1, 'asc']
],
ajax: {
url: '<?= base_url('admin/products/getAllProducts') ?>/0',
method: 'GET',
dataType: "json"
},
columnDefs: [{
orderable: false,
targets: [5],
searchable: false,
targets: [5]
}],
columns: [{
'data': 'id'
},
{
'data': 'description'
},
{
'data': 'lote'
},
{
'data': 'almacen'
},
{
'data': 'stock'
},
{
"data": function (data) {
return `<td class="text-right py-0 align-middle">
<div class="btn-group btn-group-sm">
<button class="btn bg-blue btnAddProduct" idAlmacen="${data.idAlmacen}" lote="${data.lote}" data-id="${data.id}" unidad="${data.unidad}" claveProductoSAT="${data.claveProductoSAT}" unidadSAT="${data.unidadSAT}" porcentIVARetenido="${data.porcentIVARetenido}" porcentISRRetenido="${data.porcentISRRetenido}" porcentTax="${data.porcentTax}" code="${data.code}" price = "${data.salePrice}" description = "${data.description}"><i class="fas fa-plus"></i></button>
</div>
</td>`
}
}
]
});
/**
* Evento al hacer click al boton btnAgregarDiagnostico
*/
$("#table-products").on("click", ".btnAddProduct", function () {
var idProduct = $(this).attr("data-id");
var description = $(this).attr("description");
var codeProduct = $(this).attr("code");
var salePrice = $(this).attr("price");
var porcentTax = $(this).attr("porcentTax");
var porcentIVARetenido = $(this).attr("porcentIVARetenido");
var porcentISRRetenido = $(this).attr("porcentISRRetenido");
var claveUnidadSAT = $(this).attr("unidadSAT");
var unidad = $(this).attr("unidad");
var claveProductoSAT = $(this).attr("claveProductoSAT");
var lote = $(this).attr("lote");
var idAlmacen = $(this).attr("idAlmacen");
if (porcentTax > 0) {
var tax = ((porcentTax * 0.01)) * salePrice;
} else {
var tax = 0;
}
if (porcentIVARetenido > 0) {
var IVARetenido = ((porcentIVARetenido * 0.01)) * salePrice;
$(".grupoTotalRetencionIVA").removeAttr("hidden");
} else {
var IVARetenido = 0;
}
if (porcentISRRetenido > 0) {
var ISRRetenido = ((porcentISRRetenido * 0.01)) * salePrice;
$(".grupoTotalRetencionISR").removeAttr("hidden");
} else {
var ISRRetenido = 0;
}
var neto = (((porcentTax * 0.01) + 1) * salePrice) - (IVARetenido + ISRRetenido);
/**
* Agregando registros
*/
var renglon = "<div class=\"form-group row nuevoProduct\">";
renglon = renglon + "<div class =\"col-1\"> <button type=\"button\" class=\"btn btn-danger quitProduct\" ><span class=\"far fa-trash-alt\"></span></button> ";
renglon = renglon + " <button type=\"button\" data-toggle=\"modal\" data-target=\"#modelMoreInfoRow\" class=\"btn btn-primary btnInfo\" ><span class=\"fa fa-fw fa-pencil-alt\"></span></button> </div>";
renglon = renglon + "<div class =\"col-1\"> <input type=\"hidden\" id=\"claveProductoSATR\" class=\"form-control claveProductoSATR\" name=\"claveProductoSATR\" value=\"" + claveProductoSAT + "\" required=\"\">";
renglon = renglon + "<input type=\"hidden\" id=\"lote\" class=\"form-control lote\" name=\"lote\" value=\"" + lote + "\" required=\"\">";
renglon = renglon + "<input type=\"hidden\" id=\"idAlmacen\" class=\"form-control idAlmacen\" name=\"idAlmacen\" value=\"" + idAlmacen + "\" required=\"\">";
renglon = renglon + "<input type=\"hidden\" id=\"claveUnidadSatR\" class=\"form-control claveUnidadSatR\" name=\"claveUnidadSatR\" value=\"" + claveUnidadSAT + "\" required=\"\">";
renglon = renglon + "<input type=\"hidden\" id=\"unidad\" class=\"form-control unidad\" name=\"unidad\" value=\"" + unidad + "\" required=\"\">";
renglon = renglon + "<input type=\"text\" id=\"codeProduct\" class=\"form-control codeProduct\" name=\"codeProduct\" value=\"" + codeProduct + "\" required=\"\"> </div>";
renglon = renglon + "<div class =\"col-7\"> <input type=\"text\" id=\"description\" class=\"form-control description\" idProducto =\"" + idProduct + "\" name=\"description\" value=\"" + description + "\" required=\"\"> </div>";
renglon = renglon + "<div class =\"col-1\"> <input type=\"number\" id=\"cant\" class=\"form-control cant\"name=\"cant\" value=\"1\" required=\"\"><input type=\"hidden\" id=\"porcentIVARetenido\" class=\"form-control porcentIVARetenido\"name=\"porcentIVARetenido\" value=\"" + porcentIVARetenido + "\" required=\"\"><input type=\"hidden\" id=\"porcentISRRetenido\" class=\"form-control porcentISRRetenido\"name=\"porcentISRRetenido\" value=\"" + porcentISRRetenido + "\" required=\"\"> <input type=\"hidden\" id=\"porcentTax\" class=\"form-control porcentTax\"name=\"porcentTax\" value=\"" + porcentTax + "\" required=\"\"></div>";
renglon = renglon + "<div class =\"col-1\"> <input type=\"number\" id=\"price\" class=\"form-control price\"name=\"price\" value=\"" + salePrice + "\" required=\"\"> <input type=\"hidden\" id=\"IVARetenido\" class=\"form-control IVARetenido\"name=\"IVARetenido\" value=\"" + IVARetenido + "\" required=\"\"><input type=\"hidden\" id=\"ISRRetenido\" class=\"form-control ISRRetenido\"name=\"ISRRetenido\" value=\"" + ISRRetenido + "\" required=\"\"> <input type=\"hidden\" id=\"tax\" class=\"form-control tax\"name=\"tax\" value=\"" + tax + "\" required=\"\"> </div>";
renglon = renglon + "<div class =\"col-1\"> <input readonly type=\"number\" id=\"total\" class=\"form-control total\" name=\"total\" value=\"" + salePrice + "\" required=\"\"> <input type=\"hidden\" id=\"neto\" class=\"form-control neto\" name=\"neto\" value=\"" + neto + "\" required=\"\"></div></div>";
$(".rowProducts").append(renglon);
listProducts();
});
var nombreDiv = "";
/**
* Eliminar Renglon Diagnostico
*/
$(".rowProducts").on("click", ".quitProduct", function () {
$(this).parent().parent().remove();
listProducts();
});
/**
* Mas datos Producto
*/
$(".rowProducts").on("click", ".btnInfo", function () {
nombreDiv = $(this);
var unidadSAT = $(this).parent().parent().find(".claveUnidadSatR").val();
var claveProductoSAT = $(this).parent().parent().find(".claveProductoSATR").val();
var unidad = $(this).parent().parent().find(".unidad").val();
var newOption = new Option(unidadSAT, unidadSAT, true, true);
$('#unidadSATRow').append(newOption).trigger('change');
$("#unidadSATRow").val(unidadSAT);
var newOptionClaveProducto = new Option(claveProductoSAT, claveProductoSAT, true, true);
$('#claveProductoSATRow').append(newOptionClaveProducto).trigger('change');
$("#claveProductoSATRow").val(claveProductoSAT);
$("#unidadProducto").val(unidad);
});
/**
* Eliminar Renglon Diagnostico
*/
$(".rowProducts").on("click", ".quitProduct", function () {
$(this).parent().parent().remove();
listProducts();
});
/**
* Cambia Cantidad
*/
$(".rowProducts").on("change", ".cant", function () {
var cant = Number($(this).val());
precio = $(this).parent().parent().find(".price").val();
total = Number(cant) * Number(precio);
porcIva = Number($(this).parent().parent().find(".porcentTax").val()) * 0.01;
porcIVARetenido = Number($(this).parent().parent().find(".porcentIVARetenido").val()) * 0.01;
porcISRRetenido = Number($(this).parent().parent().find(".porcentISRRetenido").val()) * 0.01;
impuesto = (porcIva) * Number(total);
IVARetenido = (porcIVARetenido) * Number(total);
ISRRetenido = (porcISRRetenido) * Number(total);
neto = ((porcIva + 1) * Number(total)) - (IVARetenido + ISRRetenido);
$(this).parent().parent().find(".total").val(total);
$(this).parent().parent().find(".neto").val(neto);
$(this).parent().parent().find(".tax").val(impuesto);
$(this).parent().parent().find(".IVARetenido").val(IVARetenido);
$(this).parent().parent().find(".ISRRetenido").val(ISRRetenido);
listProducts();
});
/**
* Cambia Cantidad
*/
$(".rowProducts").on("change", ".price", function () {
var precio = Number($(this).val());
cant = $(this).parent().parent().find(".cant").val();
total = Number(cant) * Number(precio);
porcIva = Number($(this).parent().parent().find(".porcentTax").val()) * 0.01;
porcIVARetenido = Number($(this).parent().parent().find(".porcentIVARetenido").val()) * 0.01;
porcISRRetenido = Number($(this).parent().parent().find(".porcentISRRetenido").val()) * 0.01;
IVARetenido = (porcIVARetenido) * Number(total);
ISRRetenido = (porcISRRetenido) * Number(total);
neto = ((porcIva + 1) * Number(total)) - (IVARetenido + ISRRetenido);
impuesto = (porcIva) * Number(total);
$(this).parent().parent().find(".total").val(total);
$(this).parent().parent().find(".neto").val(neto);
$(this).parent().parent().find(".tax").val(impuesto);
$(this).parent().parent().find(".IVARetenido").val(IVARetenido);
$(this).parent().parent().find(".ISRRetenido").val(ISRRetenido);
listProducts();
});
</script>
<?= $this->endSection() ?>
Creamos el archivo que contiene el modal del pago en App/Views/modulesSells/modalPayment.php con el siguiente código
<!-- Modal Vehicles -->
<div class="modal fade" id="modalPayment" tabindex="-1" role="dialog" aria-labelledby="modalPayment" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Total a Pagar</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form id="form-paciente" class="form-horizontal">
<div class="form-group row">
<label for="inputName" class="col-sm-2 col-form-label">Fecha Pago</label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="far fa-calendar-alt"></i></span>
</div>
<input type="date" name="datePayment" id="datePayment" class="form-control <?= session('error.datePayment') ? 'is-invalid' : '' ?>" value="<?php echo date('Y-m-d'); ?>" placeholder="datePayment" autocomplete="off">
</div>
</div>
</div>
<div class="form-group row">
<label for="inputName" class="col-sm-2 col-form-label">Método de Pago</label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-credit-card"></i></span>
</div>
<select name="metodoPago" id="metodoPago" class="form-control <?= session('error.uuidMail') ? 'is-invalid' : '' ?>" value="" placeholder="UUID Registro" autocomplete="off">
<option value="1"> Efectivo</option>
<option value="1"> Tarjeta</option>
<select>
</div>
</div>
</div>
<div class="form-group row">
<label for="inputName" class="col-sm-2 col-form-label">Pago</label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-dollar-sign"></i></span>
</div>
<input type="number" name="pago" id="pago" class="form-control <?= session('error.datePayment') ? 'is-invalid' : '' ?>" value="0.00" placeholder="datePayment" autocomplete="off">
</div>
</div>
</div>
<div class="form-group row">
<label for="tireType" class="col-sm-2 col-form-label">Cambio</label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-hand-holding"></i></span>
</div>
<input type="number" readonly="" name="cambio" id="cambio" class="form-control <?= session('error.folioVentaMail') ? 'is-invalid' : '' ?>" value="0.00" placeholder="" autocomplete="off">
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal"><?= lang('boilerplate.global.close') ?></button>
<button type="button" class="btn btn-primary btn-sm btnSavePayment" id="btnSavePayment">Guardar</button>
</div>
</div>
</div>
</div>
<?= $this->section('js') ?>
<script>
/*=============================================
CAMBIO EN EFECTIVO
=============================================*/
$("#pago").on("keyup", function () {
console.log("asdasd");
var efectivo = $(this).val();
var total = $("#granTotal").val();
var cambio = Number(efectivo) - Number(total);
if (Number(efectivo) < Number(total)) {
cambio = 0;
}
$("#cambio").val(cambio);
})
</script>
<?= $this->endSection() ?>
Creamos el archivo de la vista para ver mas información del renglón en App/Views/modulesSells/moreInfoRow.php con el siguiente código
<!-- Modal More Info -->
<div class="modal fade" id="modelMoreInfoRow" tabindex="-1" role="dialog" aria-labelledby="modelMoreInfoRow" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Información del Renglon</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form id="form-otrosDatosRenglon" class="form-horizontal">
<div class="form-group row">
<label for="unidadSATRow" class="col-sm-2 col-form-label">
Clave Unidad SAT
</label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
</div>
<select name="unidadSATRow" id="unidadSATRow" style="width: 90%;" class="form-control unidadSAT form-controlProducts">
<option value="0" selected>
Seleccione Clave De Unidad SAT
</option>
</select>
</div>
</div>
</div>
<div class="form-group row">
<label for="claveProductoSATRow" class="col-sm-2 col-form-label">
Clave Producto SAT
</label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
</div>
<select name="claveProductoSATRow" id="claveProductoSATRow" style="width: 90%;" class="form-control claveProductoSAT form-controlProducts">
<option value="0" selected>
Seleccione Clave de Producto SAT
</option>
</select>
</div>
</div>
</div>
<div class="form-group row">
<label for="claveProductoSATRow" class="col-sm-2 col-form-label">
Unidad Producto
</label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
</div>
<input name="unidadProducto" id="unidadProducto" class="form-control unidadProducto form-controlProducts">
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal"><?= lang('boilerplate.global.close') ?></button>
<button type="button" class="btn btn-primary btn-sm btnGuardarRenglon" id="btnGuardarRenglon" data-dismiss="modal">Guardar</button>
</div>
</div>
</div>
</div>
<?= $this->section('js') ?>
<script>
/*
* AL hacer click al editar
*/
$(document).on('click', '.btnGuardarRenglon', function (e) {
nombreDiv.parent().parent().find(".claveUnidadSatR").val($("#unidadSATRow").val());
nombreDiv.parent().parent().find(".claveProductoSATR").val($("#claveProductoSATRow").val());
nombreDiv.parent().parent().find(".unidad").val($("#unidadProducto").val());
listProducts();
});
/**
* Categorias por empresa
*/
$(".unidadSATRow").select2({
ajax: {
url: "<?= base_url('admin/products/getUnidadSATAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresa').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
/**
* Categorias por empresa
*/
$(".claveProductoSATRow").select2({
ajax: {
url: "<?= base_url('admin/products/getProductosSATAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresa').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
</script>
<?= $this->endSection() ?>
Creamos el archivo para ver la lista de las ventas
<?= $this->include('load/daterangapicker') ?>
<?= $this->include('load/toggle') ?>
<?= $this->include('julio101290\boilerplate\Views\load\datatables') ?>
<?= $this->include('julio101290\boilerplate\Views\load\select2') ?>
<!-- Extend from layout index -->
<?= $this->extend('julio101290\boilerplate\Views\layout\index') ?>
<!-- Section content -->
<?= $this->section('content') ?>
<?= $this->include('modulesSells/modaSendMail') ?>
<?= $this->include('modulesSells/paymentsList') ?>
<?= $this->include('modulesSells/modalPaymentList') ?>
<?= $this->include('modulesSells/listaFacturas') ?>
<?= $this->include('modulesSells/xmlList') ?>
<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
<div class="card-header">
<div class="float-left">
<div class="btn-group">
<div id="reportrange" style="background: #fff; cursor: pointer; padding: 5px 10px; border: 1px solid #ccc; width: 100%">
<i class="fa fa-calendar"></i>
<span></span> <i class="fa fa-caret-down"></i>
</div>
</div>
<div class="btn-group">
<div class="form-group">
<label for="idEmpresa">Empresa </label>
<select id='idEmpresa' name='idEmpresa' class="idEmpresa" style='width: 80%;'>
<?php
if (isset($idEmpresa)) {
echo " <option value='$idEmpresa'>$idEmpresa - $nombreEmpresa</option>";
} else {
echo " <option value='0'>Todas las empresas</option>";
foreach ($empresas as $key => $value) {
echo "<option value='$value[id]'>$value[id] - $value[nombre] </option> ";
}
}
?>
</select>
</div>
</div>
<div class="btn-group">
<div class="form-group">
<label for="idSucursal">Sucursal </label>
<select id='idSucursal' name='idSucursal' class="idSucursal" style='width: 100%;'>
<?php
echo " <option value='0'>Todas las Sucursales</option>";
if (isset($idSucursal)) {
echo " <option value='$idSucursal'>$idSucursal - $nombreSucursal</option>";
}
?>
</select>
</div>
</div>
<div class="btn-group">
<div class="form-group">
<label for="productos">Cliente </label>
<select id='clientes' name='clientes' class="clientes" style='width: 100%;'>
<?php
echo " <option value='0'>Todas los clientes</option>";
?>
</select>
</div>
</div>
<div class="btn-group">
<input type="checkbox" id="chkTodasLasVentas" name="chkTodasLasVentas" class="chkTodasLasVentas" data-width="250" data-height="40" checked data-toggle="toggle" data-on="Todas las ventas" data-off="Pendientes de Pago" data-onstyle="success" data-offstyle="danger">
</div>
</div>
<div class="float-right">
<div class="btn-group">
<a href="<?= base_url("admin/newSells") ?>" class="btn btn-primary btnAddCustumers" data-target="#modalAddCustumers"><i class="fa fa-plus"></i>
Nueva Venta
</a>
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table id="tableSells" class="table table-striped table-hover va-middle tableSells">
<thead>
<tr>
<th>#</th>
<th>
Folio
</th>
<th>
Cliente
</th>
<th>
Fecha
</th>
<th>
Fecha Vencimiento
</th>
<th>
SubTotal
</th>
<th>
Impuesto
</th>
<th>
Total
</th>
<th>
Pendiente
</th>
<th>
Tiempo Entrega
</th>
<th>
Creado
</th>
<th>
Modificado
</th>
<th>
Eliminado
</th>
<th>
Acciones
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- /.card -->
<?= $this->endSection() ?>
<?= $this->section('js') ?>
<script>
/**
* Cargamos la tabla
*/
var tableQuotes = $('#tableSells').DataTable({
processing: true,
serverSide: true,
responsive: true,
autoWidth: false,
order: [
[1, 'desc']
],
ajax: {
url: '<?= base_url('admin/sells') ?>',
method: 'GET',
dataType: "json"
},
columnDefs: [{
orderable: false,
targets: [13],
searchable: false,
targets: [13]
}],
columns: [{
'data': 'id'
},
{
'data': 'folio'
},
{
'data': 'nameCustumer'
},
{
'data': 'date'
},
{
'data': 'dateVen'
},
{
'data': 'subTotal'
},
{
'data': 'taxes'
},
{
'data': 'total'
},
{
'data': 'balance'
},
{
'data': 'delivaryTime'
},
{
'data': 'created_at'
},
{
'data': 'updated_at'
},
{
'data': 'deleted_at'
},
{
"data": function (data) {
var buttonPayment = "";
if (data.balance > 0) {
buttonPayment = `<button class="btn btn-success btnSetPayment" data-toggle="modal" balance ="${data.balance}" uuid="${data.UUID}" folio="${data.folio}" data-toggle="modal" data-target="#modalPayment" > <i class="fab fa-cc-visa"></i></button> `;
} else {
buttonPayment = `<button class="btn btn-success " uuid="${data.UUID}" folio="${data.folio}"> <i class="far fa-check-square"></i></button> `;
}
return `<td class="text-right py-0 align-middle">
<div class="btn-group btn-group-sm">
<a href="<?= base_url('admin/editSell') ?>/${data.UUID}" class="btn btn-primary btn-edit"><i class="fas fa-pencil-alt"></i></a>
<button class="btn btn-success btnSendMail" data-toggle="modal" correoCliente ="${data.correoCliente}" uuid="${data.UUID}" folio="${data.folio}" data-toggle="modal" data-target="#modalSendMail" > <i class=" fas fa-envelope"></i></button>
<button class="btn bg-warning btnImprimirVenta" uuid="${data.UUID}" ><i class="far fa-file-pdf"></i></button>
<button class="btn bg-maroon btnTimbrar" uuid="${data.UUID}" ><i class="fas fa-qrcode"></i></button>
<button class="btn btn-danger btn-delete" data-id="${data.id}"><i class="fas fa-trash"></i></button>
${buttonPayment}
<button class="btn bg-maroon btnPaymentsList" data-toggle="modal" uuid="${data.UUID}" data-toggle="modal" data-target="#modalPaymentsList" > <i class="fas fa-search"></i></button>
<button class="btn bg-success btnInvoiceList" data-toggle="modal" uuid="${data.UUID}" data-toggle="modal" data-target="#modalInvoiceList" > <i class="fas fa-search"></i></button>
<button class="btn bg-gray btnListXML" data-toggle="modal" uuid="${data.UUID}" data-toggle="modal" data-target="#modalListXML" > <i class="fas fa-list"></i></button>
</div>
</td>`
}
}
]
});
$("#idEmpresa").select2();
$("#idSucursal").select2({
ajax: {
url: "<?= site_url('admin/sucursales/getSucursalesAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresa').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
$("#productos").select2({
ajax: {
url: "<?= site_url('admin/products/getProductsAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresa').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
// Initialize select2 storages
$("#clientes").select2({
ajax: {
url: "<?= site_url('admin/custumers/getCustumersTodosAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
var idEmpresa = $('.idEmpresa').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash, // CSRF Token
idEmpresa: idEmpresa // search term
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
/**@abstract
*
* Al cambiar la el rango de fecha
*/
$("#chkTodasLasVentas").on("change", function () {
var datePicker = $('#reportrange').data('daterangepicker');
var desdeFecha = datePicker.startDate.format('YYYY-MM-DD');
var hastaFecha = datePicker.endDate.format('YYYY-MM-DD');
var idEmpresa = $("#idEmpresa").val();
var idSucursal = $("#idSucursal").val();
var idCliente = $("#clientes").val();
if ($(this).is(':checked')) {
todas = true;
} else {
todas = false;
}
tableQuotes.ajax.url(`<?= base_url('admin/sells') ?>/` + desdeFecha + '/' + hastaFecha + '/' + todas + '/' + idEmpresa + '/' + idSucursal + '/' + idCliente).load();
});
/*=============================================
Load Payment List
=============================================*/
$(".tableSells").on("click", '.btnPaymentsList', function () {
var uuid = $(this).attr("uuid");
console.log(uuid);
tableProducts.ajax.url(`<?= base_url('admin/payments/getPayments') ?>/` + uuid).load();
});
/*=============================================
Carga XML sin asignar
=============================================*/
$(".tableSells").on("click", '.btnListXML', function () {
var uuidSell = $(this).attr("uuid");
$("#idVentaSinAsignar").val(uuidSell);
tableListXML.ajax.url(`<?= base_url('admin/xml/xmlSinAsignar/I') ?>`).load();
});
/*=============================================
Load invouce List
=============================================*/
$(".tableSells").on("click", '.btnInvoiceList', function () {
var uuid = $(this).attr("uuid");
console.log(uuid);
tableInvoice.ajax.url(`<?= base_url('admin/xmlenlace/getXMLEnlazados') ?>/` + uuid).load();
});
/*=============================================
ENVIAR CORREO
=============================================*/
$(".tableSells").on("click", '.btnSendMail', function () {
var uuid = $(this).attr("uuid");
var folio = $(this).attr("folio");
var correo = $(this).attr("correocliente");
var newOption = new Option(correo, correo);
$('#correos').append(newOption).trigger('change');
$("#uuidMail").val(uuid);
$("#folioVentanMail").val(folio);
});
/*=============================================
ENVIAR CORREO
=============================================*/
$(".tableSells").on("click", '.btnTimbrar', function () {
var uuid = $(this).attr("uuid");
timbrarVenta(uuid);
});
/**
* Imprimir factura desde la lista de facturas
*/
$(".tableInvoice").on("click", '.btn-printInvoice', function () {
var uuid = $(this).attr("data-id");
window.open("<?= base_url('admin/xml/generarPDF') ?>" + "/" + uuid, "_blank");
});
/**
* Imprimir factura desde la lista de facturas
*/
$(".tableInvoice").on("click", '.btnDeleteEnlace', function () {
var idEnlace = $(this).attr("data-id");
Swal.fire({
title: '<?= lang('boilerplate.global.sweet.title') ?>',
text: "<?= lang('boilerplate.global.sweet.text') ?>",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '<?= lang('boilerplate.global.sweet.confirm_delete') ?>'
})
.then((result) => {
if (result.value) {
$.ajax({
url: `<?= base_url('admin/enlacexml/delete/') ?>/` + idEnlace,
method: 'GET',
}).done((data, textStatus, jqXHR) => {
Toast.fire({
icon: 'success',
title: jqXHR.statusText,
});
tableInvoice.ajax.reload();
}).fail((error) => {
Toast.fire({
icon: 'error',
title: error.responseJSON.messages.error,
});
})
}
})
});
function timbrarVenta(UUID) {
$(".btnTimbrar").attr("disabled", true);
$.ajax({
url: "<?= base_url('admin/facturar/') ?>" + UUID,
method: "GET",
cache: false,
contentType: false,
processData: false,
//dataType:"json",
success: function (respuesta) {
if (respuesta.match(/success.*/)) {
Toast.fire({
icon: 'success',
title: "Timbrada Correctamente"
});
$(".btnTimbrar").removeAttr("disabled");
window.open("<?= base_url('admin/xml/generarPDFDesdeVenta') ?>" + "/" + UUID, "_blank");
return true;
} else {
Toast.fire({
icon: 'error',
title: respuesta
});
$(".btnTimbrar").removeAttr("disabled");
return false;
}
}
}
)
return true;
}
/*=============================================
ENVIAR CORREO
=============================================*/
$(".tableSells").on("click", '.btnSetPayment', function () {
var uuid = $(this).attr("uuid");
var balance = $(this).attr("balance");
console.log("asd");
$("#uuidSellPayment").val(uuid);
$("#pago").val("0.00");
$("#granTotal").val(balance);
});
/*=============================================
IMPRIMIR VEnta
=============================================*/
$(".tableSells").on("click", '.btnImprimirVenta', function () {
var uuid = $(this).attr("uuid");
window.open("<?= base_url('admin/sells/report') ?>" + "/" + uuid, "_blank");
});
/*=============================================
ELIMINAR custumers
=============================================*/
$(".tableSells").on("click", ".btn-delete", function () {
var idSell = $(this).attr("data-id");
Swal.fire({
title: '<?= lang('boilerplate.global.sweet.title') ?>',
text: "<?= lang('boilerplate.global.sweet.text') ?>",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '<?= lang('boilerplate.global.sweet.confirm_delete') ?>'
})
.then((result) => {
if (result.value) {
$.ajax({
url: `<?= base_url('admin/sells') ?>/` + idSell,
method: 'DELETE',
}).done((data, textStatus, jqXHR) => {
Toast.fire({
icon: 'success',
title: jqXHR.statusText,
});
tableQuotes.ajax.reload();
}).fail((error) => {
Toast.fire({
icon: 'error',
title: error.responseJSON.messages.error,
});
})
}
})
})
$(function () {
var start = moment().subtract(29, 'days');
var end = moment();
var todas = true;
function cb(start, end) {
$('#reportrange span').html(start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY'));
if ($('#chkTodasLasVentas').is(':checked')) {
todas = true;
} else {
todas = false;
}
var desdeFecha = start.format('YYYY-MM-DD');
var hastaFecha = end.format('YYYY-MM-DD');
var idEmpresa = $("#idEmpresa").val();
var idSucursal = $("#idSucursal").val();
var idCliente = $("#clientes").val();
tableQuotes.ajax.url(`<?= base_url('admin/sells') ?>/` + desdeFecha + '/' + hastaFecha + '/' + todas + '/' + idEmpresa + '/' + idSucursal + '/' + idCliente).load();
}
$('#reportrange').daterangepicker({
startDate: start,
endDate: end,
ranges: {
'Hoy': [moment(), moment()],
'Ayer': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
'Ultimos 7 Dias': [moment().subtract(6, 'days'), moment()],
'Ultimos 30 Dias': [moment().subtract(29, 'days'), moment()],
'Este Mes': [moment().startOf('month'), moment().endOf('month')],
'Último Mes': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
'Todo': [moment().subtract(100, 'year').startOf('month'), moment().add(100, 'year').endOf('year')]
}
}, cb);
cb(start, end);
});
</script>
<?= $this->endSection() ?>
Metemos el modal para ver la lista de pagos de las ventas en App/Views/modulesSells/paymentsList.php con el siguiente código
<!-- Modal Pacientes -->
<div class="modal fade" id="modalPaymentsList" tabindex="-1" role="dialog" aria-labelledby="modalPaymentsList"
aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Lista de Pagos</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table id="table-payments" class="table table-striped table-hover va-middle tablePayments">
<thead>
<tr>
<th>#</th>
<th>Fecha</th>
<th>Importe Pagado</th>
<th>Importe Devuelto</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">
<?= lang('boilerplate.global.close') ?>
</button>
</div>
</div>
</div>
</div>
<?= $this->section('js') ?>
<script>
var tableProducts = $('#table-payments').DataTable({
processing: true,
serverSide: true,
autoWidth: false,
order: [[1, 'asc']],
ajax: {
url: '<?= base_url('admin/payments/getPayments') ?>/0',
method: 'GET',
dataType: "json"
},
columnDefs: [{
orderable: false,
targets: [2],
searchable: false,
targets: [2]
}],
columns: [{
'data': 'id'
},
{
'data': 'datePayment'
},
{
'data': 'importPayment'
},
{
'data': 'importBack'
},
{
"data": function (data) {
return `<td class="text-right py-0 align-middle">
<div class="btn-group btn-group-sm">
<button class="btn-danger btn-delete btnDeletePayment" data-id="${data.id}" ><i class="fas fa-trash"></i></button>
</div>
</td>`
}
}
]
});
/**
* Eliminar Renglon Diagnostico
*/
$("#table-payments").on("click", ".btnDeletePayment", function () {
var idPago = $(this).attr("data-id");
Swal.fire({
title: '<?= lang('boilerplate.global.sweet.title') ?>',
text: "<?= lang('boilerplate.global.sweet.text') ?>",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '<?= lang('boilerplate.global.sweet.confirm_delete') ?>'
})
.then((result) => {
if (result.value) {
$.ajax({
url: `<?= base_url('admin/payments/delete/') ?>/` + idPago,
method: 'GET',
}).done((data, textStatus, jqXHR) => {
Toast.fire({
icon: 'success',
title: jqXHR.statusText,
});
tableProducts.ajax.reload();
tableQuotes.ajax.reload();
}).fail((error) => {
Toast.fire({
icon: 'error',
title: error.responseJSON.messages.error,
});
})
}
})
})
</script>
<?= $this->endSection() ?>
Agregamos el modal para hacer pagos a la venta en App/Views/modulesSells/modalPaymentList.php con el siguiente código
<!-- Modal Vehicles -->
<div class="modal fade" id="modalPayment" class="modalPayment" tabindex="-1" role="dialog" aria-labelledby="modalPayment" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Total a Pagar</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form id="form-paciente" class="form-horizontal">
<div class="form-group row">
<label for="inputName" class="col-sm-2 col-form-label">Fecha Pago</label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="far fa-calendar-alt"></i></span>
</div>
<input type="date" name="datePayment" id="datePayment" class="form-control <?= session('error.datePayment') ? 'is-invalid' : '' ?>" value="<?php echo date('Y-m-d'); ?>" placeholder="datePayment" autocomplete="off">
</div>
</div>
</div>
<div class="form-group row">
<label for="inputName" class="col-sm-2 col-form-label">Método de Pago</label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-credit-card"></i></span>
</div>
<select name="metodoPago" id="metodoPago" class="form-control <?= session('error.uuidMail') ? 'is-invalid' : '' ?>" value="" placeholder="UUID Registro" autocomplete="off">
<option value="1"> Efectivo</option>
<option value="2"> Tarjeta</option>
<select>
</div>
</div>
</div>
<div class="form-group row">
<label for="inputName" class="col-sm-2 col-form-label">Pago</label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-dollar-sign"></i></span>
</div>
<input type="hidden" name="uuidSellPayment" id="uuidSellPayment" class="form-control <?= session('error.uuidSellPayment') ? 'is-invalid' : '' ?>" value="0.00" placeholder="uuidSellPayment" autocomplete="off">
<input type="hidden" name="granTotal" id="granTotal" class="form-control " value="0.00" autocomplete="off">
<input type="number" name="pago" id="pago" class="form-control <?= session('error.datePayment') ? 'is-invalid' : '' ?>" value="0.00" placeholder="datePayment" autocomplete="off">
</div>
</div>
</div>
<div class="form-group row">
<label for="tireType" class="col-sm-2 col-form-label">Cambio</label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-hand-holding"></i></span>
</div>
<input type="number" readonly="" name="cambio" id="cambio" class="form-control <?= session('error.folioVentaMail') ? 'is-invalid' : '' ?>" value="0.00" placeholder="" autocomplete="off">
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm btnCerrar" data-dismiss="modal"><?= lang('boilerplate.global.close') ?></button>
<button type="button" data-dismiss="modal" class="btn btn-primary btn-sm btnSavePayment" id="btnSavePayment" >Guardar</button>
</div>
</div>
</div>
</div>
<?= $this->section('js') ?>
<script>
/**
* Save Payment
*/
$(".btnSavePayment").on("click", function () {
savePayment();
});
function savePayment() {
var UUID = $("#uuidSellPayment").val();
var pago = $("#pago").val();
var cambio = $("#cambio").val();
var datePayment = $("#datePayment").val();
var metodoPago = $("#metodoPago").val();
$(".btnSavePayment").attr("disabled", true);
var datos = new FormData();
datos.append("UUID", UUID);
datos.append("importPayment", pago);
datos.append("importBack", cambio);
datos.append("datePayment", datePayment);
datos.append("metodoPago", metodoPago);
$.ajax({
url: "<?= base_url('admin/payments/save') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
//dataType:"json",
success: function (respuesta) {
if (respuesta.match(/Correctamente.*/)) {
Toast.fire({
icon: 'success',
title: "Guardado Correctamente"
});
$(".btnSavePayment").removeAttr("disabled");
tableQuotes.ajax.reload();
$(".btnCerrar").trigger("click");
} else {
Toast.fire({
icon: 'error',
title: respuesta
});
$(".btnSavePayment").removeAttr("disabled");
}
}
})
}
/*=============================================
CAMBIO EN EFECTIVO
=============================================*/
$("#pago").on("keyup", function () {
console.log("asdasd");
var efectivo = $(this).val();
var total = $("#granTotal").val();
var cambio = Number(efectivo) - Number(total);
if (Number(efectivo) < Number(total)) {
cambio = 0;
}
$("#cambio").val(cambio);
})
</script>
<?= $this->endSection() ?>
Creamos el archivo para listar las facturas enlazadas a la venta en App/Views/modulesSells/listaFacturas.php con el siguiente código
<!-- Modal Pacientes -->
<div class="modal fade" id="modalInvoiceList" tabindex="-1" role="dialog" aria-labelledby="modalPaymentsList"
aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Lista de facturas timbradas</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table id="table-invoice" class="table table-striped table-hover va-middle tableInvoice">
<thead>
<tr>
<th>#</th>
<th>UUID Timbre</th>
<th>Total</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">
<?= lang('boilerplate.global.close') ?>
</button>
</div>
</div>
</div>
</div>
<?= $this->section('js') ?>
<script>
var tableInvoice = $('#table-invoice').DataTable({
processing: true,
serverSide: true,
autoWidth: false,
order: [[1, 'asc']],
ajax: {
url: '<?= base_url('admin/xmlenlace/getXMLEnlazados') ?>/0',
method: 'GET',
dataType: "json"
},
columnDefs: [{
orderable: false,
targets: [2],
searchable: false,
targets: [2]
}],
columns: [{
'data': 'id'
},
{
'data': 'uuidXML'
},
{
'data': 'importe'
},
{
"data": function (data) {
return `<td class="text-right py-0 align-middle">
<div class="btn-group btn-group-sm">
<button class="btn-danger btn-delete btnDeleteEnlace" data-id="${data.id}" ><i class="fas fa-trash"></i></button>
<button class="btn bg-warning btn-printInvoice" data-id="${data.uuidXML}" ><i class="far fa-file-pdf"></i></button>
</div>
</td>`
}
}
]
});
/**
* Eliminar Renglon Diagnostico
*/
$("#table-payments").on("click", ".btnDeletePayment", function () {
var idPago = $(this).attr("data-id");
Swal.fire({
title: '<?= lang('boilerplate.global.sweet.title') ?>',
text: "<?= lang('boilerplate.global.sweet.text') ?>",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '<?= lang('boilerplate.global.sweet.confirm_delete') ?>'
})
.then((result) => {
if (result.value) {
$.ajax({
url: `<?= base_url('admin/payments/delete/') ?>/` + idPago,
method: 'GET',
}).done((data, textStatus, jqXHR) => {
Toast.fire({
icon: 'success',
title: jqXHR.statusText,
});
tableProducts.ajax.reload();
tableQuotes.ajax.reload();
}).fail((error) => {
Toast.fire({
icon: 'error',
title: error.responseJSON.messages.error,
});
})
}
})
})
</script>
<?= $this->endSection() ?>
Agregamos el modal para poder enlazar XML no enlazados a la venta en App/Views/modulesSells/xmlList con el siguiente código
<!-- Modal Pacientes -->
<div class="modal fade" id="modalListXML" tabindex="-1" role="dialog" aria-labelledby="modalListXML"
aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Lista de XML Timbrados</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
<input type="hidden" id="idVentaSinAsignar" name="idVentaSinAsignar" value="">
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table id="table-listXML" class="table table-striped table-hover va-middle tableListXML">
<thead>
<tr>
<th>#</th>
<th>Fecha</th>
<th>RFC</th>
<th>Nombre Receptor</th>
<th>UUID</th>
<th>Serie</th>
<th>folio</th>
<th>total</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">
<?= lang('boilerplate.global.close') ?>
</button>
</div>
</div>
</div>
</div>
<?= $this->section('js') ?>
<script>
var tableListXML = $('#table-listXML').DataTable({
processing: true,
serverSide: true,
responsive: true,
autoWidth: false,
order: [[1, 'asc']],
ajax: {
url: '<?= base_url('admin/xml/xmlSinAsignar/I') ?>',
method: 'GET',
dataType: "json"
},
columnDefs: [{
orderable: false,
targets: [8],
searchable: false,
targets: [8]
}],
columns: [{
'data': 'id'
},
{
'data': 'fecha'
},
{
'data': 'rfcReceptor'
},
{
'data': 'nombreReceptor'
},
{
'data': 'uuidTimbre'
},
{
'data': 'serie'
},
{
'data': 'folio'
},
{
'data': 'total'
},
{
"data": function (data) {
return `<td class="text-right py-0 align-middle">
<div class="btn-group btn-group-sm">
<button class="btn-success btn-addXMLSell" data-id="${data.uuidTimbre}" ><i class="fas fa-plus-circle"></i></button>
</div>
</td>`
}
}
]
});
/**
* Eliminar Renglon Diagnostico
*/
$("#table-listXML").on("click", ".btn-addXMLSell", function () {
var uuidTimbre = $(this).attr("data-id");
var uuidVenta = $("#idVentaSinAsignar").val();
var datos = new FormData();
datos.append("uuidTimbre", uuidTimbre);
datos.append("uuidVenta", uuidVenta);
$.ajax({
url: "<?= base_url('admin/xmlenlace/enlazaVenta') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
success: function (respuesta) {
if (respuesta.match(/Correctamente.*/)) {
Toast.fire({
icon: 'success',
title: "Guardado Correctamente"
});
tableListXML.ajax.reload();
// $('#modalAddCustumers').modal('hide');
} else {
Toast.fire({
icon: 'error',
title: respuesta
});
//$("#btnSaveCustumers").removeAttr("disabled");
}
}
})
});
</script>
<?= $this->endSection() ?>
Creamos las rutas necesarias en App/Config/Routes.php
$routes->resource('sells', [
'filter' => 'permission:sells-permission',
'controller' => 'SellsController',
'except' => 'show'
]);
$routes->get('newSells', 'SellsController::newSell');
$routes->get('editSell/(:any)', 'SellsController::editSell/$1');
$routes->post('sells/save', 'SellsController::save');
$routes->post('sells/getLastCode', 'SellsController::getLastCode');
$routes->get('sells/report/(:any)', 'SellsController::report/$1');
$routes->get('sells/(:any)/(:any)/(:any)/(:any)/(:any)/(:any)', 'SellsController::sellsFilters/$1/$2/$3/$4/$5/$6');
$routes->get('reporteVentas', 'SellsController::reportSellsProducts');
$routes->get('sellsReport/(:any)/(:any)/(:any)/(:any)/(:any)/(:any)', 'SellsController::sellsReport/$1/$2/$3/$4/$5/$6');
$routes->get('facturar/(:any)', 'FacturaElectronicaController::timbrar/$1');
Agregamos el menú para crear una nueva venta con los siguientes datos

Creamos el menú para ver la lista de ventas con los siguientes datos

Creamos el permiso necesario para la venta de la siguiente forma

Y listo ya tenemos nuestro modulo de ventas con facturación electronica


1 pingback