Creacin de un sistema de almacn con C# (Parte 1)Creacin del Proyecto
Nuestro proyecto lo realizaremos con Visual Studio 2010.
Tambin puede utilizarse Visual C# 2010 Express el cual puede descargarse desde la pgina: http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-csharp-express
1. Creamos un nuevo proyecto:
2. Eliminamos el formulario y la clase:
3. Agregamos varias carpetas las cuales nos servirn para organizar nuestro proyecto:
4. Ahora agregamos cinco formularios y una clase, as como se muestra en la figura:
Nota: Por favor ignorar la carpeta llamada "Turorial", es la que estoy utilizando para generar este documento.Una vez hecho esto, continuaremos con el diseo de la base de datos
Creacin de un sistema de almacn con C# (Parte 2)Creacin de la Base de datos
Creamos una base de datos con Microsoft Access, con las siguientes tablas:users
Nombre del CampoTipo de DatosDescripcin
user_loginTexto(50)Nombre de inicio de sesin
user_passwordTexto(255)Contrasea del usuario
nombreTexto(255)Nombre del usuario
activoSi/NoSi est activo
administrarSi/NoSi puede administrar el sistema
reportesSi/NoSi puede ver reportes
articulos
Nombre del CampoTipo de DatosDescripcin
id_articuloTexto(50)Id del artculo
articuloTexto(255)Nombre del artculo
localizacionTexto(255)Ubicacin en el almacn
grupoTexto(255)Grupo del articulo
unidad_medidaTexto(255)Unidad de medida
existenciaNmero(Doble)Existencia
cant_minNmero(Doble)Existencia mnima
costo_promedioNmero(Doble)Costo promedio
entradas
Nombre del CampoTipo de DatosDescripcin
id_entradaAutonumricoId de la entrada
fecha_registroFecha/HoraFecha de registro en el sistema
fecha_entradaFecha/HoraFecha de la entrada en el almacen
proveedorTexto(255)Nombre del proveedor
folio_facturaTexto(50)Folio de la factura de compra
fecha_facturaFecha/HoraFecha de la factura
user_loginTexto(50)Usuario que registra la entrada
entradas_detalle
Nombre del CampoTipo de DatosDescripcin
id_entrada_detalleAutonumricoId del detalle de la entrada
id_entradaNmeroId de la entrada
id_articuloTexto(50)Id del artculo
cantidadNmero(Doble)Cantidad que entra al almacn
precio_compraNmero(Doble)Precio de compra (segun factura)
ivaNmero(Doble)Impuesto que cobra el proveedor (en porcentaje)
salidas
Nombre del CampoTipo de DatosDescripcin
id_salidaAutonumricoId de la salida
fecha_registroFecha/HoraFecha de registro en el sistema
fecha_salidaFecha/HoraFecha de la salida
responsableTexto(255)Responsable de la salida
user_loginTexto(50)Usuario que registra la salida
salidas_detalle
Nombre del CampoTipo de DatosDescripcin
id_salida_detalleAutonumricoId del detalle de la salida
id_salidaNmeroId de la salida
id_articuloTexto(50)Id del artculo
cantidadNmero(Doble)Cantidad que sale
Una vez que diseamos nuestras tablas, las relacionamos. Las relaciones deben de quedar as:
Especificaciones tcnicas: Todos los nombres de los campos son con minsculas. Esto no afecta en la programacin, pero deseamos poder llevar un estndar en todo lo que vayamos desarrollando. Deber respetar los tipos de datos, eso nos evitar posibles errores en tiempo de ejecucin.
Entradas al AlmacnDiseo de la pantallaEmpezaremos diseando la pantalla de entradas (formulario frmEntrada), la apariencia debe de quedar mas o menos as:
A continuacion una tabla descriptiva con los nombres de los objetos:ObjetoPropiedadValor
LabelNamelblFechaEntrada
TextFecha Entrada:
DateTimePickerNamedtpFechaEntrada
FormatCustom
CustomFormatdd/MM/yyyy
LabelNamelblFechaFactura
TextFecha Factura:
DateTimePickerNamedtpFechaFactura
FormatCustom
CustomFormatdd/MM/yyyy
LabelNamelblFolioFactura
TextFolio Factura:
TextBoxNametxtFolioFactura
LabelNamelblNombreProveedor
TextNombre del Proveedor:
TextBoxNametxtNombreProveedor
LabelNamelblIdArticulo
TextArticulo:
TextBoxNametxtIdArticulo
LabelNamelblCantidad
TextCantidad:
TextBoxNametxtCantidad
LabelNamelblPrecioCompra
TextPrecio:
TextBoxNametxtPrecioCompra
ButtonNamebtnAgregar
TextAgregar
ButtonNamebtnGrabar
TextGrabar
ButtonNamebtnCancelar
TextCancelar
ListViewNamelvEntrada
FullRowSelectTrue
GridLinesTrue
HideSelectionFalse
ProgramacinLa parte de la programacin es la mas enredada. Voy a considerar que el lector es un novato con nociones bastantebsicas e insuficientes como para comprender la estructura de la programacin C#. Recomiendo al lector poner mucha atencina los pasos que aqui se describan y no omitir nada, leer y re-leer hasta que haya comprendido lo que tiene que hacer.Comprendiendo el cdigo de un formulario C#Con mucho cuidado haremos doble clic sobre el formulario asegurndonos de no tocar con el puntero del mouse ningun objeto. Veremos un cdigomuy parecido al siguiente:using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;
namespace almacen.Formularios{ public partial class frmEntrada : Form { public frmEntrada() { InitializeComponent(); }
private void frmEntrada_Load(object sender, EventArgs e) {
} }}
A continuacin incluir comentarios en esta misma porcin de cdigo con la finalidad de que podamos identificar claramente su organizacin:/** * Aqui se agrupan los espacios de nombres * Son necesarios para facilitarnos el acceso * a ciertas librerias o DLLs */using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;//Aqui inicia nuestro espacio de nombresnamespace almacen.Formularios{ //aqui inicia la clase public partial class frmEntrada : Form { //este es el constructor predeterminado public frmEntrada() { InitializeComponent(); } //Aqui declararemos nuestras variables private void frmEntrada_Load(object sender, EventArgs e) { /** * Aqui incia la ejecucin del Formulario */ } //Aqui se ubican los procedimientos y funciones } //Fin de la clase, normalmente no se utiliza}/** * Fin del Espacio de Nombres * Este espacio no lo utilizaremos, * normalmente no se utiliza */
As se organiza el cdigo de un formulario C#. Debemos notar que todo inicia y termina con las llaves { }, existen algunos casos en los quepuede omitirse el uso de las llaves, principalmente en las estructuras de desicin if, peropara este tutorial, me asegurar de escribir tanto mucho o tanto poco (mucho o poco) cdigo segun sea necesario para evitar confusiones.Ahora comenzaremos a programar, iniciamos nuestra tarea declarando todas las variables que vamos a utilizar.En la zona de declaraciones, declaramos las siguientes variables:DataTable tmpEntrada = new DataTable();string CnnStr = @" Provider=Microsoft.Jet.OLEDB.4.0; "+ "Data Source=D:\\DOCS\\tyrodeveloper\\almacen.mdb; "+ "Jet OLEDB:Database Password=; Persist Security Info=False;";
Ahora escribiremos el cdigo de las funciones y procedimientos:void generaColumnas(){ lvEntrada.Clear(); lvEntrada.View = View.Details; lvEntrada.Columns.Add("", 0, HorizontalAlignment.Left); lvEntrada.Columns.Add("Id ", 100, HorizontalAlignment.Left); lvEntrada.Columns.Add("Producto", 240, HorizontalAlignment.Left); lvEntrada.Columns.Add("Cantidad", 60, HorizontalAlignment.Right); lvEntrada.Columns.Add("Precio", 60, HorizontalAlignment.Right); lvEntrada.Columns.Add("Total", 80, HorizontalAlignment.Right);}void mostrarEntrada(){ try { double varIVA = 0; double varTOTAL = 0; lvEntrada.Items.Clear(); for (int i = 0; i < tmpEntrada.Rows.Count; i++) { lvEntrada.Items.Add(tmpEntrada.Rows[i]["id"].ToString()); lvEntrada.Items[i].SubItems.Add(tmpEntrada.Rows[i]["id_articulo"].ToString()); lvEntrada.Items[i].SubItems.Add(tmpEntrada.Rows[i]["articulo"].ToString()); lvEntrada.Items[i].SubItems.Add(String.Format("{0:N}", Convert.ToDouble(tmpEntrada.Rows[i]["cantidad"]))); lvEntrada.Items[i].SubItems.Add(String.Format("{0:C}", Convert.ToDouble(tmpEntrada.Rows[i]["precio_compra"]))); lvEntrada.Items[i].SubItems.Add(String.Format("{0:C}", (Convert.ToDouble(tmpEntrada.Rows[i]["precio_compra"]) * Convert.ToDouble(tmpEntrada.Rows[i]["cantidad"])))); varTOTAL += Convert.ToDouble(tmpEntrada.Rows[i]["precio_compra"]) * Convert.ToDouble(tmpEntrada.Rows[i]["cantidad"]); varIVA += (Convert.ToDouble(tmpEntrada.Rows[i]["cantidad"]) * Convert.ToDouble(tmpEntrada.Rows[i]["precio_compra"])) - ((Convert.ToDouble(tmpEntrada.Rows[i]["cantidad"]) * Convert.ToDouble(tmpEntrada.Rows[i]["precio_compra"])) / (1.16)); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); }}bool agregarArticulo(string prmId, double prmCantidad, double prmPrecioCompra, double prmIVA){ try { string varId = ""; string varNombre = ""; OleDbConnection cnn = new OleDbConnection(CnnStr); cnn.Open(); string strSQL="select articulo from articulos "+ "where id_articulo='"+ prmId +"'"; OleDbCommand cmd = new OleDbCommand(strSQL, cnn); OleDbDataReader dr = cmd.ExecuteReader(); if (dr.Read()) { varId = prmId; varNombre = dr["articulo"].ToString(); ; //agregamos la venta a la tabla temporal DataRow row = tmpEntrada.NewRow(); row["id_articulo"] = varId; row["articulo"] = varNombre; row["cantidad"] = prmCantidad; row["precio_compra"] = prmPrecioCompra; row["iva"] = prmIVA; tmpEntrada.Rows.Add(row); } else { MessageBox.Show("El articulo no existe", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return (false); } dr.Close(); cnn.Close();
return (true); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return (false); }}bool grabarEntrada(string prmFechaEntrada, string prmFechaFactura, string prmFolioFactura, string prmNombreProveedor, string prmUserLogin){ try { OleDbConnection cnn = new OleDbConnection(CnnStr); cnn.Open(); OleDbTransaction tran = cnn.BeginTransaction(); OleDbCommand cmd = new OleDbCommand(); cmd.Connection = cnn; cmd.Transaction = tran; //insertamos el registro de la Entrada try { cmd.CommandText = "insert into entradas(fecha_entrada,fecha_factura,folio_factura,proveedor,user_login) " + " values (#" + prmFechaEntrada + "#,#" + prmFechaFactura + "#,'" + prmFolioFactura + "','" + prmNombreProveedor + "','" + prmUserLogin + "')"; cmd.ExecuteNonQuery(); //obtenemos el folio int _FolioEntrada = 0; cmd.CommandText = "select @@identity"; _FolioEntrada = Convert.ToInt32(cmd.ExecuteScalar()); //insertamos el detalle de laentrada for (int i = 0; i < tmpEntrada.Rows.Count; i++) { string _IdArticulo = Convert.ToString(tmpEntrada.Rows[i]["id_articulo"]); double _Cantidad = Convert.ToDouble(tmpEntrada.Rows[i]["cantidad"]); double _IVA = Convert.ToDouble(tmpEntrada.Rows[i]["iva"]); double _PrecioCompra = Convert.ToDouble(tmpEntrada.Rows[i]["precio_compra"]); double _CostoPromedio = 0; //insertamos el articulo cmd.CommandText = "insert into entradas_detalle(id_entrada,id_articulo,cantidad,precio_compra,iva) " + "values(" + _FolioEntrada + ",'" + _IdArticulo + "'," + _Cantidad + "," + _PrecioCompra + "," + _IVA + ")"; cmd.ExecuteNonQuery(); //actualizamosexistencias cmd.CommandText = "update articulos set " + " existencia=existencia + " + _Cantidad + "" + " where id_articulo='" + _IdArticulo + "'"; cmd.ExecuteNonQuery(); //establecemos el costo promedio cmd.CommandText = "select avg(precio_compra) " + " from entradas_detalle " + " where id_articulo='" + _IdArticulo + "'"; _CostoPromedio = Convert.ToDouble(cmd.ExecuteScalar()); cmd.CommandText = "update articulos set " + " costo_promedio=" + _CostoPromedio + "" + " where id_articulo='" + _IdArticulo + "'"; cmd.ExecuteNonQuery(); } //finalizamos la transaccion tran.Commit(); cnn.Close(); MessageBox.Show("Entrada grabada correctamente", "Informacin del Sistema", MessageBoxButtons.OK, MessageBoxIcon.Information); return (true); } catch (OleDbException errEntrada) { tran.Rollback(); cnn.Close(); MessageBox.Show(errEntrada.Message); return (false); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return (false); }}
Ahora damos doble clic sobre el botn Agregar (btnAgregar) y escribimos el siguiente cdigo:try { if (agregarArticulo(txtIdArticulo.Text, Convert.ToDouble(txtCantidad.Text), Convert.ToDouble(txtPrecioCompra.Text), 0.16)) { mostrarEntrada(); }}catch (Exception ex) { MessageBox.Show(ex.Message);}
Ahora, agregaremos el cdigo para grabar la entrada, hacemos doble clic sobre el botn Grabar (btnGrabar) y escribimos el siguiente cdigo:if (grabarEntrada(dtpFechaEntrada.Value.ToShortDateString(), dtpFechaFactura.Value.ToShortDateString(), txtFolioFactura.Text, txtNombreProveedor.Text,"admin")) { this.Close();}
El cdigo que pondremos en el Form_Load es el siguiente://>Definimos la tabla para las ventas TemporalesDataColumn idColumn = new DataColumn("id", typeof(int));idColumn.Unique = true;idColumn.AutoIncrement = true;idColumn.AutoIncrementSeed = 1;idColumn.AutoIncrementStep = 1;tmpEntrada.Columns.Add(idColumn);//declaramos el resto de los campostmpEntrada.Columns.Add("id_articulo", typeof(string));tmpEntrada.Columns.Add("articulo", typeof(string));tmpEntrada.Columns.Add("cantidad", typeof(Double));tmpEntrada.Columns.Add("precio_compra", typeof(Double));tmpEntrada.Columns.Add("iva", typeof(Double));//agregamos un primary keytmpEntrada.PrimaryKey = new DataColumn[] { tmpEntrada.Columns["id"] };//= prmCantidad) { //agregamos la venta a la tabla temporal DataRow row = tmpEntrada.NewRow(); row["id_articulo"] = varId; row["articulo"] = varNombre; row["cantidad"] = prmCantidad; tmpEntrada.Rows.Add(row); } else { MessageBox.Show("No hay suficientes existencias"); } } else { MessageBox.Show("El articulo no existe", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return (false); } dr.Close(); cnn.Close(); return (true); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return (false); }}bool grabarSalida(string prmFechaSalida, string prmResponsable, string prmUserLogin){ try { OleDbConnection cnn = new OleDbConnection(CnnStr); cnn.Open(); OleDbTransaction tran = cnn.BeginTransaction(); OleDbCommand cmd = new OleDbCommand(); cmd.Connection = cnn; cmd.Transaction = tran; //insertamos el registro de la Entrada try { cmd.CommandText = "insert into salidas(fecha_salida,responsable,user_login) " + " values (#" + prmFechaSalida + "#,'" + prmResponsable + "','" + prmUserLogin + "')"; cmd.ExecuteNonQuery(); //obtenemos el folio int _FolioSalida = 0; cmd.CommandText = "select @@identity"; _FolioSalida = Convert.ToInt32(cmd.ExecuteScalar()); //insertamos el detalle de laentrada for (int i = 0; i < tmpEntrada.Rows.Count; i++) { string _IdArticulo = Convert.ToString(tmpEntrada.Rows[i]["id_articulo"]); double _Cantidad = Convert.ToDouble(tmpEntrada.Rows[i]["cantidad"]); //insertamos el articulo cmd.CommandText = "insert into salidas_detalle(id_salida,id_articulo,cantidad) " + "values(" + _FolioSalida + ",'" + _IdArticulo + "'," + _Cantidad + ")"; cmd.ExecuteNonQuery(); //actualizamosexistencias cmd.CommandText = "update articulos set " + " existencia=existencia - " + _Cantidad + "" + " where id_articulo='" + _IdArticulo + "'"; cmd.ExecuteNonQuery(); } //finalizamos la transaccion tran.Commit(); cnn.Close(); MessageBox.Show("Salida grabada correctamente", "Informacin del Sistema", MessageBoxButtons.OK, MessageBoxIcon.Information); return (true); } catch (OleDbException errEntrada) { tran.Rollback(); cnn.Close(); MessageBox.Show(errEntrada.Message); return (false); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return (false); }}
Ahora damos doble clic sobre el botn Agregar (btnAgregar) y escribimos el siguiente cdigo:try{ if (agregarArticulo(txtIdArticulo.Text, Convert.ToDouble(txtCantidad.Text))) { mostrarEntrada(); }}catch (Exception ex){ MessageBox.Show(ex.Message);}
Ahora, agregaremos el cdigo para grabar la entrada, hacemos doble clic sobre el botn Grabar (btnGrabar) y escribimos el siguiente cdigo:if (grabarSalida(dtpFechaSalida.Value.ToShortDateString(), txtResponsable.Text, "admin")){ this.Close();}
El cdigo que pondremos en el Form_Load es el siguiente://>Definimos la tabla para las salida TemporalDataColumn idColumn = new DataColumn("id", typeof(int));idColumn.Unique = true;idColumn.AutoIncrement = true;idColumn.AutoIncrementSeed = 1;idColumn.AutoIncrementStep = 1;tmpEntrada.Columns.Add(idColumn);//declaramos el resto de los campostmpEntrada.Columns.Add("id_articulo", typeof(string));tmpEntrada.Columns.Add("articulo", typeof(string));tmpEntrada.Columns.Add("cantidad", typeof(Double));//agregamos un primary keytmpEntrada.PrimaryKey = new DataColumn[] { tmpEntrada.Columns["id"] };//