La descarga masiva es un proceso que permite descargar un gran número de archivos o datos de forma simultánea. En el contexto de las facturas electrónicas en México, la descarga masiva se refiere al proceso de descargar un gran número de CFDI de forma simultánea desde el portal del SAT.
Por lo tanto vamos agregar este utilidad utilizando las librerías de https://www.phpcfdi.com/librerias/
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.
Creamos el archivo de lenguaje en español en App/Languaje/es/proveedores.php con el siguiente código.
<?php
$proveedores["logDescription"] = "El registro en proveedores fue guardado con los siguientes datos:";
$proveedores["logUpdate"] = "El registro en proveedores fue actualizado con los siguientes datos:";
$proveedores["logDeleted"] = "El registro en proveedores fue eliminado con los siguientes datos:";
$proveedores["msg_delete"] = "El Registro en clieproveedoresntes fue eliminado correctamente:";
$proveedores["add"] = "Agregar Proveedor";
$proveedores["edit"] = "Editar Proveedor";
$proveedores["createEdit"] = "Crear / Editar";
$proveedores["title"] = "Admon. Proveedores";
$proveedores["subtitle"] = "Lista de Proveedores";
$proveedores["fields"]["firstname"] = "Nombre";
$proveedores["fields"]["lastname"] = "Apellido";
$proveedores["fields"]["taxID"] = "RFC";
$proveedores["fields"]["email"] = "Correo Electronico";
$proveedores["fields"]["direction"] = "Direccion";
$proveedores["fields"]["birthdate"] = "Fecha de nacimiento";
$cusproveedorestumers["fields"]["created_at"] = "Fecha de creacion";
$proveedores["fields"]["updated_at"] = "Ultima modificacion";
$proveedores["fields"]["deleted_at"] = "Fecha de eliminacion";
$proveedores["fields"]["actions"] = "Acciones";
$proveedores["msg"]["msg_insert"] = "Registro agregado correctamente.";
$proveedores["msg"]["msg_update"] = "Registro modificado correctamente.";
$proveedores["msg"]["msg_delete"] = "Registro eliminado correctamente.";
$proveedores["msg"]["msg_get"] = "Registro obtenido correctamente.";
$proveedores["msg"]["msg_get_fail"] = "Registro no encontrado o eliminado.";
return $proveedores;
Creamos el archivo de lenguaje en ingles en App/Languaje/en/proveedores.php con el siguiente código.
<?php
$proveedores["logDescription"] = "The custumers was saved with the following data:";
$proveedores["logUpdate"] = "The custumers was updated with the following data:";
$proveedores["logDeleted"] = "The custumers was deleted with the following data:";
$proveedores["msg_delete"] = "The custumers was deleted correctly:";
$proveedores["add"] = "Add Vendor";
$proveedores["edit"] = "Edit Vendor";
$proveedores["createEdit"] = "Create / Edit";
$proveedores["title"] = "Vendors management";
$proveedores["subtitle"] = "Vendors list";
$proveedores["fields"]["firstname"] = "Firstname";
$proveedores["fields"]["lastname"] = "Lastname";
$proveedores["fields"]["taxID"] = "TaxID";
$proveedores["fields"]["email"] = "Email";
$proveedores["fields"]["direction"] = "Direction";
$proveedores["fields"]["birthdate"] = "Birthdate";
$proveedores["fields"]["created_at"] = "Created_at";
$proveedores["fields"]["updated_at"] = "Updated_at";
$proveedores["fields"]["deleted_at"] = "Deleted_at";
$proveedores["fields"]["actions"] = "Actions";
$proveedores["msg"]["msg_insert"] = "The Vendor has been correctly added.";
$proveedores["msg"]["msg_update"] = "The Vendor has been correctly modified.";
$proveedores["msg"]["msg_delete"] = "The Vendor has been correctly deleted.";
$proveedores["msg"]["msg_get"] = "The Vendor has been successfully get.";
$proveedores["msg"]["msg_get_fail"] = "The Vendor not found or already deleted.";
return $proveedores;
En App/Config/Routes.php en el grupo admin agregamos las siguientes rutas
Ahora para poder timbrar facturas CFDI necesitamos tener un catalogo de series electrónicas.
En el catalogo de series electrónicas vamos a necesitar los siguientes datos
Empresa
Sucursal
Tipo Serie (venta,pago,devolucion,bonificacion)
Serie
Desde Fecha
Hasta Fecha
Desde Folio
Hasta Folio
Ambiente Timbrado
Token pruebas
Token producción
Primero creamos el archivo de migración App/Database/migrations/2023-10-17120916_Seriesfacturaelectronica.php para la creación de la tabla en la base de datos
Bien como ya saben para hacer una venta se requiere saber de que sucursal es así como ciertas configuraciones particulares por sucursal como la configuración de las series electrónicas para el timbrado del CFDI, así como los datos que saldran en las impresiones de los reportes, como la dirección etc
Por esta ocasión agregaremos lo siguientes datos, posterior mente se pueden agregar mas si se necesitan
Primeramente creamos el archivo de migración app/database/migrations/2023-02-14110147_Branchoffices.php , se dan cuenta que dice Branchoffice, es por que en su momento lo quise empezar en ingles para practicar
Creamos el archivo del modelo usuarios por sucursal app/model/UsuariosSucursalModel.php
<?php
namespace App\Models;
use CodeIgniter\Model;
class UsuariosSucursalModel extends Model
{
protected $table = 'usuarios_sucursal';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $useSoftDeletes = true;
protected $allowedFields = ['id', 'idEmpresa', 'idSucursal', 'idUsuario', 'status', '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 mdlSucursalesPorUsuario($sucursal, $empresasID)
{
$result = $this->db->table('users a, usuariosempresa b')
->select(
'ifnull(a.id,0) as id
,a.username
,b.idEmpresa
,' . $sucursal . ' as idSucursal
,ifnull((select status
from usuarios_sucursal z
where z.idUsuario = a.id
and z.idEmpresa=b.idEmpresa
and z.idSucursal=' . $sucursal . '
),\'off\') as status
,ifnull((select id
from usuarios_sucursal z
where z.idUsuario = a.id
and z.idEmpresa=b.idEmpresa
and z.idSucursal=' . $sucursal . '
),0) as idSucursalUsuario
'
)
->where('a.id', 'b.idUsuario', FALSE)
->where('b.idEmpresa', $empresasID);
return $result;
}
}
Creamos el archivo app/controller/BranchofficesController.php
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
use \App\Models\{
BranchofficesModel
};
use App\Models\LogModel;
use CodeIgniter\API\ResponseTrait;
use App\Models\EmpresasModel;
use App\Models\UsuariosSucursalModel;
class BranchofficesController extends BaseController {
use ResponseTrait;
protected $log;
protected $branchoffices;
protected $empresas;
protected $usuariosPorSucursal;
public function __construct() {
$this->branchoffices = new BranchofficesModel();
$this->log = new LogModel();
$this->empresas = new EmpresasModel();
$this->usuariosPorSucursal = new UsuariosSucursalModel();
helper('menu');
}
public function index() {
helper('auth');
$idUser = user()->id;
$titulos["empresas"] = $this->empresas->mdlEmpresasPorUsuario($idUser);
if (count($titulos["empresas"]) == "0") {
$empresasID[0] = "0";
} else {
$empresasID = array_column($titulos["empresas"], "id");
}
if ($this->request->isAJAX()) {
$datos = $this->branchoffices->select('id
,key
,name
,cologne
,city
,postalCode
,timeDifference
,tax,dateAp
,phone
,fax
,companie
,created_at
,deleted_at
,updated_at')->where('deleted_at', null)
->whereIn('companie', $empresasID);;
return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
}
// $empresas = $this->empresas->select("id,nombre")->asObject()->findAll();
// $titulos["empresas"] = $empresas;
$titulos["title"] = lang('branchoffices.title');
$titulos["subtitle"] = lang('branchoffices.subtitle');
return view('branchoffices', $titulos);
}
/**
* Read Branchoffices
*/
public function getBranchoffices() {
$idBranchoffices = $this->request->getPost("idBranchoffices");
$datosBranchoffices = $this->branchoffices->find($idBranchoffices);
echo json_encode($datosBranchoffices);
}
/**
* Save or update Branchoffices
*/
public function save() {
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$datos = $this->request->getPost();
if ($datos["idBranchoffices"] == 0) {
try {
if ($this->branchoffices->save($datos) === false) {
$errores = $this->branchoffices->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->branchoffices->update($datos["idBranchoffices"], $datos) == false) {
$errores = $this->branchoffices->errors();
foreach ($errores as $field => $error) {
echo $error . " ";
}
return;
} else {
$dateLog["description"] = lang("branchoffices.logUpdated") . json_encode($datos);
$dateLog["user"] = $userName;
$this->log->save($dateLog);
echo "Actualizado Correctamente";
return;
}
}
return;
}
/**
* Delete Branchoffices
* @param type $id
* @return type
*/
public function delete($id) {
$infoBranchoffices = $this->branchoffices->find($id);
helper('auth');
$userName = user()->username;
if (!$found = $this->branchoffices->delete($id)) {
return $this->failNotFound(lang('branchoffices.msg.msg_get_fail'));
}
$logData["description"] = lang("branchoffices.logDeleted") . json_encode($infoBranchoffices);
$logData["user"] = $userName;
$this->log->save($logData);
return $this->respondDeleted($found, lang('branchoffices.msg_delete'));
}
public function usuariosPorSucursal($sucursal) {
helper('auth');
$idUser = user()->id;
$datosSucursal = $this->branchoffices->select("companie as empresa")->where("id",$sucursal)->first();
if(isset($datosSucursal["empresa"])){
$idEmpresa = $datosSucursal["empresa"];
}else{
$idEmpresa = -1;
}
$usuarios = $this->usuariosPorSucursal->mdlSucursalesPorUsuario($sucursal, $idEmpresa);
return \Hermawan\DataTables\DataTable::of($usuarios)->toJson(true);
}
/**
* Activar Desactivar Usuario Por Empresa
*/
public function ActivarDesactivar() {
$datos = $this->request->getPost();
if ($datos["id"] > 0) {
//ACTUALIZA SI EXISTE
if ($this->usuariosPorSucursal->update($datos["id"], $datos) === false) {
$errores = $this->usuariosPorSucursal->errors();
foreach ($errores as $field => $error) {
echo $error . " ";
}
return;
}
echo "ok";
} else {
//INSERTA SI NO EXISTE
if ($this->usuariosPorSucursal->save($datos) === false) {
$errores = $this->usuariosPorSucursal->errors();
foreach ($errores as $key => $error) {
echo $error . " ";
}
return;
}
echo "ok";
}
}
/**
* Get Storages via AJax
*/
public function getSucursalesAjax() {
$request = service('request');
$postData = $request->getPost();
$response = array();
// Read new token and assign in $response['token']
$response['token'] = csrf_hash();
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$sucursalesPorUsuario = $this->usuariosPorSucursal->select("*")
->where("idUsuario", $idUser)
->where("status", "on")->findAll();
$sucursalesPorUsuario = array_column($sucursalesPorUsuario, "idSucursal");
if (!isset($postData['searchTerm'])) {
// Fetch record
$sucursales = new BranchofficesModel();
$listSucursales = $sucursales->select('id,key,name')->where("deleted_at", null)
->whereIn("id", $sucursalesPorUsuario)
->where("companie", $postData["idEmpresa"])
->orderBy('id')
->orderBy('key')
->orderBy('name')
->findAll();
} else {
$searchTerm = $postData['searchTerm'];
// Fetch record
$sucursales = new BranchofficesModel();
$listSucursales = $sucursales->select('id,key,name')
->where("deleted_at", null)
->whereIn("id", $sucursalesPorUsuario)
->where("companie", $postData["idEmpresa"])
->like('name', $searchTerm)
->orLike('id', $searchTerm)
->orLike('key', $searchTerm)
->findAll();
}
$data = array();
$data[] = array(
"id" => 0,
"text" => "0 Todas las sucursales",
);
foreach ($listSucursales as $sucursal) {
$data[] = array(
"id" => $sucursal['id'],
"text" => $sucursal['key'] . ' ' . $sucursal['name'],
);
}
$response['data'] = $data;
return $this->response->setJSON($response);
}
}
Creamos el archivo del controlador para usuarios por sucursal app/controller/UsuariosSucursalController.php
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
use \App\Models\{
UsuariosSucursalModel
};
use App\Models\LogModel;
use CodeIgniter\API\ResponseTrait;
class UsuariosSucursalController extends BaseController {
use ResponseTrait;
protected $log;
protected $usuariosSucursal;
public function __construct() {
$this->usuariosSucursal = new UsuariosSucursalModel();
$this->log = new LogModel();
helper('menu');
}
public function index() {
if ($this->request->isAJAX()) {
$datos = $this->usuariosSucursal>select('id,idEmpresa,idSucursal,idUsuario,status,created_at,updated_at,deleted_at')->where('deleted_at', null);
return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
}
$titulos["title"] = "Usuarios Sucursal";
$titulos["subtitle"] = "Usuarios Por Sucursal";
return view('usuariosAlmacen', $titulos);
}
/**
* Read Usuariosempresa
*/
public function getUsuariosAlmacen() {
$idUsuariosAlmacen = $this->request->getPost("idUsuariosSucursal");
$datosUsuariosAlmacen = $this->usuariosAlmacen->find($idUsuariosAlmacen);
echo json_encode($datosUsuariosAlmacen);
}
/**
* Save or update Usuariosempresa
*/
public function save() {
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$datos = $this->request->getPost();
if ($datos["idUsuariosSucursal"] == 0) {
try {
if ($this->usuariosSucursal->save($datos) === false) {
$errores = $this->usuariosSucursal->errors();
foreach ($errores as $field => $error) {
echo $error . " ";
}
return;
}
$dateLog["description"] = "Usuarios Por Sucursal" . 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->usuariosSucursal->update($datos["idUsuariossucursal"], $datos) == false) {
$errores = $this->usuariosSucursal->errors();
foreach ($errores as $field => $error) {
echo $error . " ";
}
return;
} else {
$dateLog["description"] = lang("usuariosSucursal.logUpdated") . json_encode($datos);
$dateLog["user"] = $userName;
$this->log->save($dateLog);
echo "Actualizado Correctamente";
return;
}
}
return;
}
/**
* Delete Usuariosempresa
* @param type $id
* @return type
*/
public function delete($id) {
$infoUsuariosSucursal = $this->usuariosSucursal->find($id);
helper('auth');
$userName = user()->username;
if (!$found = $this->usuariosSucursal->delete($id)) {
return $this->failNotFound(lang('usuariosempresa.msg.msg_get_fail'));
}
$this->usuariosSucursal->purgeDeleted();
$logData["description"] = "Datos Anteriores Usuarios Por Sucursal" . json_encode($infoUsuariosSucursal);
$logData["user"] = $userName;
$this->log->save($logData);
return $this->respondDeleted($found, lang('usuariossucursal.msg_delete'));
}
}
Creamos el archivo principal de la vista de sucursales app/views/branchoffice.php este archivo hará una inclusión a los modales de usuarios por sucursal y captura de sucursales
Ya vimos como usar AutoCrud para crear los catálogos, en esta ocasión tambien usamos autocrud, aun así dejaremos el código fuente completo de este modulo
Creamos el archivo modelo al app/models/CustumersModel.php con el siguiente contenido
Para la traducción en ingles creamos el archivo app/languaje/es/custumers.php con el siguiente contenido
<?php
$custumers["logDescription"] = "The custumers was saved with the following data:";
$custumers["logUpdate"] = "The custumers was updated with the following data:";
$custumers["logDeleted"] = "The custumers was deleted with the following data:";
$custumers["msg_delete"] = "The custumers was deleted correctly:";
$custumers["add"] = "Add Custumers";
$custumers["edit"] = "Edit custumers";
$custumers["createEdit"] = "Create / Edit";
$custumers["title"] = "custumers management";
$custumers["subtitle"] = "custumers list";
$custumers["fields"]["firstname"] = "Firstname";
$custumers["fields"]["lastname"] = "Lastname";
$custumers["fields"]["taxID"] = "TaxID";
$custumers["fields"]["email"] = "Email";
$custumers["fields"]["direction"] = "Direction";
$custumers["fields"]["birthdate"] = "Birthdate";
$custumers["fields"]["created_at"] = "Created_at";
$custumers["fields"]["updated_at"] = "Updated_at";
$custumers["fields"]["deleted_at"] = "Deleted_at";
$custumers["fields"]["actions"] = "Actions";
$custumers["msg"]["msg_insert"] = "The custumers has been correctly added.";
$custumers["msg"]["msg_update"] = "The custumers has been correctly modified.";
$custumers["msg"]["msg_delete"] = "The custumers has been correctly deleted.";
$custumers["msg"]["msg_get"] = "The Custumers has been successfully get.";
$custumers["msg"]["msg_get_fail"] = "The custumers not found or already deleted.";
return $custumers;
Para nuestra traduccion en español creamos el archivo app/languaje/es/custumers.php
<?php
$custumers["logDescription"] = "El registro en clientes fue guardado con los siguientes datos:";
$custumers["logUpdate"] = "El registro en clientes fue actualizado con los siguientes datos:";
$custumers["logDeleted"] = "El registro en clientes fue eliminado con los siguientes datos:";
$custumers["msg_delete"] = "El Registro en clientes fue eliminado correctamente:";
$custumers["add"] = "Agregar Cliente";
$custumers["edit"] = "Editar Cliente";
$custumers["createEdit"] = "Crear / Editar";
$custumers["title"] = "Admon. Clientes";
$custumers["subtitle"] = "Lista de Clientes";
$custumers["fields"]["firstname"] = "Nombre";
$custumers["fields"]["lastname"] = "Apellido";
$custumers["fields"]["taxID"] = "RFC";
$custumers["fields"]["email"] = "Correo Electronico";
$custumers["fields"]["direction"] = "Direccion";
$custumers["fields"]["birthdate"] = "Fecha de nacimiento";
$custumers["fields"]["created_at"] = "Fecha de creacion";
$custumers["fields"]["updated_at"] = "Ultima modificacion";
$custumers["fields"]["deleted_at"] = "Fecha de eliminacion";
$custumers["fields"]["actions"] = "Acciones";
$custumers["msg"]["msg_insert"] = "Registro agregado correctamente.";
$custumers["msg"]["msg_update"] = "Registro modificado correctamente.";
$custumers["msg"]["msg_delete"] = "Registro eliminado correctamente.";
$custumers["msg"]["msg_get"] = "Registro obtenido correctamente.";
$custumers["msg"]["msg_get_fail"] = "Registro no encontrado o eliminado.";
return $custumers;
Creamos nuestro archivo de migración en app/databases/migrations/2023-04-21063335_Custumers.php con el siguiente contenido
Ya vimos como crear módulos y catalogo ahora mostraremos como automatizar esa parte del proceso de desarrollo para ser un poco mas eficientes para ello escribimos un código que escribe el código repetitivo
Creamos el archivo app/controller/AutoCrudController.php con el siguiente código
-- phpMyAdmin SQL Dump
-- version 5.0.4
-- https://www.phpmyadmin.net/
--
-- Servidor: 127.0.0.1
-- Tiempo de generación: 21-04-2023 a las 20:19:25
-- Versión del servidor: 10.4.17-MariaDB
-- Versión de PHP: 7.4.15
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Base de datos: `ci4jcpos`
--
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `categorias`
--
CREATE TABLE `categorias` (
`id` int(11) NOT NULL,
`descripcion` varchar(128) COLLATE utf8mb4_spanish2_ci DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_spanish2_ci;
--
-- Índices para tablas volcadas
--
--
-- Indices de la tabla `categorias`
--
ALTER TABLE `categorias`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT de las tablas volcadas
--
--
-- AUTO_INCREMENT de la tabla `categorias`
--
ALTER TABLE `categorias`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
Corremos la siguiente URL en el navegador para crear todo el catalogo
JCPOS: Una solución de punto de venta en constante evolución
En una reciente transmisión en vivo, el equipo de desarrollo detrás de JCPOS discutió los últimos cambios y mejoras en su solución de punto de venta. JCPOS es un sistema de punto de venta que ha estado en desarrollo desde el 2020, y ha evolucionado constantemente desde entonces para satisfacer las necesidades de sus usuarios.
Uno de los cambios más notables que el equipo ha realizado es el cambio de nombre de JC post a JCPOS. Esto se hizo para mantener la coherencia en el nombre a lo largo de los años, y evitar confusiones al cambiar el nombre cada año.
Otro de los cambios que se discutió en la transmisión fue la reciente publicación del repositorio de JCPOS en Github. Ahora está disponible para que cualquier persona interesada lo pueda descargar y explorar el código fuente. Además, se hizo hincapié en que los usuarios pueden contribuir al proyecto si encuentran algún problema o tienen alguna sugerencia.
El equipo también habló de algunos cambios específicos que han realizado en JCPOS, como la corrección de un problema en la bitácora que no estaba ordenando los botones de manera correcta. También se discutió la implementación de descuentos en las ventas, para asegurarse de que funcionen correctamente. Además, se está trabajando en la corrección de detalles menores, como la ordenación de la lista de ventas.
El equipo de JCPOS también habló sobre su intención de usar Composer para gestionar las dependencias del proyecto, lo que les permitirá mantenerse actualizados con las últimas versiones de las librerías que utilizan. También se mencionó la adición de impuestos a los productos, lo que permitirá la implementación de facturación electrónica en el futuro.
Finalmente, el equipo mencionó a sus patrocinadores y clientes, agradeciendo su apoyo y mencionando que los nombres de los patrocinadores se agregarán al repositorio en el futuro. También se proporcionó información sobre cómo patrocinar el proyecto.
En resumen, JCPOS es un proyecto de punto de venta en constante evolución. El equipo detrás de JCPOS está trabajando constantemente para mejorar la solución, escuchar las necesidades de los usuarios y mantenerse actualizado con las últimas tecnologías y herramientas de desarrollo. Si estás interesado en probar JCPOS o contribuir al proyecto, ¡asegúrate de visitar su repositorio en Github!
en main.js lo dejamos haci lo que hara es cargar la url y levantar el servicio de php
// Modules to control application life and create native browser window
const {app, BrowserWindow} = require('electron')
const path = require('path')
const exec = require('child_process').exec;
function execute(command, callback) {
exec(command, (error, stdout, stderr) => {
callback(stdout);
});
};
// call the function
execute('Ejecutar.bat', (output) => {
console.log(output);
});
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// and load the index.html of the app.
mainWindow.setMenu(null)
mainWindow.loadURL('http://localhost:8097')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
ahora posicionados en la carpeta \electron-quick-start> corremos el siguiente comando
npm install
Después creamos el paquete-ejecutable con el siguiente comando
Creamos una carpeta en C: llamada aplicación o como ustedes quieran llamarle y copiamos el contenido, la carpeta del proyecto del codeigniter y los archivos ejecutable de PHP con los que trabajan, pueden copiar los del xampp y con el que debugean a través de netbeans quedaría de la siguiente forma
ConvertidorXMLPDF seria el proyecto en codeigniter, php8 son los binarios necesarios para ejecutar código php, este lo pueden extraer de xampp y lo demas son los archivos de electronJS
Ahora en el archivo de configuración de código igniter en config/app.php en la base URL la dejamos asi
public $baseURL = '[http://localhost:8097/](http://localhost:8097/)';
El archivo Ejecutar.bat es el que va iniciar todo el codeigniter y dentro de el va el siguiente codigo
@echo off
php8\php.exe convertidorXMLPDF/spark serve --port 8097
El archivo Ejecutar.bat se ejecuta automáticamente al abrir el ejecutable
Y listo ahora solo queda hacer el instalador pero lo dejamos para otro manual.
Usamos cookies en nuestro sitio web para brindarle la experiencia más relevante recordando sus preferencias y visitas repetidas. Al hacer clic en "Aceptar", acepta el uso de TODAS las cookies.
This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.