Anexsoft | Blog y dictado de cursos de Tecnología

En este encontrarás tutoriales de tecnología como PHP, ASP.NET MVC, Front-End, entre otros y cursos exigentes de modalidad online que te ayudarán a crecer profesionalmente.

Ejemplo de facturador con ASP.NET MVC
Actualizado el 21 Enero, 2016 y leído 15,037 veces
Calificación: 9.50 / 10

Ejemplo de facturador con ASP.NET MVC

Anexsoft

Como para finalizar el año les comparto este ejemplo de un facturador para ASP.NET MVC. Ideal para sus proyectos personales, aprender más o dominarlo para examen típico de trabajo.

En sí, no voy a explicar como desarrollar el facturador desde 0. Lo que voy hacer es darte un know-how de su desarrollo y ofrecerte el código de fuente para que lo puedas analizar. Lo he tratado de hacer lo más sencillo posible para que puedas entenderlo. Lo que si puedo hacer es ayudarte con las dudas que tengas.

¿En qué consiste el facturador?

El facturador es bastante sencillo, esta compuesto por 3 pantallas, una para visualizar, otra para el listado de todos los comprobantes registros y otra para registrar/adicionar un nuevo comprobante. Ahora vamos a enfocarnos en el registro de un nuevo comprobante que es la parte más fuerte del facturador.

 

El ViewModel se lleva el premio en el facturador

Como vieron en el diagrama de entidad relación mostrado anteriormente, la lógica es bastante sencilla. Lo que hice fue crear un ViewModel para el comprobante y el detalle. De esta manera sería más facil trabajar la vista de creación de un comprobante. Adicionalmente, a estos les agregue cierta lógica de negocio para que me calcule los montos, valide entre otros.

ComprobanteViewModel

public class ComprobanteViewModel {
    #region Cabecera
    public string Cliente { get; set; }
    public int CabeceraProductoId { get; set; }
    public string CabeceraProductoNombre { get; set; }
    public int CabeceraProductoCantidad { get; set; }
    public decimal CabeceraProductoPrecio { get; set; }
    #endregion

    #region Contenido
    public List<ComprobanteDetalleViewModel> ComprobanteDetalle { get; set; }
    #endregion

    #region Pie
    public decimal Total()
    {
        return ComprobanteDetalle.Sum(x => x.Monto());
    }
    public DateTime Creado { get; set; }
    #endregion

    public ComprobanteViewModel()
    {
        ComprobanteDetalle = new List<ComprobanteDetalleViewModel>();
        Refrescar();
    }

    public void Refrescar() {
        CabeceraProductoId = 0;
        CabeceraProductoNombre = null;
        CabeceraProductoCantidad = 1;
        CabeceraProductoPrecio = 0;
    }

    public bool SeAgregoUnProductoValido()
    {
        return !(CabeceraProductoId == 0 || string.IsNullOrEmpty(CabeceraProductoNombre) || CabeceraProductoCantidad == 0 || CabeceraProductoPrecio == 0);
    }

    public bool ExisteEnDetalle(int ProductoId)
    {
        return ComprobanteDetalle.Any(x => x.ProductoId == ProductoId);                        
    }

    public void RetirarItemDeDetalle() {
        if (ComprobanteDetalle.Count > 0)
        {
            var detalleARetirar = ComprobanteDetalle.Where(x => x.Retirar)
                                                    .SingleOrDefault();

            ComprobanteDetalle.Remove(detalleARetirar);
        }
    }

    public void AgregarItemADetalle()
    {
        ComprobanteDetalle.Add(new ComprobanteDetalleViewModel
        {
            ProductoId = CabeceraProductoId,
            ProductoNombre = CabeceraProductoNombre,
            PrecioUnitario = CabeceraProductoPrecio,
            Cantidad = CabeceraProductoCantidad,
        });

        Refrescar();
    }

    public Comprobante ToModel()
    {
        var comprobante = new Comprobante();
        comprobante.Cliente = this.Cliente;
        comprobante.Creado = DateTime.Now;
        comprobante.Total = this.Total();

        foreach(var d in ComprobanteDetalle)
        {
            comprobante.ComprobanteDetalle.Add(new ComprobanteDetalle {
                ProductoId = d.ProductoId,
                Monto = d.Monto(),
                PrecioUnitario = d.PrecioUnitario,
                Cantidad = d.Cantidad
            });
        }

        return comprobante;
    }
}

NOTA: este contiene un método llamado refrescar, su finalidad es que luego de agregar el detalle al comprobante limpiara los campos que contiene la información del producto a agregar. Finalmente, no me salía con este, así que declaré un script con jQuery para limpiar dichos campos cada vez que se refresca el formulario.

ComprobanteDetalleViewModel

public partial class ComprobanteDetalleViewModel
{
    public int ProductoId { get; set; }
    public string ProductoNombre { get; set; }
    public int Cantidad { get; set; }
    public decimal PrecioUnitario { get; set; }
    public bool Retirar { get; set; }
    public decimal Monto()
    {
        return Cantidad * PrecioUnitario;
    }
}

NOTA: la propeidad Retirar, si es TRUE la remueve del detalle del facturador. Esto lo usamo cuando presionamos en el detalle del comprobante el botón de eliminar detalle.

Vista de creación de un comprobante

En la vista maquetamos todo lo que necesitamos para crear un comprobante y metemos todo dentro de etiquetas formulario que apunta a la acción de mi contralador que va realizar toda la lógica.

¿Si todo está dentro de un formulario, como haces para agregar/retirar el detalle y generar el comprobante?

Lo que hice fue, a cada botón de mi formulario agregarle un value. Gracias a este, desde mi controlador hago un "IF" para ver que acción estamos realizando.

Agregar producto

<button class="btn btn-primary" type="submit" value="agregar_producto" name="action">
    <i class="glyphicon glyphicon-plus"></i>
</button>

 

Retirar producto

<button class="btn btn-danger btn-xs btn-block btn-retirar" type="submit" value="retirar_producto" name="action">
    <i class="glyphicon glyphicon-remove"></i>
</button>

NOTA: mediante jQuery declaramos un evento para antes del postback, setee el valor Retirar del modelo a True.

$(".btn-retirar").click(function () {
    if (confirm('¿Está seguro de retirar el item seleccionado?')) {
        $(this).closest('.list-group-item').find('.retirar').val("True");
        return true;
    }

    return false;
})

Generar comprobante

<button class="btn btn-primary btn-block btn-lg" type="submit" value="generar" name="action">Generar comprobante</button>

Nota: como pueden ver, todos los botones son del tipo Submit. Cada vez que hago click en uno de ellos envía un valor diferente al controlador, este valor llega como la variable action.

 

El controlador

Como mencioné, la acción de mi controlador espera el valor seteado en la variable action y luego realzará la lógica respectiva en base a la condición que coincida.

[HttpPost]
public ActionResult Registrar(ComprobanteViewModel model, string action)
{
    if (action == "generar")
    {
        if (!string.IsNullOrEmpty(model.Cliente))
        {
            if (cl.Registrar(model.ToModel()))
            {
                return Redirect("~/");
            }
        }
        else {
            ModelState.AddModelError("cliente", "Debe agregar un cliente para el comprobante");
        }
    }
    else if (action == "agregar_producto")
    {
        // Si no ha pasado nuestra validación, mostramos el mensaje personalizado de error
        if (!model.SeAgregoUnProductoValido())
        {
            ModelState.AddModelError("producto_agregar", "Solo puede agregar un producto válido al detalle");
        }
        else if (model.ExisteEnDetalle(model.CabeceraProductoId))
        {
            ModelState.AddModelError("producto_agregar", "El producto elegido ya existe en el detalle");
        }
        else
        {
            model.AgregarItemADetalle();
        }
    }
    else if (action == "retirar_producto")
    {
        model.RetirarItemDeDetalle();
    }
    else {
        throw new Exception("Acción no definida ..");
    }

    return View(model);
}

Si se dan cuenta, neustro ViewModel ComprobanteViewModel, ya implementa toda la lógica necesaria para que interactue con el usuario y pueda generar el comprobante.

 

En resumen

Vamos jugando con el ViewModel del comprobante para mostrar la información al usuario y al final cuando damos en generar, nuestro ComprobanteViewModel tiene un método para generar nuestra entidad Comprobante + su detalle (el que hace referencia a nuestras tablas) y este lo guardamos en la base de datos usando Entity Framework.

 

Bien, les comparto el GitHub para que puedan descargar el facturador y darle un vistazo. Si tienen duda me la dejan como comentario.

PD: no voy agregar funcionalidades adicionales, al menos que paguen :p jeje.

Saludos y feliz año :)

¡Adquiera ya!

  • Software de Venta e Inventario hecho en PHP y Codeigniter

    Software de Venta e Inventario hecho en PHP y Codeigniter
  • Código de fuente de Red Social desarrollada en ASP.NET MVC

    Código de fuente de Red Social desarrollada en ASP.NET MVC
  • Software de Portafolio Profesional hecho en ASP.NET MVC 5 C#

    Software de Portafolio Profesional hecho en ASP.NET MVC 5 C#

Últimas publicaciones

Encuesta

¿Cómo nos conociste?

Síguenos

Estudia con nosotros y crece profesionalmente

Nuestros cursos han sido hecho en base a lo que demanda el mercado hoy en día.
La experiencia obtenida es la de un ambiente laboral.

Anexsoft
© 2017 Anexsoft, blog y cursos online de TI.