Creación de un sistema de almacén con C# (Parte 1) Creación del Proyecto Nuestro proyecto lo realizaremos con Visual Studio 2010. También puede utilizarse Visual C# 2010 Express el cual puede descargarse desde la página: 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 servirán 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 llam ada "Turorial", es la que estoy utilizando para generar este documento. Una vez hecho esto, continuaremos con el diseño de la base de datos
Creación de un sistema de almacén con C# (Parte 2) Creación de la Base de datos
Creamos una base de datos da tos con Microsoft Access, con las siguientes tablas:
users Nombre del Campo
Tipo de Datos
Descripción
user_login
Texto(50)
Nombre de inicio de sesión
user_password
Texto(255)
Contraseña del usuario
nombre
Texto(255)
Nombre del usuario
activo
Si/No
Si está activo
administrar
Si/No
Si puede administrar el sistema
Nota: Por favor ignorar la carpeta llamada llam ada "Turorial", es la que estoy utilizando para generar este documento. Una vez hecho esto, continuaremos con el diseño de la base de datos
Creación de un sistema de almacén con C# (Parte 2) Creación de la Base de datos
Creamos una base de datos da tos con Microsoft Access, con las siguientes tablas:
users Nombre del Campo
Tipo de Datos
Descripción
user_login
Texto(50)
Nombre de inicio de sesión
user_password
Texto(255)
Contraseña del usuario
nombre
Texto(255)
Nombre del usuario
activo
Si/No
Si está activo
administrar
Si/No
Si puede administrar el sistema
reportes
Si/No
Si puede ver reportes
articulos Nombre del Campo
Tipo de Datos
Descripción
id_articulo
Texto(50)
Id del artículo
articulo
Texto(255)
Nombre del artículo
localizacion
Texto(255)
Ubicación en el almacén
grupo
Texto(255)
Grupo G rupo del articulo
unidad_medida
Texto(255)
Unidad de medida
existencia
Número(Doble)
Existencia
cant_min
Número(Doble)
Existencia mínima
costo_promedio
Número(Doble)
Costo promedio
entradas Nombre del Campo
Tipo de Datos
Descripción
id_entrada
Autonumérico
Id de la entrada
fecha_registro
Fecha/Hora
Fecha de registro en el sistema
fecha_entrada
Fecha/Hora
Fecha de la entrada en el almacen
proveedor
Texto(255)
Nombre del proveedor
folio_factura
Texto(50)
Folio de la factura de compra
fecha_factura
Fecha/Hora
Fecha de la factura
user_login
Texto(50)
Usuario que registra la entrada
entradas_detalle Nombre del Campo
Tipo de Datos
Descripción
id_entrada_detalle
Autonumérico
Id del detalle de la entrada
id_entrada
Número
Id de la entrada
id_articulo
Texto(50)
Id del artículo
cantidad
Número(Doble)
Cantidad que entra al almacén
precio_compra
Número(Doble)
Precio de compra (segun factura)
iva
Número(Doble)
Impuesto que cobra el proveedor (en porcentaje)
salidas Nombre del Campo
Tipo de Datos
Descripción
id_salida
Autonumérico
Id de la salida
fecha_registro
Fecha/Hora
Fecha de registro en el sistema
fecha_salida
Fecha/Hora
Fecha de la salida
responsable
Texto(255)
Responsable de la salida
user_login
Texto(50)
Usuario que registra la salida
salidas_detalle
Nombre del Campo
Tipo de Datos
Descripción
id_salida_detalle
Autonumérico
Id del detalle de la salida
id_salida
Número
Id de la salida
id_articulo
Texto(50)
Id del artículo
cantidad
Número(Doble)
Cantidad que sale
Una vez que diseñamos nuestras tablas, las relacionamos. Las relaciones deben de quedar así:
Especificaciones técnicas:
Todos los nombres de los campos son con minúsculas. Esto no afecta en la programación, pero deseamos poder llevar un estándar en todo lo que vayamos desarrollando.
Deberá respetar los tipos de datos, eso nos evitará posibles errores en tiempo de ejecución.
Creación de un sistema de almacén con C# (Parte 3) Entradas al Almacén
Diseño de la pantalla
Empezaremos diseñando 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:
Objeto
Propiedad
Valor
Label
Name
lblFechaEntrada
DateTimePicker
Text
Fecha Entrada:
Name
dtpFechaEntrada
Format
Custom
CustomFormat dd/MM/yyyy
Name
lblFechaFactura
Text
Fecha Factura:
Name
dtpFechaFactura
Format
Custom
Label
DateTimePicker
CustomFormat dd/MM/yyyy
Name
lblFolioFactura
Text
Folio Factura:
TextBox
Name
txtFolioFactura
Label
Name
lblNombreProveedor
Label
TextBox
Text
Nombre del Proveedor:
Name
txtNombreProveedor
Name
lblIdArticulo
Text
Articulo:
Name
txtIdArticulo
Name
lblCantidad
Text
Cantidad:
Name
txtCantidad
Name
lblPrecioCompra
Text
Precio:
Name
txtPrecioCompra
Name
btnAgregar
Text
Agregar
Label
TextBox
Label
TextBox
Label
TextBox
Button
Name
btnGrabar
Text
Grabar
Name
btnCancelar
Text
Cancelar
Name
lvEntrada
Button
Button
FullRowSelect True ListView GridLines
True
HideSelection False
Programación
La parte de la programación es la mas enredada. Voy a considerar que el lector es un novato con nociones bastante básicas e insuficientes como para comprender la estructura de la programación C#. Recomiendo al lector poner mucha atención a 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 código de un formulario C#
Con mucho cuidado haremos doble clic sobre el formulario asegurándonos de no tocar con el
puntero del mouse ningun objeto. Veremos un código muy 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 continuación incluiré comentarios en esta misma porción de código con la finalidad de que podamos identificar claramente su organización:
/** * 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 nombres namespace 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 ejecución 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 código de un formulario C#. Debemos notar que todo inicia y termina con las llaves { }, existen algunos casos en los que puede omitirse el uso de las llaves, principalmente en las estructuras de desición if, pero para este tutorial, me aseguraré de escribir tanto mucho o tanto poco (mucho o poco) código 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 código 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"].ToStrin g());
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", "Información 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 botón Agregar (btnAgregar) y escribimos el siguiente código:
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 código para grabar la entrada, hacemos doble clic sobre el botón Grabar (btnGrabar) y escribimos el siguiente código:
if (grabarEntrada(dtpFechaEntrada.Value.ToShortDateString(), dtpFechaFactura.Value.ToShortDateString(), txtFolioFactura.Text, txtNombreProveedor.Text,"admin")) { this.Close(); }
El código que pondremos en el Form_Load es el siguiente:
//>Definimos la tabla para las ventas Temporales DataColumn 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 campos tmpEntrada.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 key tmpEntrada.PrimaryKey = new DataColumn[] { tmpEntrada.Columns["id"] }; //
En el botón Salir (btnSalir) escribimos esto:
this.Close();
Para efectos de aprendizaje basico me aseguré de no poner funcionalidad demasiado complicada. Lo que tratamos de desarrollar es un sistema de almacén sencillo, no se trata de desarrollar un sistema comercial cero errores, tratamos de sentar las bases técnicas para, en un futuro, lograr un gran sistema de almacén con toda la funcionalidad comercial.
Aqui un ejemplo de la pantalla funcionando:
Creación de un sistema de almacén con C# (Parte 4) Reporte de Entradas
Diseño de la pantalla
Para comenzar, le daremos diseño al formulario "frmEntradasLista" el cual nos servirá para mostrar un listado de las entradas que se hayan registrado, la apariencia debe de quedar mas o menos así:
Se agregaron tres Button, un ListView y un Label, las propiedades están descritas en la siguiente tabla:
Objeto
Propiedad
Valor
Name
btnNueva
Text
Nueva
Name
btnMostrar
Text
Mostrar
Name
btnSalir
Text
Salir
Name
lvEntradas
FullRowSelect
True
GridLines
True
HideSelection
False
Name
lblMensaje
Button
Button
Button
ListView
Label
Text
Doble clic para imprimir.
Ahora procedemos con el diseño del reporte de entradas, lo primero que haremos será crear un DataSet el cual nos servirá para el posterior diseño del reporte.
Agregamos un nuevo objeto del tipo DataSet y le asignamos el nombre dsRptEntrada como se muestra:
Le damos diseño para que quede como se muestra:
El DataSet aparece vacío, debemos agregar un DataTable y darle el diseño para que quede como se muestra en la imagen. De entre las propiedades que debemos destacar es que el tipo de datos de los campos cantidad, precio_compra e iva son System.Double. Los tipos de datos para los campos id_articulo y articulo son System.String.
Una vez terminado el diseño del DataSet agregamos un Reporte, pero utilizaremos un asistente, aqui muestro con imagenes todo el proceso:
Selecionamos que nuestro origen de datos es un objeto:
En la siguiente ventana, expanda todo y ubique el DataSet que acaba de crear anteriormente, como se muestra a continuación:
Luego, escriba un nombre para el DataSet (propiedad Name), se recomienda poner el mismo que puso anteriormente:
Arrastre los campos que desea mostrar en el reporte a la sección Values como se muestra en la imagen:
Desactive la operación Sum:
Seleccione un formato (apariencia):
Elija a su gusto:
Agregue el encabezado y el pié del reporte:
Agregue los parametros prmFechaEntrada, prmFechaFactura, prmFolioFactura y
prmProveedor
Ejemplo de como agregar un parametro (Repitalo con los demás):
Agregue cuatro TextBox al encabezado y organicelos ordenadamente:
Arrastre los parametros creados enfrente de los TextBox:
Agrege una columna al reporte:
Puede darle diseño al reporte, hagalo a su gusto, aqui se muestra algo muy básico:
Agregaremos una función para calcular el total:
En seguida se muestra como hacerla:
Agregaremos un nuevo formulario llamado frmVerReporte al cual agregaremos un control ReportViewer al cual estableceremos una propiedad Modifiers=Public (En la ventana de propiedades), aqui se muestra una imagen:
Hasta aqui todo ha sido diseño, ahora escribiremos el código que hace todo posible:
Declaramos las siguientes variables (En el formulario frmEntradasLista):
string CnnStr = @" Provider=Microsoft.Jet.OLEDB.4.0; " + "Data Source=D:\\DOCS\\tyrodeveloper\\almacen.mdb; " + "Jet OLEDB:Database Password=; Persist Security Info=False;"; string reportFile = @"D:\\DOCS\\tyrodeveloper\\almacen\\almacen\\Reportes\\rptEntrada.rdlc" ;
Ahora agregamos los siguientes procedimientos:
void generaColumnas() { lvEntradas.Clear(); lvEntradas.View = View.Details; lvEntradas.Columns.Add("Folio ", 40, HorizontalAlignment.Left); lvEntradas.Columns.Add("Fecha Entrada", 85, HorizontalAlignment.Left); lvEntradas.Columns.Add("Fecha Factura", 85, HorizontalAlignment.Left); lvEntradas.Columns.Add("Folio Factura", 85, HorizontalAlignment.Left); lvEntradas.Columns.Add("Proveedor", 200, HorizontalAlignment.Left); } void mostrarEntradas() { try { OleDbConnection cnn = new OleDbConnection(CnnStr); cnn.Open(); OleDbCommand cmd = new OleDbCommand(); cmd.Connection = cnn; cmd.CommandText = "select * from entradas"; OleDbDataReader dr = cmd.ExecuteReader(); int i = 0; lvEntradas.Items.Clear(); while (dr.Read()) {
//mostramos los datos lvEntradas.Items.Add(dr["id_entrada"].ToString());
lvEntradas.Items[i].SubItems.Add(String.Format( "{0:dd/MM/yyyy}",dr["fecha _entrada"])); lvEntradas.Items[i].SubItems.Add(String.Format( "{0:dd/MM/yyyy}", dr["fecha_factura"])); lvEntradas.Items[i].SubItems.Add(dr["folio_factura"].ToString()); lvEntradas.Items[i].SubItems.Add(dr["proveedor"].ToString()); i++; } dr.Close(); cnn.Close(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } void mostrarReporte(int prmIdEntrada) { try {
if (!File.Exists(reportFile)) { MessageBox.Show(String.Format("No se encuentra \n{0}\nRevise por favor", reportFile)); return; } //AHORA MOSTRAMOS EL REPORTE OleDbConnection cnn = new OleDbConnection(CnnStr); cnn.Open(); DataSet dsReporte = new DataSet();
OleDbDataAdapter da = new OleDbDataAdapter("select d.*,a.articulo "+ " from entradas_detalle d,articulos a "+ " where a.id_articulo=d.id_articulo and id_entrada="+ prmIdEntrada +"", cnn); da.Fill(dsReporte, "rptentrada"); if (dsReporte.Tables["rptEntrada"].Rows.Count == 0) { cnn.Close(); MessageBox.Show("No hay Datos"); return; }
Formularios.frmVerReporte frm = new Formularios.frmVerReporte(); frm.reportViewer1.LocalReport.DataSources.Clear(); frm.reportViewer1.LocalReport.Dispose(); frm.reportViewer1.Reset(); frm.reportViewer1.LocalReport.DataSources.Add( new ReportDataSource("dsRptEntrada", dsReporte.Tables["rptEntrada"])); frm.reportViewer1.LocalReport.ReportPath = reportFile; //parametros List param = new List(); OleDbCommand cmd = new OleDbCommand("select * from entradas where id_entrada=" + prmIdEntrada + "", cnn); OleDbDataReader dr = cmd.ExecuteReader(); while (dr.Read()) { //folio_factura ReportParameter pFolioFactura = new ReportParameter(); pFolioFactura.Name = "prmFolioFactura"; pFolioFactura.Values.Add(dr["folio_factura"].ToString()); param.Add(pFolioFactura); //fecha_entrada
ReportParameter pFechaEntrada = new ReportParameter(); pFechaEntrada.Name = "prmFechaEntrada"; pFechaEntrada.Values.Add(dr["fecha_entrada"].ToString()); param.Add(pFechaEntrada); //fecha_factura ReportParameter pFechaFactura = new ReportParameter(); pFechaFactura.Name = "prmFechaFactura"; pFechaFactura.Values.Add(dr["fecha_factura"].ToString()); param.Add(pFechaFactura); //proveedor ReportParameter pProveedor = new ReportParameter(); pProveedor.Name = "prmProveedor"; pProveedor.Values.Add(dr["proveedor"].ToString()); param.Add(pProveedor);
} dr.Close(); //agregamos los parametros a la coleccion frm.reportViewer1.LocalReport.SetParameters(param); frm.reportViewer1.RefreshReport(); frm.ShowDialog(); cnn.Close(); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error loading report", MessageBoxButtons.OK, MessageBoxIcon.Error); }
}
Agregamos sl siguiente código en el Form_Load:
lvEntradas.DoubleClick += new EventHandler(lvEntradas_DoubleClick); generaColumnas(); mostrarEntradas();
Luego, agregamos el siguiente código:
void lvEntradas_DoubleClick(object sender, EventArgs e) { if (lvEntradas.SelectedItems.Count != 0) { int _FolioEntrada = Convert.ToInt32(lvEntradas.SelectedItems[0].Text); mostrarReporte(_FolioEntrada); } }
El código para el botón btnNueva:
frmEntrada entrada = new frmEntrada(); entrada.StartPosition = FormStartPosition.CenterScreen; entrada.ShowDialog();
El código para el botón btnMostrar:
mostrarEntradas(); El código para el botón btnSalir
this.Close();
Aqui un ejemplo de la pantalla funcionando:
Aqui un ejemplo del reporte:
Creación de un sistema de almacén con C# (Parte 5) Salidas del Almacén
Diseño de la pantalla
Empezaremos diseñando la pantalla de salidas (formulario frmSalida), la apariencia debe de quedar mas o menos así:
A continuacion una tabla descriptiva con los nombres de los objetos:
Objeto
Propiedad
Valor
Name
lblFechaSalida
Text
Fecha Salida:
Name
dtpFechaSalida
Format
Custom
CustomFormat
dd/MM/yyyy
Label
DateTimePicker
Label
TextBox
Name
lblResponsable
Text
Responsable de la Salida:
Name
txtResponsable
Name
lblIdArticulo
Text
Articulo:
Name
txtIdArticulo
Name
lblCantidad
Text
Cantidad:
Name
txtCantidad
Name
btnAgregar
Text
Agregar
Name
btnGrabar
Text
Grabar
Name
btnCancelar
Text
Cancelar
Name
lvSalida
FullRowSelect
True
GridLines
True
HideSelection
False
Label
TextBox
Label
TextBox
Button
Button
Button
ListView
Programación
La parte de la programación es la mas enredada. Voy a considerar que el lector es un novato con nociones bastante básicas e insuficientes como para comprender la estructura de la programación C#. Recomiendo al lector poner mucha atención a los pasos que aqui se describan y no omitir nada, leer y re-leer hasta que haya comprendido
lo que tiene que hacer.
Declaramos las siguientes variables:
//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;";
Escribiremos el código de las funciones y procedimientos:
void generaColumnas() { lvSalida.Clear(); lvSalida.View = View.Details; lvSalida.Columns.Add("", 0, HorizontalAlignment.Left); lvSalida.Columns.Add("Id ", 100, HorizontalAlignment.Left); lvSalida.Columns.Add("Producto", 240, HorizontalAlignment.Left); lvSalida.Columns.Add("Cantidad", 60, HorizontalAlignment.Right); } void mostrarEntrada()
{ try { lvSalida.Items.Clear(); for (int i = 0; i < tmpEntrada.Rows.Count; i++) { lvSalida.Items.Add(tmpEntrada.Rows[i]["id"].ToString());
lvSalida.Items[i].SubItems.Add(tmpEntrada.Rows[i][ "id_articulo"].ToString ());
lvSalida.Items[i].SubItems.Add(tmpEntrada.Rows[i][ "articulo"].ToString()) ; lvSalida.Items[i].SubItems.Add(String.Format( "{0:N}", Convert.ToDouble(tmpEntrada.Rows[i]["cantidad"]))); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } bool agregarArticulo(string prmIdArticulo, double prmCantidad) { try { string varId = ""; string varNombre = ""; double varExistencia = 0; OleDbConnection cnn = new OleDbConnection(CnnStr); cnn.Open(); string strSQL = "select articulo,existencia from articulos " +
"where id_articulo='" + prmIdArticulo + "'"; OleDbCommand cmd = new OleDbCommand(strSQL, cnn); OleDbDataReader dr = cmd.ExecuteReader(); if (dr.Read()) { varId = prmIdArticulo; varNombre = dr["articulo"].ToString(); varExistencia =Convert.ToDouble(dr["existencia"]); if (varExistencia >= 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", "Información 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 botón Agregar (btnAgregar) y escribimos el siguiente código:
try { if (agregarArticulo(txtIdArticulo.Text, Convert.ToDouble(txtCantidad.Text))) { mostrarEntrada(); } } catch (Exception ex) { MessageBox.Show(ex.Message); }
Ahora, agregaremos el código para grabar la entrada, hacemos doble clic sobre el botón Grabar (btnGrabar) y escribimos el siguiente código:
if (grabarSalida(dtpFechaSalida.Value.ToShortDateString(), txtResponsable.Text, "admin")) {
this.Close(); }
El código que pondremos en el Form_Load es el siguiente:
//>Definimos la tabla para las salida Temporal DataColumn 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 campos tmpEntrada.Columns.Add("id_articulo", typeof(string)); tmpEntrada.Columns.Add("articulo", typeof(string)); tmpEntrada.Columns.Add("cantidad", typeof(Double)); //agregamos un primary key tmpEntrada.PrimaryKey = new DataColumn[] { tmpEntrada.Columns["id"] }; //
En el botón Salir (btnSalir) escribimos esto:
this.Close();
Aqui un ejemplo de la pantalla funcionando:
Creación de un sistema de almacén con C# (Parte 6) Reporte de Entradas
Diseño de la pantalla
Para comenzar, le daremos diseño al formulario "frmSalidasLista" el cual nos servirá para mostrar un listado de las salidas que se hayan registrado, la apariencia debe de quedar mas o menos así:
Se agregaron tres Button, un ListView y un Label, las propiedades están descritas en la siguiente tabla:
Objeto
Propiedad
Valor
Name
btnNueva
Text
Nueva
Name
btnMostrar
Text
Mostrar
Name
btnSalir
Text
Salir
Name
lvSalidas
FullRowSelect
True
GridLines
True
HideSelection
False
Name
lblMensaje
Text
Doble clic para imprimir.
Button
Button
Button
ListView
Label
Ahora procedemos con el diseño del reporte de salidas, este proceso se muestra en la parte 4 de este tutorial, el cual deberá quedar mas o menos así:
Ahora agregamos los siguientes procedimientos:
void generaColumnas(){ lvSalidas.Clear(); lvSalidas.View = View.Details; lvSalidas.Columns.Add("Folio ", 40, HorizontalAlignment.Left); lvSalidas.Columns.Add("Fecha Salida", 85, HorizontalAlignment.Left); lvSalidas.Columns.Add("Responsable", 200, HorizontalAlignment.Left); } void mostrarSalidas(){ try { OleDbConnection cnn = new OleDbConnection(CnnStr); cnn.Open(); OleDbCommand cmd = new OleDbCommand(); cmd.Connection = cnn; cmd.CommandText = "select * from salidas"; OleDbDataReader dr = cmd.ExecuteReader(); int i = 0; lvSalidas.Items.Clear(); while (dr.Read()) { //mostramos los datos lvSalidas.Items.Add(dr["id_salida"].ToString()); lvSalidas.Items[i].SubItems.Add(String.Format( "{0:dd/MM/yyyy}",
dr["fecha_salida"])); lvSalidas.Items[i].SubItems.Add(dr["responsable"].ToString()); i++; } dr.Close(); cnn.Close(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } void mostrarReporte(int prmIdSalida){ try{ if (!File.Exists(reportFile)){ MessageBox.Show(String.Format("No se encuentra \n{0}\nRevise por favor", reportFile)); return; } //AHORA MOSTRAMOS EL REPORTE OleDbConnection cnn = new OleDbConnection(CnnStr); cnn.Open(); DataSet dsReporte = new DataSet(); OleDbDataAdapter da = new OleDbDataAdapter("select d.*,a.articulo " + " from salidas_detalle d,articulos a " + " where a.id_articulo=d.id_articulo and id_salida=" + prmIdSalida + "", cnn); da.Fill(dsReporte, "rptSalida"); if (dsReporte.Tables["rptSalida"].Rows.Count == 0) { cnn.Close(); MessageBox.Show("No hay Datos"); return; }
Formularios.frmVerReporte frm = new Formularios.frmVerReporte(); frm.reportViewer1.LocalReport.DataSources.Clear(); frm.reportViewer1.LocalReport.Dispose(); frm.reportViewer1.Reset(); frm.reportViewer1.LocalReport.DataSources.Add( new ReportDataSource("dsRptSalida", dsReporte.Tables["rptSalida"])); frm.reportViewer1.LocalReport.ReportPath = reportFile; //parametros List param = new List(); OleDbCommand cmd = new OleDbCommand("select * from salidas where id_salida=" + prmIdSalida + "", cnn); OleDbDataReader dr = cmd.ExecuteReader(); while (dr.Read()){ //fecha_salida ReportParameter pFechaEntrada = new ReportParameter(); pFechaEntrada.Name = "prmFechaSalida"; pFechaEntrada.Values.Add(dr["fecha_salida"].ToString()); param.Add(pFechaEntrada); //responsable ReportParameter pProveedor = new ReportParameter(); pProveedor.Name = "prmResponsable"; pProveedor.Values.Add(dr["responsable"].ToString()); param.Add(pProveedor); } dr.Close(); //agregamos los parametros a la coleccion frm.reportViewer1.LocalReport.SetParameters(param); frm.reportViewer1.RefreshReport(); frm.ShowDialog(); cnn.Close(); } catch (Exception ex){
MessageBox.Show(ex.Message, "Error al cargar el reporte", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
Agregamos sl siguiente código en el Form_Load:
lvSalidas.DoubleClick += new EventHandler(lvSalidas_DoubleClick); generaColumnas(); mostrarSalidas();
Luego, agregamos el siguiente código:
void lvSalidas_DoubleClick(object sender, EventArgs e) { if (lvSalidas.SelectedItems.Count != 0){ int _FolioSalida = Convert.ToInt32(lvSalidas.SelectedItems[0].Text); mostrarReporte(_FolioSalida); } }
El código para el botón btnNueva:
frmSalida salida = new frmSalida(); salida.StartPosition = FormStartPosition.CenterScreen; salida.ShowDialog();
El código para el botón btnMostrar:
mostrarSalidas(); El código para el botón btnSalir
this.Close();
Aqui un ejemplo de la pantalla funcionando:
Aqui un ejemplo del reporte:
Hasta este punto ya hemos desarrollado la funcionalidad básica. En la siguiente parte haremos que aparesca una pantalla pricipal desde la que mandaremos llamar las que hasta hoy hemos desarrollado.
Creación de un sistema de almacén con C# (Parte 7) Pantalla principal
Le daremos diseño al formulario frmPrincipal agregando un MenuStrip, un ToolStrip y estableciendo su pripiedad IsMdiContainer = true para que quede de la siguiente manera:
A continuación una tabla que describe los objetos:
Objeto
Propiedad
Valor
MenuStrip
Name
mnuPrincipal
ToolStripMenuItem Name
mnuArchivo
Text
Archivo
Name
mnuAyuda
Text
Ayuda
Name
mnuEntradas
Text
Entradas
Name
mnuSalidas
Text
Salidas
Name
mnuSalir
Text
Salir del Sistema
Name
barPrincipal
Name
btnEntradas
Text
Entradas
ToolStripMenuItem
ToolStripMenuItem
ToolStripMenuItem
ToolStripMenuItem
ToolStrip
ToolStripButton DisplayStyle
ImageAndText
TextImageRelation ImageAboveText Image
(A su gusto)
Name
btnSalidas
Text
Salidas
ToolStripButton DisplayStyle
ImageAndText
TextImageRelation ImageAboveText Image ToolStripButton Name
(A su gusto) btnSalir
Text
Salir
DisplayStyle
ImageAndText
TextImageRelation ImageAboveText Image
(A su gusto)
Ahora crearemos los siguientes procedimientos:
void entradas() { frmEntradasLista entradas = new frmEntradasLista(); entradas.MdiParent = this; entradas.Show(); } void salidas() { frmSalidasLista salidas = new frmSalidasLista(); salidas.MdiParent = this; salidas.Show(); } void salir() { this.Close(); }
Ahora solo resta poner el código en cada uno de los botones y menús, los ponemos de uno por uno, dando doble clic sobre cada uno, iniciamos con mnuEntradas:
entradas(); Seguimos con mnuSalidas:
salidas(); Asi lo hacemos también con los botones btnEntradas y btnSalidas
Ahora, el toque final de nuestra aplicación, abrimos la clase InicioAplicacion y nos aseguramos que esté como se muestra a continuación:
using System; using System.Windows.Forms; namespace almacen.Clases { class InicioAplicacion {
/// /// The main entry point for the application. /// [STAThread] static void Main()