Herramientas Informaticas

Etiqueta: JCPOS Página 3 de 5

Creando CRUD de Tipos de movimiento #13

Para registrar los movimientos requerimos especificar que tipo de movimiento es como puede ser entradas por compra, salidas por venta, entrada por devolución de cliente, saluda por devolución a proveedor

Para ello crearemos el siguiente catalogo de Tipos de movimiento con los siguientes campos

  • Empresa
  • Descripción
  • tipo
  • Es traspaso

Primero creamos el archivo de migración App/Database/2023-08-17222335_Tipos_movimientos_inventario.php con el siguiente código

Creando CRUD de Almacenes #12

Es necesario para llevar el control correcto del inventario tener almacenes,

A continuación mostramos como crear el CRUD de almacenes

El CRUD tendrá los siguientes datos

  • Empresa
  • Clave
  • Nombre
  • Inicio de inventario

Creando CRUD de Proveedores #11

Antes de empezar con el inventario necesitaremos los catálogos principales, uno de ellos es el catalogo de proveedores.

El catalogo es similar al de clientes

Para ello necesitamos en los siguientes campos:

Datos Generales

  • Empresa
  • Nombre
  • Apellido
  • Correo Electrónico
  • Dirección
  • Código Postal
  • Fecha de nacimiento

Datos Extra Facturación

  • Razón social
  • RFC
  • Forma de pago
  • Método de pago
  • Uso CFDI
  • Regimen Fiscal
Leer Mas: Creando CRUD de Proveedores #11

Creamos el archivo de migración App/Database/Migrations/2023-04-21063336_Proveedores con el siguiente codigo

<?php

namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class Proveedores extends Migration {

    public function up() {
        // Custumers
        $this->forge->addField([
            'id' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
            'idEmpresa' => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
            'firstname' => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
            'lastname' => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
            'razonSocial' => ['type' => 'varchar', 'constraint' => 512, 'null' => true],
            'taxID' => ['type' => 'varchar', 'constraint' => 64, 'null' => true],
            'email' => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
            'direction' => ['type' => 'varchar', 'constraint' => 1024, 'null' => true],
            'birthdate' => ['type' => 'datetime', 'null' => true],
            'formaPago' => ['type' => 'varchar', 'constraint' => 16, 'null' => true],
            'metodoPago' => ['type' => 'varchar', 'constraint' => 16, 'null' => true],
            'usoCFDI' => ['type' => 'varchar', 'constraint' => 16, 'null' => true],
            'codigoPostal' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true],
            'regimenFiscal' => ['type' => 'varchar', 'constraint' => 128, '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('proveedores', true);
    }

    public function down() {
        $this->forge->dropTable('proveedores', true);
    }

}

Creamos el archivo modelo en App/Models/ProveedoresModel.php con el siguiente código

<?php

namespace App\Models;

use CodeIgniter\Model;

class ProveedoresModel extends Model {

    protected $table = 'proveedores';
    protected $primaryKey = 'id';
    protected $useAutoIncrement = true;
    protected $returnType = 'array';
    protected $useSoftDeletes = true;
    protected $allowedFields = ['id'
        , 'idEmpresa'
        , 'firstname'
        , 'lastname'
        , 'taxID'
        , 'email'
        , 'direction'
        , 'birthdate'
        , 'created_at'
        , 'updated_at'
        , 'deleted_at'
        , 'metodoPago'
        , 'formaPago'
        , 'codigoPostal'
        , 'regimenFiscal'
        , 'razonSocial'
        , 'usoCFDI'];
    protected $useTimestamps = true;
    protected $createdField = 'created_at';
    protected $deletedField = 'deleted_at';
    protected $validationRules = [
    ];
    protected $validationMessages = [];
    protected $skipValidation = false;

    /**
     * Obtener Clientes
     */
    public function mdlGetProveedores($empresas) {


        $resultado = $this->db->table('proveedores a, empresas b')
                ->select('a.id
                    ,a.idEmpresa
                    ,b.nombre as nombreEmpresa
                    ,a.firstname
                    ,a.lastname
                    ,a.taxID
                    ,a.email
                    ,a.direction
                    ,a.birthdate
                    ,a.metodoPago
                    ,a.formaPago
                    ,a.usoCFDI
                    ,a.created_at
                    ,a.updated_at
                    ,a.codigoPostal
                    ,a.regimenFiscal
                    ,a.razonSocial
                    ,a.deleted_at')
                ->where('a.idEmpresa', 'b.id', FALSE)
                ->whereIn('a.idEmpresa', $empresas);

        return $resultado;
    }

}

Creamos el archivo controlador en App/Controllers/ProveedoresController.php con el siguiente código.

<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use \App\Models\{
    ProveedoresModel
};
use App\Models\LogModel;
use CodeIgniter\API\ResponseTrait;
use App\Models\EmpresasModel;

class ProveedoresController extends BaseController {

    use ResponseTrait;

    protected $log;
    protected $proveedores;
    protected $empresa;

    public function __construct() {
        $this->proveedores = new ProveedoresModel();
        $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->proveedores->mdlGetProveedores($empresasID);
            return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
        }

        $fechaActual = fechaMySQLADateTimeHTML5(fechaHoraActual());

        $titulos["title"] = lang('proveedores.title');
        $titulos["subtitle"] = lang('proveedores.subtitle');
        $titulos["fecha"] = $fechaActual;

        $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);
        return view('proveedores', $titulos);
    }

    /**
     * Read Custumers
     */
    public function getProveedores() {
        $idProveedor = $this->request->getPost("idProveedor");

        $datosProveedor = $this->proveedores->find($idProveedor);
        echo json_encode($datosProveedor);
    }

    /**
     * Get Custumers via AJax
     */
    public function getProveedoresAjax() {

        $request = service('request');
        $postData = $request->getPost();

        $response = array();

        // Read new token and assign in $response['token']
        $response['token'] = csrf_hash();
        $proveedores = new ProveedoresModel();
        $idEmpresa = $postData['idEmpresa'];

        if (!isset($postData['searchTerm'])) {
            // Fetch record

            $listProveedores = $proveedores->select('id,firstname,lastname')->where("deleted_at", null)
                    ->where('idEmpresa', $idEmpresa)
                    ->orderBy('id')
                    ->orderBy('firstname')
                    ->orderBy('lastname')
                    ->findAll(10);
        } else {
            $searchTerm = $postData['searchTerm'];

            // Fetch record

            $listProveedores = $proveedores->select('id,firstname,lastname')->where("deleted_at", null)
                    ->where('idEmpresa', $idEmpresa)
                    ->groupStart()
                    ->like('firstname', $searchTerm)
                    ->orLike('id', $searchTerm)
                    ->orLike('lastname', $searchTerm)
                    ->groupEnd()
                    ->findAll(10);
        }

        $data = array();
        foreach ($listProveedores as $proveedores) {
            $data[] = array(
                "id" => $proveedores['id'],
                "text" => $proveedores['id'] . ' ' . $proveedores['firstname'] . ' ' . $proveedores['lastname'],
            );
        }

        $response['data'] = $data;

        return $this->response->setJSON($response);
    }

    /**
     * Save or update Custumers
     */
    public function save() {
        helper('auth');
        $userName = user()->username;
        $idUser = user()->id;
        $datos = $this->request->getPost();
        if ($datos["idProveedor"] == 0) {
            try {
                if ($this->proveedores->save($datos) === false) {
                    $errores = $this->proveedores->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->proveedores->update($datos["idProveedor"], $datos) == false) {
                $errores = $this->proveedores->errors();
                foreach ($errores as $field => $error) {
                    echo $error . " ";
                }
                return;
            } else {
                $dateLog["description"] = lang("proveedores.logUpdated") . json_encode($datos);
                $dateLog["user"] = $userName;
                $this->log->save($dateLog);
                echo "Actualizado Correctamente";
                return;
            }
        }
        return;
    }

    /**
     * Delete Custumers
     * @param type $id
     * @return type
     */
    public function delete($id) {
        $infoCustumers = $this->proveedores->find($id);
        helper('auth');
        $userName = user()->username;
        if (!$found = $this->proveedores->delete($id)) {
            return $this->failNotFound(lang('custumers.msg.msg_get_fail'));
        }
        $this->proveedores->purgeDeleted();
        $logData["description"] = lang("proveedores.logDeleted") . json_encode($infoCustumers);
        $logData["user"] = $userName;
        $this->log->save($logData);
        return $this->respondDeleted($found, lang('custumers.msg_delete'));
    }

}

Creamos el archivo principal de la vista en App/Views/proveedores.php con el siguiente código.

<?= $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('modulesProveedores/modalCaptureProveedores') ?>

<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
    <div class="card-header">
        <div class="float-right">
            <div class="btn-group">

                <button class="btn btn-primary btnAddProveedores" data-toggle="modal" data-target="#modalAddProveedores"><i
                        class="fa fa-plus"></i>

                    <?= lang('proveedores.add') ?>

                </button>

            </div>
        </div>
    </div>
    <div class="card-body">
        <div class="row">
            <div class="col-md-12">
                <div class="table-responsive">
                    <table id="tableProveedores" class="table table-striped table-hover va-middle tableProveedores">
                        <thead>
                            <tr>

                                <th>#</th>

                                <th>Empresa</th>
                                <th>
                                    <?= lang('proveedores.fields.firstname') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.lastname') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.taxID') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.email') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.direction') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.birthdate') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.created_at') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.updated_at') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.deleted_at') ?>
                                </th>

                                <th>
                                    <?= lang('proveedores.fields.actions') ?>
                                </th>

                            </tr>
                        </thead>
                        <tbody>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- /.card -->

<?= $this->endSection() ?>


<?= $this->section('js') ?>
<script>

    /**
     * Cargamos la tabla
     */

    var tableProveedores = $('#tableProveedores').DataTable({
        processing: true,
        serverSide: true,
        responsive: true,
        autoWidth: false,
        order: [[1, 'asc']],

        ajax: {
            url: '<?= base_url('admin/proveedores') ?>',
            method: 'GET',
            dataType: "json"
        },
        columnDefs: [{
                orderable: false,
                targets: [11],
                searchable: false,
                targets: [11]

            }],
        columns: [{
                'data': 'id'
            },

            {
                'data': 'nombreEmpresa'
            },

            {
                'data': 'firstname'
            },

            {
                'data': 'lastname'
            },

            {
                'data': 'taxID'
            },

            {
                'data': 'email'
            },

            {
                'data': 'direction'
            },

            {
                'data': 'birthdate'
            },

            {
                'data': 'created_at'
            },

            {
                'data': 'updated_at'
            },

            {
                'data': 'deleted_at'
            },

            {
                "data": function (data) {
                    return `<td class="text-right py-0 align-middle">
                         <div class="btn-group btn-group-sm">
                             <button class="btn btn-warning btnEditProveedores" data-toggle="modal" idProveedor="${data.id}" data-target="#modalAddProveedores">  <i class=" fa fa-edit"></i></button>
                             <button class="btn btn-danger btn-delete" data-id="${data.id}"><i class="fas fa-trash"></i></button>
                         </div>
                         </td>`
                }
            }
        ]
    });







    /**
     * Carga datos actualizar
     */


    /*=============================================
     EDITAR Proveedores
     =============================================*/
    $(".tableProveedores").on("click", ".btnEditProveedores", function () {

        var idProveedor = $(this).attr("idProveedor");

        var datos = new FormData();
        datos.append("idProveedor", idProveedor);

        $.ajax({

            url: "<?= base_url('admin/proveedores/getProveedores') ?>",
            method: "POST",
            data: datos,
            cache: false,
            contentType: false,
            processData: false,
            dataType: "json",
            success: function (respuesta) {

                $("#idProveedor").val(respuesta["id"]);
                $("#idEmpresaProveedor").val(respuesta["idEmpresa"]);
                $("#idEmpresaProveedor").trigger("change");
                $("#firstname").val(respuesta["firstname"]);
                $("#razonSocial").val(respuesta["razonSocial"]);
                $("#lastname").val(respuesta["lastname"]);
                $("#taxID").val(respuesta["taxID"]);
                $("#email").val(respuesta["email"]);
                $("#direction").val(respuesta["direction"]);
                $("#birthdate").val(respuesta["birthdate"]);

                $("#formaPago").val(respuesta["formaPago"]);
                $("#formaPago").trigger("change");
                $("#metodoPago").val(respuesta["metodoPago"]);
                $("#metodoPago").trigger("change");
                $("#usoCFDI").val(respuesta["usoCFDI"]);
                $("#usoCFDI").trigger("change");

                $("#codigoPostal").val(respuesta["codigoPostal"]);
                $("#regimenFiscal").val(respuesta["regimenFiscal"]);
                $("#regimenFiscal").trigger("change");

            }

        })

    })

    $("#idEmpresaProveedor ").select2();
    /*=============================================
     ELIMINAR proveedores
     =============================================*/
    $(".tableProveedores").on("click", ".btn-delete", function () {

        var idProveedores = $(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/proveedores') ?>/` + idProveedores,
                            method: 'DELETE',
                        }).done((data, textStatus, jqXHR) => {
                            Toast.fire({
                                icon: 'success',
                                title: jqXHR.statusText,
                            });


                            tableProveedores.ajax.reload();
                        }).fail((error) => {
                            Toast.fire({
                                icon: 'error',
                                title: error.responseJSON.messages.error,
                            });
                        })
                    }
                })
    })

    $(function () {
        $("#modalAddProveedores").draggable();

    });


</script>
<?= $this->endSection() ?>

Creamos el archivo secundario que contiene el modal en App/Views/modulesProveedores/modalCaptureProveedores.php con el siguiente codigo.

<?= $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('modulesProveedores/modalCaptureProveedores') ?>

<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
    <div class="card-header">
        <div class="float-right">
            <div class="btn-group">

                <button class="btn btn-primary btnAddProveedores" data-toggle="modal" data-target="#modalAddProveedores"><i
                        class="fa fa-plus"></i>

                    <?= lang('proveedores.add') ?>

                </button>

            </div>
        </div>
    </div>
    <div class="card-body">
        <div class="row">
            <div class="col-md-12">
                <div class="table-responsive">
                    <table id="tableProveedores" class="table table-striped table-hover va-middle tableProveedores">
                        <thead>
                            <tr>

                                <th>#</th>

                                <th>Empresa</th>
                                <th>
                                    <?= lang('proveedores.fields.firstname') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.lastname') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.taxID') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.email') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.direction') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.birthdate') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.created_at') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.updated_at') ?>
                                </th>
                                <th>
                                    <?= lang('proveedores.fields.deleted_at') ?>
                                </th>

                                <th>
                                    <?= lang('proveedores.fields.actions') ?>
                                </th>

                            </tr>
                        </thead>
                        <tbody>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- /.card -->

<?= $this->endSection() ?>


<?= $this->section('js') ?>
<script>

    /**
     * Cargamos la tabla
     */

    var tableProveedores = $('#tableProveedores').DataTable({
        processing: true,
        serverSide: true,
        responsive: true,
        autoWidth: false,
        order: [[1, 'asc']],

        ajax: {
            url: '<?= base_url('admin/proveedores') ?>',
            method: 'GET',
            dataType: "json"
        },
        columnDefs: [{
                orderable: false,
                targets: [11],
                searchable: false,
                targets: [11]

            }],
        columns: [{
                'data': 'id'
            },

            {
                'data': 'nombreEmpresa'
            },

            {
                'data': 'firstname'
            },

            {
                'data': 'lastname'
            },

            {
                'data': 'taxID'
            },

            {
                'data': 'email'
            },

            {
                'data': 'direction'
            },

            {
                'data': 'birthdate'
            },

            {
                'data': 'created_at'
            },

            {
                'data': 'updated_at'
            },

            {
                'data': 'deleted_at'
            },

            {
                "data": function (data) {
                    return `<td class="text-right py-0 align-middle">
                         <div class="btn-group btn-group-sm">
                             <button class="btn btn-warning btnEditProveedores" data-toggle="modal" idProveedor="${data.id}" data-target="#modalAddProveedores">  <i class=" fa fa-edit"></i></button>
                             <button class="btn btn-danger btn-delete" data-id="${data.id}"><i class="fas fa-trash"></i></button>
                         </div>
                         </td>`
                }
            }
        ]
    });







    /**
     * Carga datos actualizar
     */


    /*=============================================
     EDITAR Proveedores
     =============================================*/
    $(".tableProveedores").on("click", ".btnEditProveedores", function () {

        var idProveedor = $(this).attr("idProveedor");

        var datos = new FormData();
        datos.append("idProveedor", idProveedor);

        $.ajax({

            url: "<?= base_url('admin/proveedores/getProveedores') ?>",
            method: "POST",
            data: datos,
            cache: false,
            contentType: false,
            processData: false,
            dataType: "json",
            success: function (respuesta) {

                $("#idProveedor").val(respuesta["id"]);
                $("#idEmpresaProveedor").val(respuesta["idEmpresa"]);
                $("#idEmpresaProveedor").trigger("change");
                $("#firstname").val(respuesta["firstname"]);
                $("#razonSocial").val(respuesta["razonSocial"]);
                $("#lastname").val(respuesta["lastname"]);
                $("#taxID").val(respuesta["taxID"]);
                $("#email").val(respuesta["email"]);
                $("#direction").val(respuesta["direction"]);
                $("#birthdate").val(respuesta["birthdate"]);

                $("#formaPago").val(respuesta["formaPago"]);
                $("#formaPago").trigger("change");
                $("#metodoPago").val(respuesta["metodoPago"]);
                $("#metodoPago").trigger("change");
                $("#usoCFDI").val(respuesta["usoCFDI"]);
                $("#usoCFDI").trigger("change");

                $("#codigoPostal").val(respuesta["codigoPostal"]);
                $("#regimenFiscal").val(respuesta["regimenFiscal"]);
                $("#regimenFiscal").trigger("change");

            }

        })

    })

    $("#idEmpresaProveedor ").select2();
    /*=============================================
     ELIMINAR proveedores
     =============================================*/
    $(".tableProveedores").on("click", ".btn-delete", function () {

        var idProveedores = $(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/proveedores') ?>/` + idProveedores,
                            method: 'DELETE',
                        }).done((data, textStatus, jqXHR) => {
                            Toast.fire({
                                icon: 'success',
                                title: jqXHR.statusText,
                            });


                            tableProveedores.ajax.reload();
                        }).fail((error) => {
                            Toast.fire({
                                icon: 'error',
                                title: error.responseJSON.messages.error,
                            });
                        })
                    }
                })
    })

    $(function () {
        $("#modalAddProveedores").draggable();

    });


</script>
<?= $this->endSection() ?>

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

    $routes->resource('proveedores', [
        'filter' => 'permission:proveedores-permission',
        'controller' => 'ProveedoresController',
        'except' => 'show'
    ]);
    $routes->post('proveedores/save', 'ProveedoresController::save');
    $routes->post('proveedores/getProveedores', 'ProveedoresController::getProveedores');
    $routes->post('proveedores/getProveedoresAjax', 'ProveedoresController::getProveedoresAjax');

Creamos el menú de proveedores tal cual se ve en la imagen

Creamos el permiso y lo asignamos al rol correspondiente

Y listo ya tenemos nuestro catalogo de proveedores

Video demostrativo

Creando CRUD de Series Electrónicas #10

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

<?php

namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class Seriesfacturaelectronica extends Migration {

    public function up() {
        // Seriesfacturaelectronica
        $this->forge->addField([
            'id' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
            'idEmpresa' => ['type' => 'bigint', 'constraint' => 20, 'null' => false],
            'sucursal' => ['type' => 'bigint', 'constraint' => 20, 'null' => false],
            'tipoSerie' => ['type' => 'varchar', 'constraint' => 16, 'null' => false],
            'serie' => ['type' => 'varchar', 'constraint' => 16, 'null' => false],
            'desdeFecha' => ['type' => 'date', 'null' => false],
            'hastaFecha' => ['type' => 'date', 'null' => false],
            'desdeFolio' => ['type' => 'bigint', 'constraint' => 20, 'null' => false],
            'hastaFolio' => ['type' => 'bigint', 'constraint' => 20, 'null' => false],
            'ambienteTimbrado' => ['type' => 'varchar', 'constraint' => 32, 'null' => false],
            'tokenPruebas' => ['type' => 'text', 'null' => false],
            'tokenProduccion' => ['type' => 'text', '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('seriesfacturaelectronica', true);
    }

    public function down() {
        $this->forge->dropTable('seriesfacturaelectronica', true);
    }

}

Creamos el archivo modelo App/Models/SeriesfacturaelectronicaModel.php para el acceso a la tabla

<?php

namespace App\Models;

use CodeIgniter\Model;

class SeriesfacturaelectronicaModel extends Model {

    protected $table = 'seriesfacturaelectronica';
    protected $primaryKey = 'id';
    protected $useAutoIncrement = true;
    protected $returnType = 'array';
    protected $useSoftDeletes = true;
    protected $allowedFields = ['id'
        , 'idEmpresa'
        , 'sucursal'
        , 'tipoSerie'
        , 'serie'
        , 'desdeFecha'
        , 'hastaFecha'
        , 'desdeFolio'
        , 'hastaFolio'
        , 'ambienteTimbrado'
        , 'tokenPruebas'
        , 'tokenProduccion'
        , '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 mdlGetSeriesfacturaelectronica($idEmpresas) {

        $result = $this->db->table('seriesfacturaelectronica a, empresas b, branchoffices c')
                ->select('a.id
                            ,a.idEmpresa
                            ,a.sucursal
                            ,a.tipoSerie
                            ,a.serie
                            ,a.desdeFecha
                            ,a.hastaFecha
                            ,a.desdeFolio
                            ,a.hastaFolio
                            ,a.ambienteTimbrado
                            ,a.tokenPruebas
                            ,a.tokenProduccion
                            ,a.created_at
                            ,a.updated_at
                            ,a.deleted_at 
                            ,b.nombre as nombreEmpresa
                            ,c.name as nombreSucursal
                            ')
                ->where('a.idEmpresa', 'b.id', FALSE)
                ->where('a.sucursal', 'c.id', FALSE)
                ->whereIn('a.idEmpresa', $idEmpresas);

        return $result;
    }

}

Creamos el archivo controlador App/Controllers/SeriesfacturaelectronicaController.php

<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use \App\Models\{
    SeriesfacturaelectronicaModel
};
use App\Models\LogModel;
use CodeIgniter\API\ResponseTrait;
use App\Models\EmpresasModel;
use App\Models\BranchofficesModel;

class SeriesfacturaelectronicaController extends BaseController {

    use ResponseTrait;

    protected $log;
    protected $seriesfacturaelectronica;
    protected $sucursales;

    public function __construct() {
        $this->seriesfacturaelectronica = new SeriesfacturaelectronicaModel();
        $this->log = new LogModel();
        $this->empresa = new EmpresasModel();
        $this->sucursales = new BranchofficesModel();
                
        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->seriesfacturaelectronica->mdlGetSeriesfacturaelectronica($empresasID);

            return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
        }
        $titulos["title"] = lang('seriesfacturaelectronica.title');
        $titulos["subtitle"] = lang('seriesfacturaelectronica.subtitle');
        return view('seriesfacturaelectronica', $titulos);
    }

    /**
     * Read Seriesfacturaelectronica
     */
    public function getSeriesfacturaelectronica() {

        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");
        }


        $idSeriesfacturaelectronica = $this->request->getPost("idSeriesfacturaelectronica");
        $datosSeriesfacturaelectronica = $this->seriesfacturaelectronica->whereIn('idEmpresa', $empresasID)
                        ->where("id", $idSeriesfacturaelectronica)->first();
        
        $datosSucursal = $this->sucursales->select("*")->where("id",$datosSeriesfacturaelectronica["sucursal"])->first();
        
        if($datosSucursal["name"]!=null){
            
            $datosSeriesfacturaelectronica["nombreSucursal"] = $datosSucursal["name"];
            
        }else{
            
            $datosSucursal["name"] =""; 
            
        }
        
        
        echo json_encode($datosSeriesfacturaelectronica);
    }

    /**
     * Save or update Seriesfacturaelectronica
     */
    public function save() {
        helper('auth');
        $userName = user()->username;
        $idUser = user()->id;
        $datos = $this->request->getPost();
        if ($datos["idSeriesfacturaelectronica"] == 0) {
            try {
                if ($this->seriesfacturaelectronica->save($datos) === false) {
                    $errores = $this->seriesfacturaelectronica->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->seriesfacturaelectronica->update($datos["idSeriesfacturaelectronica"], $datos) == false) {
                $errores = $this->seriesfacturaelectronica->errors();
                foreach ($errores as $field => $error) {
                    echo $error . " ";
                }
                return;
            } else {
                $dateLog["description"] = lang("seriesfacturaelectronica.logUpdated") . json_encode($datos);
                $dateLog["user"] = $userName;
                $this->log->save($dateLog);
                echo "Actualizado Correctamente";
                return;
            }
        }
        return;
    }

    /**
     * Delete Seriesfacturaelectronica
     * @param type $id
     * @return type
     */
    public function delete($id) {
        $infoSeriesfacturaelectronica = $this->seriesfacturaelectronica->find($id);
        helper('auth');
        $userName = user()->username;
        if (!$found = $this->seriesfacturaelectronica->delete($id)) {
            return $this->failNotFound(lang('seriesfacturaelectronica.msg.msg_get_fail'));
        }
        $this->seriesfacturaelectronica->purgeDeleted();
        $logData["description"] = lang("seriesfacturaelectronica.logDeleted") . json_encode($infoSeriesfacturaelectronica);
        $logData["user"] = $userName;
        $this->log->save($logData);
        return $this->respondDeleted($found, lang('seriesfacturaelectronica.msg_delete'));
    }

}

Para los archivos de la vista ya se la saben, es un archivo principal en el que incluimos los archivos secundarios

Creamos el archivo principal App/Views/seriesfacturaelectronica.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('modulesSeriesfacturaelectronica/modalCaptureSeriesfacturaelectronica') ?>

<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
    <div class="card-header">
        <div class="float-right">
            <div class="btn-group">

                <button class="btn btn-primary btnAddSeriesfacturaelectronica" data-toggle="modal" data-target="#modalAddSeriesfacturaelectronica"><i class="fa fa-plus"></i>

                    <?= lang('seriesfacturaelectronica.add') ?>

                </button>

            </div>
        </div>
    </div>
    <div class="card-body">
        <div class="row">
            <div class="col-md-12">
                <div class="table-responsive">
                    <table id="tableSeriesfacturaelectronica" class="table table-striped table-hover va-middle tableSeriesfacturaelectronica">
                        <thead>
                            <tr>

                                <th>#</th>
                                <th><?= lang('seriesfacturaelectronica.fields.empresa') ?></th>
                                <th><?= lang('seriesfacturaelectronica.fields.sucursal') ?></th>
                                <th>Tipo Serie</th>
                                <th><?= lang('seriesfacturaelectronica.fields.desdeFecha') ?></th>
                                <th><?= lang('seriesfacturaelectronica.fields.hastaFecha') ?></th>
                                <th><?= lang('seriesfacturaelectronica.fields.desdeFolio') ?></th>
                                <th><?= lang('seriesfacturaelectronica.fields.ambienteTimbrado') ?></th>
                                <th><?= lang('seriesfacturaelectronica.fields.tokenPruebas') ?></th>
                                <th><?= lang('seriesfacturaelectronica.fields.tokenProduccion') ?></th>
                                <th><?= lang('seriesfacturaelectronica.fields.created_at') ?></th>
                                <th><?= lang('seriesfacturaelectronica.fields.updated_at') ?></th>
                                <th><?= lang('seriesfacturaelectronica.fields.deleted_at') ?></th>

                                <th><?= lang('seriesfacturaelectronica.fields.actions') ?> </th>

                            </tr>
                        </thead>
                        <tbody>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- /.card -->

<?= $this->endSection() ?>


<?= $this->section('js') ?>
<script>

    /**
     * Cargamos la tabla
     */

    var tableSeriesfacturaelectronica = $('#tableSeriesfacturaelectronica').DataTable({
        processing: true,
        serverSide: true,
        responsive: true,
        autoWidth: false,
        order: [[1, 'asc']],

        ajax: {
            url: '<?= base_url('admin/seriesfacturaelectronica') ?>',
            method: 'GET',
            dataType: "json"
        },
        columnDefs: [{
                orderable: false,
                targets: [12],
                searchable: false,
                targets: [12]

            }],
        columns: [{
                'data': 'id'
            },

            {
                'data': 'nombreEmpresa'
            },

            {
                'data': 'nombreSucursal'
            },

            {
                'data': 'tipoSerie'
            },

            {
                'data': 'desdeFecha'
            },

            {
                'data': 'hastaFecha'
            },

            {
                'data': 'desdeFolio'
            },

            {
                'data': 'ambienteTimbrado'
            },

            {
                'data': 'tokenPruebas'
            },

            {
                'data': 'tokenProduccion'
            },

            {
                'data': 'created_at'
            },

            {
                'data': 'updated_at'
            },

            {
                'data': 'deleted_at'
            },

            {
                "data": function (data) {
                    return `<td class="text-right py-0 align-middle">
                         <div class="btn-group btn-group-sm">
                             <button class="btn btn-warning btnEditSeriesfacturaelectronica" data-toggle="modal" idSeriesfacturaelectronica="${data.id}" data-target="#modalAddSeriesfacturaelectronica">  <i class=" fa fa-edit"></i></button>
                             <button class="btn btn-danger btn-delete" data-id="${data.id}"><i class="fas fa-trash"></i></button>
                         </div>
                         </td>`
                }
            }
        ]
    });



    $(document).on('click', '#btnSaveSeriesfacturaelectronica', function (e) {


        var idSeriesfacturaelectronica = $("#idSeriesfacturaelectronica").val();
        var empresa = $("#empresa").val();
        var sucursal = $("#sucursal").val();
        var tipoSerie = $("#tipoSerie").val();
        var serie = $("#serie").val();
        var desdeFecha = $("#desdeFecha").val();
        var hastaFecha = $("#hastaFecha").val();
        var desdeFolio = $("#desdeFolio").val();
        var hastaFolio = $("#hastaFolio").val();

        if ($("#ambienteTimbrado").is(':checked')) {

            var ambienteTimbrado = "on";

        } else {

            var ambienteTimbrado = "off";

        }

        var tokenPruebas = $("#tokenPruebas").val();
        var tokenProduccion = $("#tokenProduccion").val();


        $("#btnSaveSeriesfacturaelectronica").attr("disabled", true);

        var datos = new FormData();
        datos.append("idSeriesfacturaelectronica", idSeriesfacturaelectronica);
        datos.append("idEmpresa", empresa);
        datos.append("sucursal", sucursal);
        datos.append("tipoSerie", tipoSerie);
        datos.append("serie", serie);
        datos.append("desdeFecha", desdeFecha);
        datos.append("hastaFecha", hastaFecha);
        datos.append("desdeFolio", desdeFolio);
        datos.append("hastaFolio", hastaFolio);
        datos.append("ambienteTimbrado", ambienteTimbrado);
        datos.append("tokenPruebas", tokenPruebas);
        datos.append("tokenProduccion", tokenProduccion);


        $.ajax({

            url: "<?= base_url('admin/seriesfacturaelectronica/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"
                    });

                    tableSeriesfacturaelectronica.ajax.reload();
                    $("#btnSaveSeriesfacturaelectronica").removeAttr("disabled");


                    $('#modalAddSeriesfacturaelectronica').modal('hide');
                } else {

                    Toast.fire({
                        icon: 'error',
                        title: respuesta
                    });

                    $("#btnSaveSeriesfacturaelectronica").removeAttr("disabled");


                }

            }

        }

        )

    });



    /**
     * Carga datos actualizar
     */


    /*=============================================
     EDITAR Seriesfacturaelectronica
     =============================================*/
    $(".tableSeriesfacturaelectronica").on("click", ".btnEditSeriesfacturaelectronica", function () {

        var idSeriesfacturaelectronica = $(this).attr("idSeriesfacturaelectronica");

        var datos = new FormData();
        datos.append("idSeriesfacturaelectronica", idSeriesfacturaelectronica);

        $.ajax({

            url: "<?= base_url('admin/seriesfacturaelectronica/getSeriesfacturaelectronica') ?>",
            method: "POST",
            data: datos,
            cache: false,
            contentType: false,
            processData: false,
            dataType: "json",
            success: function (respuesta) {
                $("#idSeriesfacturaelectronica").val(respuesta["id"]);

                $("#empresa").val(respuesta["idEmpresa"]);

                var newOptionSucursal = new Option(respuesta["nombreSucursal"], respuesta["sucursal"], true, true);
                $('#sucursal').append(newOptionSucursal).trigger('change');
                $("#sucursal").val(respuesta["sucursal"]);


                $("#sucursal").val(respuesta["sucursal"]);
                $("#tipoSerie").val(respuesta["tipoSerie"]);
                $("#tipoSerie").trigger("change");
                $("#serie").val(respuesta["serie"]);
                $("#desdeFecha").val(respuesta["desdeFecha"]);
                $("#hastaFecha").val(respuesta["hastaFecha"]);
                $("#desdeFolio").val(respuesta["desdeFolio"]);
                $("#hastaFolio").val(respuesta["hastaFolio"]);

                $("#ambienteTimbrado").bootstrapToggle(respuesta["ambienteTimbrado"]);
                $("#tokenPruebas").val(respuesta["tokenPruebas"]);
                $("#tokenProduccion").val(respuesta["tokenProduccion"]);


            }

        })

    })


    /*=============================================
     ELIMINAR seriesfacturaelectronica
     =============================================*/
    $(".tableSeriesfacturaelectronica").on("click", ".btn-delete", function () {

        var idSeriesfacturaelectronica = $(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/seriesfacturaelectronica') ?>/` + idSeriesfacturaelectronica,
                            method: 'DELETE',
                        }).done((data, textStatus, jqXHR) => {
                            Toast.fire({
                                icon: 'success',
                                title: jqXHR.statusText,
                            });


                            tableSeriesfacturaelectronica.ajax.reload();
                        }).fail((error) => {
                            Toast.fire({
                                icon: 'error',
                                title: error.responseJSON.messages.error,
                            });
                        })
                    }
                })
    })

    $(function () {
        $("#modalAddSeriesfacturaelectronica").draggable();

    });


    $("#tipoSerie").select2();

</script>
<?= $this->endSection() ?>
        

En el archivo secundario App/Views/modulesSeriesfacturaelectronica/modalCaptureSeriesfacturaelectronica.php

<!-- Modal Seriesfacturaelectronica -->
<div class="modal fade" id="modalAddSeriesfacturaelectronica" tabindex="-1" role="dialog" aria-labelledby="modalAddSeriesfacturaelectronica" aria-hidden="true">
    <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title"><?= lang('seriesfacturaelectronica.createEdit') ?></h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                <form id="form-seriesfacturaelectronica" class="form-horizontal">
                    <input type="hidden" id="idSeriesfacturaelectronica" name="idSeriesfacturaelectronica" value="0">

                    <div class="form-group row">
                        <label for="emitidoRecibido" class="col-sm-2 col-form-label">Empresa</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 class="form-control empresa" name="empresa" id="empresa" style = "width:80%;">
                                    <option value="0">Seleccione empresa</option>
                                    <?php
                                    foreach ($empresas as $key => $value) {

                                        echo "<option value='$value[id]' selected>$value[id] - $value[nombre] </option>  ";
                                    }
                                    ?>

                                </select>

                            </div>
                        </div>
                    </div>

                    <div class="form-group row">
                        <label for="sucursal" class="col-sm-2 col-form-label">Sucursal</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 class="form-control sucursal" name="sucursal" id="sucursal" style = "width:80%;">
                                    <option value="0">Seleccione sucursal</option>


                                </select>

                            </div>
                        </div>
                    </div>


                    <div class="form-group row">
                        <label for="sucursal" class="col-sm-2 col-form-label">Tipo Serie</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 class="form-control tipoSerie" name="tipoSerie" id="tipoSerie" style = "width:80%;">
                                    <option value="ven">Venta</option>
                                    <option value="pag">Pago</option>
                                    <option value="dev">Devolución</option>
                                    <option value="bon">Bonificaciónn</option>

                                </select>

                            </div>
                        </div>
                    </div>


                    <div class="form-group row">
                        <label for="desdeFecha" class="col-sm-2 col-form-label"><?= lang('seriesfacturaelectronica.fields.desdeFecha') ?></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 type="date" name="desdeFecha" id="desdeFecha" class="form-control <?= session('error.desdeFecha') ? 'is-invalid' : '' ?>" value="<?= old('desdeFecha') ?>" placeholder="<?= lang('seriesfacturaelectronica.fields.desdeFecha') ?>" autocomplete="off">
                            </div>
                        </div>
                    </div>
                    <div class="form-group row">
                        <label for="hastaFecha" class="col-sm-2 col-form-label"><?= lang('seriesfacturaelectronica.fields.hastaFecha') ?></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 type="date" name="hastaFecha" id="hastaFecha" class="form-control <?= session('error.hastaFecha') ? 'is-invalid' : '' ?>" value="<?= old('hastaFecha') ?>" placeholder="<?= lang('seriesfacturaelectronica.fields.hastaFecha') ?>" autocomplete="off">
                            </div>
                        </div>
                    </div>

                    <div class="form-group row">
                        <label for="serie" class="col-sm-2 col-form-label">Serie</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 type="text" name="serie" id="serie" class="form-control <?= session('error.serie') ? 'is-invalid' : '' ?>" value="<?= old('desdeFolio') ?>" placeholder="Inserte serie" autocomplete="off">
                            </div>
                        </div>
                    </div>


                    <div class="form-group row">
                        <label for="desdeFolio" class="col-sm-2 col-form-label"><?= lang('seriesfacturaelectronica.fields.desdeFolio') ?></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 type="number" name="desdeFolio" id="desdeFolio" class="form-control <?= session('error.desdeFolio') ? 'is-invalid' : '' ?>" value="<?= old('desdeFolio') ?>" placeholder="<?= lang('seriesfacturaelectronica.fields.desdeFolio') ?>" autocomplete="off">
                            </div>
                        </div>
                    </div>

                    <div class="form-group row">
                        <label for="hastaFolio" class="col-sm-2 col-form-label">Hasta Folio</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 type="number" name="hastaFolio" id="hastaFolio" class="form-control <?= session('error.desdeFolio') ? 'is-invalid' : '' ?>" value="<?= old('hastaFolio') ?>" placeholder="Hasta Folio" autocomplete="off">
                            </div>
                        </div>
                    </div>
                    <div class="form-group row">
                        <label for="ambienteTimbrado" class="col-sm-2 col-form-label"><?= lang('seriesfacturaelectronica.fields.ambienteTimbrado') ?></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 type="checkbox" name="ambienteTimbrado" id="ambienteTimbrado" class="form-control " autocomplete="off" data-width="250" data-height="40" checked data-toggle="toggle" data-on="produccion" data-off="pruebas" data-onstyle="success" data-offstyle="danger">
                            </div>
                        </div>
                    </div>
                    <div class="form-group row">
                        <label for="tokenPruebas" class="col-sm-2 col-form-label"><?= lang('seriesfacturaelectronica.fields.tokenPruebas') ?></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 type="text" name="tokenPruebas" id="tokenPruebas" class="form-control <?= session('error.tokenPruebas') ? 'is-invalid' : '' ?>" value="<?= old('tokenPruebas') ?>" placeholder="<?= lang('seriesfacturaelectronica.fields.tokenPruebas') ?>" autocomplete="off">
                            </div>
                        </div>
                    </div>
                    <div class="form-group row">
                        <label for="tokenProduccion" class="col-sm-2 col-form-label"><?= lang('seriesfacturaelectronica.fields.tokenProduccion') ?></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 type="text" name="tokenProduccion" id="tokenProduccion" class="form-control <?= session('error.tokenProduccion') ? 'is-invalid' : '' ?>" value="<?= old('tokenProduccion') ?>" placeholder="<?= lang('seriesfacturaelectronica.fields.tokenProduccion') ?>" 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" id="btnSaveSeriesfacturaelectronica"><?= lang('boilerplate.global.save') ?></button>
            </div>
        </div>
    </div>
</div>

<?= $this->section('js') ?>


<script>

    $(document).on('click', '.btnAddSeriesfacturaelectronica', function (e) {


        $(".form-control").val("");

        $("#idSeriesfacturaelectronica").val("0");

        $("#empresa").val("0");
        $("#empresa").trigger("change");

        $("#ambienteTimbrado").bootstrapToggle("off");

        $("#btnSaveSeriesfacturaelectronica").removeAttr("disabled");

    });

    /* 
     * AL hacer click al editar
     */



    $(document).on('click', '.btnEditSeriesfacturaelectronica', function (e) {


        var idSeriesfacturaelectronica = $(this).attr("idSeriesfacturaelectronica");

        //LIMPIAMOS CONTROLES
        $(".form-control").val("");

        $("#idSeriesfacturaelectronica").val(idSeriesfacturaelectronica);
        $("#btnGuardarSeriesfacturaelectronica").removeAttr("disabled");

    });


    $("#empresa").select2();

    $("#empresa").trigger("change");



    $("#sucursal").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 = $('.empresa').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() ?>
        

En las rutas App/config/Routes.php dentro del grupo admin agregamos el siguiente código

    $routes->resource('seriesfacturaelectronica', [
        'filter' => 'permission:seriesfacturaelectronica-permission',
        'controller' => 'seriesfacturaelectronicaController',
        'except' => 'show'
    ]);
    $routes->post('seriesfacturaelectronica/save', 'SeriesfacturaelectronicaController::save');
    $routes->post('seriesfacturaelectronica/getSeriesfacturaelectronica', 'SeriesfacturaelectronicaController::getSeriesfacturaelectronica');

Creamos el menú para las series electrónicas con los siguientes datos

Y listo ya tenemos nuestro CRUD de Series Electronicas

Creando CRUD de clientes #06

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

Leer Mas: Creando CRUD de clientes #06
<?php
namespace App\Models;
use CodeIgniter\Model;
class CustumersModel extends Model{
    protected $table      = 'custumers';
    protected $primaryKey = 'id';
    protected $useAutoIncrement = true;
    protected $returnType     = 'array';
    protected $useSoftDeletes = true;
    protected $allowedFields = ['id','firstname','lastname','taxID','email','direction','birthdate','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 nuestro archivo controlador app/controllers/CustumersControllers.php

<?php
 namespace App\Controllers;
 use App\Controllers\BaseController;
 use \App\Models\{CustumersModel};
 use App\Models\LogModel;
 use CodeIgniter\API\ResponseTrait;
 class CustumersController extends BaseController {
     use ResponseTrait;
     protected $log;
     protected $custumers;
     public function __construct() {
         $this->custumers = new CustumersModel();
         $this->log = new LogModel();
         helper('menu');
         helper('utilerias');
     }
     public function index() {
         if ($this->request->isAJAX()) {
             $datos = $this->custumers->select('id,firstname,lastname,taxID,email,direction,birthdate,created_at,updated_at,deleted_at')->where('deleted_at', null);
             return \Hermawan\DataTables\DataTable::of($datos)->toJson(true);
         }


         $fechaActual =  fechaMySQLADateTimeHTML5(fechaHoraActual());

         $titulos["title"] = lang('custumers.title');
         $titulos["subtitle"] = lang('custumers.subtitle');
         $titulos["fecha"] = $fechaActual;
         return view('custumers', $titulos);
     }
     /**
      * Read Custumers
      */
     public function getCustumers() {
         $idCustumers = $this->request->getPost("idCustumers");
         $datosCustumers = $this->custumers->find($idCustumers);
         echo json_encode($datosCustumers);
     }
     /**
      * Save or update Custumers
      */
     public function save() {
         helper('auth');
         $userName = user()->username;
         $idUser = user()->id;
         $datos = $this->request->getPost();
         if ($datos["idCustumers"] == 0) {
             try {
                 if ($this->custumers->save($datos) === false) {
                     $errores = $this->custumers->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->custumers->update($datos["idCustumers"], $datos) == false) {
                 $errores = $this->custumers->errors();
                 foreach ($errores as $field => $error) {
                     echo $error . " ";
                 }
                 return;
             } else {
                 $dateLog["description"] = lang("custumers.logUpdated") . json_encode($datos);
                 $dateLog["user"] = $userName;
                 $this->log->save($dateLog);
                 echo "Actualizado Correctamente";
                 return;
             }
         }
         return;
     }
     /**
      * Delete Custumers
      * @param type $id
      * @return type
      */
     public function delete($id) {
         $infoCustumers = $this->custumers->find($id);
         helper('auth');
         $userName = user()->username;
         if (!$found = $this->custumers->delete($id)) {
             return $this->failNotFound(lang('custumers.msg.msg_get_fail'));
         }
         $this->custumers->purgeDeleted();
         $logData["description"] = lang("custumers.logDeleted") . json_encode($infoCustumers);
         $logData["user"] = $userName;
         $this->log->save($logData);
         return $this->respondDeleted($found, lang('custumers.msg_delete'));
     }
 }
        

Creamos nuestro archivo de la visa en app/views/custumers.php con el siguiente contenido

<?= $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('modulesCustumers/modalCaptureCustumers') ?>

<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
 <div class="card-header">
     <div class="float-right">
         <div class="btn-group">

             <button class="btn btn-primary btnAddCustumers" data-toggle="modal" data-target="#modalAddCustumers"><i class="fa fa-plus"></i>

                 <?= lang('custumers.add') ?>

             </button>

         </div>
     </div>
 </div>
 <div class="card-body">
     <div class="row">
         <div class="col-md-12">
             <div class="table-responsive">
                 <table id="tableCustumers" class="table table-striped table-hover va-middle tableCustumers">
                     <thead>
                         <tr>

                             <th>#</th>
                             <th><?= lang('custumers.fields.firstname') ?></th>
<th><?= lang('custumers.fields.lastname') ?></th>
<th><?= lang('custumers.fields.taxID') ?></th>
<th><?= lang('custumers.fields.email') ?></th>
<th><?= lang('custumers.fields.direction') ?></th>
<th><?= lang('custumers.fields.birthdate') ?></th>
<th><?= lang('custumers.fields.created_at') ?></th>
<th><?= lang('custumers.fields.updated_at') ?></th>
<th><?= lang('custumers.fields.deleted_at') ?></th>

                             <th><?= lang('custumers.fields.actions') ?> </th>

                         </tr>
                     </thead>
                     <tbody>
                     </tbody>
                 </table>
             </div>
         </div>
     </div>
 </div>
</div>
<!-- /.card -->

<?= $this->endSection() ?>


<?= $this->section('js') ?>
<script>

 /**
  * Cargamos la tabla
  */

 var tableCustumers = $('#tableCustumers').DataTable({
     processing: true,
     serverSide: true,
     responsive: true,
     autoWidth: false,
     order: [[1, 'asc']],

     ajax: {
         url: '<?= base_url(route_to('admin/custumers')) ?>',
         method: 'GET',
         dataType: "json"
     },
     columnDefs: [{
             orderable: false,
             targets: [10],
             searchable: false,
             targets: [10]

         }],
     columns: [{
             'data': 'id'
         },
        
          
{
    'data': 'firstname'
},
 
{
    'data': 'lastname'
},
 
{
    'data': 'taxID'
},
 
{
    'data': 'email'
},
 
{
    'data': 'direction'
},
 
{
    'data': 'birthdate'
},
 
{
    'data': 'created_at'
},
 
{
    'data': 'updated_at'
},
 
{
    'data': 'deleted_at'
},

         {
             "data": function (data) {
                 return `<td class="text-right py-0 align-middle">
                         <div class="btn-group btn-group-sm">
                             <button class="btn btn-warning btnEditCustumers" data-toggle="modal" idCustumers="${data.id}" data-target="#modalAddCustumers">  <i class=" fa fa-edit"></i></button>
                             <button class="btn btn-danger btn-delete" data-id="${data.id}"><i class="fas fa-trash"></i></button>
                         </div>
                         </td>`
             }
         }
     ]
 });



 $(document).on('click', '#btnSaveCustumers', function (e) {

     
var idCustumers = $("#idCustumers").val();
var firstname = $("#firstname").val();
var lastname = $("#lastname").val();
var taxID = $("#taxID").val();
var email = $("#email").val();
var direction = $("#direction").val();
var birthdate = $("#birthdate").val();

     $("#btnSaveCustumers").attr("disabled", true);

     var datos = new FormData();
    datos.append("idCustumers", idCustumers);
    datos.append("firstname", firstname);
    datos.append("lastname", lastname);
    datos.append("taxID", taxID);
    datos.append("email", email);
    datos.append("direction", direction);
    datos.append("birthdate", birthdate);


     $.ajax({

         url: "<?= route_to('admin/custumers/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"
                 });

                 tableCustumers.ajax.reload();
                 $("#btnSaveCustumers").removeAttr("disabled");


                 $('#modalAddCustumers').modal('hide');
             } else {

                 Toast.fire({
                     icon: 'error',
                     title: respuesta
                 });

                 $("#btnSaveCustumers").removeAttr("disabled");
                

             }

         }

     }

     )

 });



 /**
  * Carga datos actualizar
  */


 /*=============================================
  EDITAR Custumers
  =============================================*/
 $(".tableCustumers").on("click", ".btnEditCustumers", function () {

     var idCustumers = $(this).attr("idCustumers");
        
     var datos = new FormData();
     datos.append("idCustumers", idCustumers);

     $.ajax({

         url: "<?= base_url(route_to('admin/custumers/getCustumers')) ?>",
         method: "POST",
         data: datos,
         cache: false,
         contentType: false,
         processData: false,
         dataType: "json",
         success: function (respuesta) {
             $("#idCustumers").val(respuesta["id"]);
             
             $("#firstname").val(respuesta["firstname"]);
$("#lastname").val(respuesta["lastname"]);
$("#taxID").val(respuesta["taxID"]);
$("#email").val(respuesta["email"]);
$("#direction").val(respuesta["direction"]);
$("#birthdate").val(respuesta["birthdate"]);


         }

     })

 })


 /*=============================================
  ELIMINAR custumers
  =============================================*/
 $(".tableCustumers").on("click", ".btn-delete", function () {

     var idCustumers = $(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(route_to('admin/custumers')) ?>/` + idCustumers,
                         method: 'DELETE',
                     }).done((data, textStatus, jqXHR) => {
                         Toast.fire({
                             icon: 'success',
                             title: jqXHR.statusText,
                         });


                         tableCustumers.ajax.reload();
                     }).fail((error) => {
                         Toast.fire({
                             icon: 'error',
                             title: error.responseJSON.messages.error,
                         });
                     })
                 }
             })
 })

 $(function () {
    $("#modalAddCustumers").draggable();
    
});


</script>
<?= $this->endSection() ?>
        

Para el modal creamos el siguiente archivo app/views/modulesCustumers/modalCaptureCustumers.php con el siguiente contenido

<!-- Modal Custumers -->
  <div class="modal fade" id="modalAddCustumers" tabindex="-1" role="dialog" aria-labelledby="modalAddCustumers" aria-hidden="true">
      <div class="modal-dialog modal-lg" role="document">
          <div class="modal-content">
              <div class="modal-header">
                  <h5 class="modal-title"><?= lang('custumers.createEdit') ?></h5>
                  <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                      <span aria-hidden="true">&times;</span>
                  </button>
              </div>
              <div class="modal-body">
                  <form id="form-custumers" class="form-horizontal">
                      <input type="hidden" id="idCustumers" name="idCustumers" value="0">

                      <div class="form-group row">
    <label for="firstname" class="col-sm-2 col-form-label"><?= lang('custumers.fields.firstname') ?></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 type="text" name="firstname" id="firstname" class="form-control <?= session('error.firstname') ? 'is-invalid' : '' ?>" value="<?= old('firstname') ?>" placeholder="<?= lang('custumers.fields.firstname') ?>" autocomplete="off">
        </div>
    </div>
</div>
<div class="form-group row">
    <label for="lastname" class="col-sm-2 col-form-label"><?= lang('custumers.fields.lastname') ?></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 type="text" name="lastname" id="lastname" class="form-control <?= session('error.lastname') ? 'is-invalid' : '' ?>" value="<?= old('lastname') ?>" placeholder="<?= lang('custumers.fields.lastname') ?>" autocomplete="off">
        </div>
    </div>
</div>
<div class="form-group row">
    <label for="taxID" class="col-sm-2 col-form-label"><?= lang('custumers.fields.taxID') ?></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 type="text" name="taxID" id="taxID" class="form-control <?= session('error.taxID') ? 'is-invalid' : '' ?>" value="<?= old('taxID') ?>" placeholder="<?= lang('custumers.fields.taxID') ?>" autocomplete="off">
        </div>
    </div>
</div>
<div class="form-group row">
    <label for="email" class="col-sm-2 col-form-label"><?= lang('custumers.fields.email') ?></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 type="text" name="email" id="email" class="form-control <?= session('error.email') ? 'is-invalid' : '' ?>" value="<?= old('email') ?>" placeholder="<?= lang('custumers.fields.email') ?>" autocomplete="off">
        </div>
    </div>
</div>
<div class="form-group row">
    <label for="direction" class="col-sm-2 col-form-label"><?= lang('custumers.fields.direction') ?></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 type="text" name="direction" id="direction" class="form-control <?= session('error.direction') ? 'is-invalid' : '' ?>" value="<?= old('direction') ?>" placeholder="<?= lang('custumers.fields.direction') ?>" autocomplete="off">
        </div>
    </div>
</div>
<div class="form-group row">
    <label for="birthdate" class="col-sm-2 col-form-label"><?= lang('custumers.fields.birthdate') ?></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 type="datetime-local" name="birthdate" id="birthdate" class="form-control <?= session('error.birthdate') ? 'is-invalid' : '' ?>" value="<?= $fecha ?>" placeholder="<?= lang('custumers.fields.birthdate') ?>" 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" id="btnSaveCustumers"><?= lang('boilerplate.global.save') ?></button>
              </div>
          </div>
      </div>
  </div>

  <?= $this->section('js') ?>


  <script>

      $(document).on('click', '.btnAddCustumers', function (e) {


          $(".form-control").val("");

          $("#idCustumers").val("0");

          $("#birthdate").val("<?= $fecha ?>");

          $("#btnSaveCustumers").removeAttr("disabled");

      });

      /* 
       * AL hacer click al editar
       */



      $(document).on('click', '.btnEditCustumers', function (e) {


          var idCustumers = $(this).attr("idCustumers");

          //LIMPIAMOS CONTROLES
        $(".form-control").val("");

          $("#idCustumers").val(idCustumers);
          $("#btnGuardarCustumers").removeAttr("disabled");

      });




  </script>


  <?= $this->endSection() ?>
        

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

<?php
    namespace App\Database\Migrations;
    use CodeIgniter\Database\Migration;
    class Custumers extends Migration
    {
    public function up()
    {
     // Custumers
    $this->forge->addField([
        'id'                    => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
        'firstname'             => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
        'lastname'             => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
        'taxID'             => ['type' => 'varchar', 'constraint' => 64, 'null' => true],
        'email'             => ['type' => 'varchar', 'constraint' => 128, 'null' => true],
        'direction'             => ['type' => 'varchar', 'constraint' => 1024, 'null' => true],
        'birthdate'             => ['type' => 'datetime' , '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('custumers', true);
    }
    public function down(){
        $this->forge->dropTable('custumers', true);
        }
    }

Corremos el comando php serve migrate para levantar la tabla custumers

Listo ya solo queda configurar los permisos y menú

Demostración en video

CI4JCPOS Construyendo Menú #2

Ya tenemos la base del proyecto, ahora lo que sigue es darle forma creando los menús

Realmente aquí no hay nada complejo, el menú soporta 2 niveles, podemos escoger nuestro icono de font awesome le pones la ruta y que roles tendrán acceso a ese nivel, para acomodar el menú solo basta con arrastrar y soltar los items
Realmente aquí no hay nada complejo, el menú soporta 2 niveles, podemos escoger nuestro icono de font awesome le pones la ruta y que roles tendrán acceso a ese nivel, para acomodar el menú solo basta con arrastrar y soltar los items
Video Demostrativo

JCPOS Ultimate – Nuevo Repositorio #1

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!

Agregando derecho para que permita ver stock al hacer la venta JCPOS2022

Uno de los cambios que no han estado solicitando es que no todos los usuario puedan ver el stock, si no que si no tiene derecho que solo vea el color por si esta bajo en existencia así que empezando

Primero que nada empezamos agregando el cambio del derecho en la base de datos para ello ejecutamos el siguiente comando en la base de datos

alter table perfiles add permiteVerStockVentas  varchar(5) null

CAMBIOS PUNTO DE VENTA JCPOS 2021 ARQUEO DE CAJA

Se han hecho algunos cambios significativos al arqueo de caja y son los siguientes

Se agrego una opción en datos empresa para especificar si se va usar el arqueo se caja, en caso de que no este activado se podrá realizar una venta aunque no este abierta una caja

En configuración ->Datos empresa definimos si se validara el arqueo de caja

En arqueo de caja se agrego para poder escoger con que usuario/vendedor se abrirá la caja, antes solo se podía abrir con el usuario con el que se inicio sesión

De lado izquierdo vemos como abrimos la caja con el usuario asd y en el centro vemos como podemos escoger con un combo el usuario/vendedor

En el fuente archivo configuración.php se agrego una constante llamada debug, lo ideal si tenemos el programa en XAMPP es que esa variable este como false, pero si queremos debugear directamente con PHP sin utilizar el archivo .htaccess debemos ponerlo en true

normalmente debe de estar como false

Se agrego el campo caja en datosempresa lo puede agregar con el siguiente código SQL

ALTER TABLE `datosempresa` ADD `caja` VARCHAR(5) NULL AFTER `diasEntrega`;

MAS CORRECCIONES Y AGRADECIMIENTOS 26

Saludos camaradas, en este vídeo se verán algunas correcciones al sistema así como un nuevo panel para los colaboradores Saludos y esperemos que les sirva

Ver demo en linea
http://pos.cesarsystems.com.mx/

Página 3 de 5

Creado con WordPress & Tema de Anders Norén