Está en la página 1de 46

C# - APLICACIN DE ESCRITORIO, SISTEMAS DE VENTAS PART IV CREACIN DE LA CAPA DE PRESENTACIN

1. ENTORNO

SQL Server 2008 Visual Studio 2008

2. INTRODUCCIN En el tutorial en la Parte II y en la Parte III hemos creado la capa de datos y la capa de negocios respectivamente de nuestra aplicacin, ahora solo nos falta crear nuestra capa de presentacion. La capa de presentacion puede ser una aplicacion del tipo escritorio, web, etc. Es por eso que se utiliza la programacion en capas, debido a que no importa que cambiamos hagamos en alguna capa no se sentira en las otras de manera brusca. 3. DESARROLLO 3.1. Creando el Proyecto Ahora debemos de agregar a nuestro proyecto un proyecto del tipo biblioteca de clases que se llamara "CapaPresentacion". No olvidar que debemos de ir a "Archivo-->Agregar-->Nuevo Proyecto"

3.2. Agregando la referencia con la Capa de Negocios Debemos de establecer la comunicacion entre la Capa de Presentacin y la Capa de Negocios. Para eso hacemos clic derecho en nuestro proyecto que se llama "CapaPresentacion" y nos vamos a la opcion de "Agregar Referencia"

Y de ah seleccionamos que se comunica con la Capa de Negocios

3.3. Formulario frmMantenimientoProducto En este formulario vamos a realizar un mantenimiento a la tabla Producto de nuestra Base de Datos que se llama BDTutorial y que esta diseada en SQL Server 2008. A mantenimiento me refiero a los procesos de insercin, actualizacin y consulta de datos de la tabla Producto. Debemos de disear el siguiente formulario

En el cual el componente dgvProducto tiene los siguientes valores de propiedades:


AllowUserToAddRows = False AllowUserToDeleteRows = False MultiSelect = False ReadOnly = True SelectionMode = FullRowSelect

Y como columnas tiene

codigoProducto o DataPropertyName = codigoProducto o HeaderText = codigoProducto o Visible = False Nombre o DataPropertyName = nombre o HeaderText = Nombre o Visible = True Precio o DataPropertyName = precio o HeaderText = Precio o Visible = True

En la otra pestaa del tabControl tenemos los siguientes componentes:

Y su cdigo fuente del formulario seria 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; //Comunicarse con la Capa de Negocios using CapaNegocios; //Desarollado por Henry Joe Wong Urquiza namespace CapaPresentacion { public partial class frmMantenimientoProducto : Form { //Variable que nos indica si vamos a insertar un nuevo producto private bool nuevo = false; //Variable que nos indica si vamos a modificar un producto private bool modificar = false; //Constructor del formulario public frmMantenimientoProducto() { InitializeComponent(); } //Evento que se lanza cuando se va a mostrar el formulario private void frmMantenimientoProducto_Load(object sender, EventArgs e) { //Para ubicar al formulario en la parte superior del contenedor this.Top = 0; this.Left = 0; //Le decimos al DataGridView que no auto genere las columnas this.dgvProductos.AutoGenerateColumns = false; //Llenamos el DataGridView con la informacion de todos nuestros //productos this.dgvProductos.DataSource = NegProducto.ObtenerProducto(); //Deshabilita los controles this.habilitar(false); //Establece los botones this.botones(); } //Para mostrar mensaje de confirmacion

private void mOK(string men) { MessageBox.Show(men, "MENSAJE", MessageBoxButtons.OK, MessageBoxIcon.Information); } //Para mostrar mensaje de error private void mError(string men) { MessageBox.Show(men, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); } //Limpia los controles del formulario private void limpiar() { this.txtNombre.Text = string.Empty; this.nudPrecio.Value = 0; } //Habilita los controles de los formularios private void habilitar(bool valor) { this.txtNombre.ReadOnly = !valor; this.nudPrecio.Enabled = valor; } //Habilita los botones private void botones() { if (this.nuevo || this.modificar) { this.habilitar(true); this.btnNuevo.Enabled = false; this.btnGuardar.Enabled = true; this.btnModificar.Enabled = false; this.btnCancelar.Enabled = true; } else { this.habilitar(false); this.btnNuevo.Enabled = true; this.btnGuardar.Enabled = false; this.btnModificar.Enabled = true; this.btnCancelar.Enabled = false; } }

//Evento clic del boton btnNuevo private void btnNuevo_Click(object sender, EventArgs e) { this.nuevo=true; this.modificar=false; this.botones(); this.limpiar(); this.txtCodigo.Text = string.Empty; this.txtNombre.Focus(); } //Evento clic del boton btnGuardar private void btnGuardar_Click(object sender, EventArgs e) { //La variable que almacena si se inserto o se modifico la tabla string rpta = ""; if(this.nuevo) { //Vamos a insertar un producto rpta=NegProducto.Insertar(this.txtNombre.Text.Trim().ToUpper(), this.nudPrecio.Value); }else { //Vamos a modificar un producto rpta=NegProducto.Actualizar(Convert.ToInt32(this.txtCodigo.Text), this.txtNombre.Text.Trim().ToUpper(), this.nudPrecio.Value); } //Si la respuesta fue OK, fue porque se modifico o inserto el Producto //de forma correcta if (rpta.Equals("OK")) { if (this.nuevo) { this.mOK("Se inserto de forma correcta al Producto"); } else { this.mOK("Se actualizo de forma correcta al Producto"); } } else

{ //Mostramos el mensaje de error this.mError(rpta); } this.nuevo=false; this.modificar=false; this.botones(); this.limpiar(); this.dgvProductos.DataSource = NegProducto.ObtenerProducto(); this.txtCodigo.Text=""; } //Evento clic del boton btnModificar private void btnModificar_Click(object sender, EventArgs e) { //Si no ha seleccionado un producto no puede modificar if(!this.txtCodigo.Text.Equals("")) { this.modificar=true; this.botones(); } else { this.mError("Debe de buscar un producto para Modificar"); } } //Evento clic del boton btnCancelar private void btnCancelar_Click(object sender, EventArgs e) { this.nuevo=false; this.modificar=false; this.botones(); this.limpiar(); this.txtCodigo.Text=string.Empty; } //Evento double clic del DataGridView de Productos private void dgvProductos_DoubleClick(object sender, EventArgs e) { this.txtCodigo.Text = Convert.ToString(this.dgvProductos.CurrentRow.Cells["codigoProducto"].Value); this.txtNombre.Text = Convert.ToString(this.dgvProductos.CurrentRow.Cells["nombre"].Value); this.nudPrecio.Value = Convert.ToDecimal(this.dgvProductos.CurrentRow.Cells["precio"].Value);

this.tabControl.SelectedIndex = 1; } } } 3.4. Formulario frmSeleccionarProducto Es un formulario del tipo modal que nos permitir seleccionar un producto de nuestra base de datos para registrar la venta. Y tiene el siguiente diseo

En el cual el componente dgvProducto tiene los siguientes valores de propiedades:

AllowUserToAddRows = False AllowUserToDeleteRows = False MultiSelect = False ReadOnly = True SelectionMode = FullRowSelect

Y como columnas tiene

codigoProducto o DataPropertyName = codigoProducto o HeaderText = codigoProducto o Visible = False Nombre o DataPropertyName = nombre o HeaderText = Nombre o Visible = True Precio o DataPropertyName = precio o HeaderText = Precio o Visible = True

Y como cdigo fuente tiene lo 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; //Comunicarse con la Capa de Negocios using CapaNegocios; //Desarollado por Henry Joe Wong Urquiza namespace CapaPresentacion { public partial class frmSeleccionarProducto : Form { //El formulario padre private frmRegistrarVenta frame; //El constructor del formulario public frmSeleccionarProducto() { InitializeComponent(); } //Establece los valores del formulario padre public void estableceFormulario(frmRegistrarVenta frame) {

this.frame = frame; } //Evento que se ejecuta cuando se muestra el formulario private void frmSeleccionarProducto_Load(object sender, EventArgs e) { //Que no se genere las columnas de forma automatica this.dgvProducto.AutoGenerateColumns = false; //Obtiene todos los productos y lo asigana al DataGridView this.dgvProducto.DataSource = NegProducto.ObtenerProducto(); } //Evento double clic del DataGridView private void dgvProducto_DoubleClick(object sender, EventArgs e) { //Estableciendo los datos a las cajas de texto del formulario padre this.frame.codigoProductoSeleccionado = Convert.ToInt32(this.dgvProducto.CurrentRow.Cells["codigoProducto"].Value); this.frame.txtProducto.Text = Convert.ToString(this.dgvProducto.CurrentRow.Cells["nombre"].Value); this.frame.txtPrecio.Text = Convert.ToString(this.dgvProducto.CurrentRow.Cells["precio"].Value); //Cerrando el formulario this.Hide(); } } } 3.5. Formulario frmRegistrarVenta Este formulario es la parte principal del sistema en cual se registra la venta. Tener en cuenta que si el detalle de la venta es mayor a 50 soles, dolares, euros, etc se le aplica un descuento del 5% del sub total de la venta. Debemos realizar el siguiente diseo del formulario

En cual la accesibilidad de los controles txtProducto y txtPrecio es del tipoInternal y tiene la propiedad ReadOnly en True. Y ademas el componente dgvDetalle tiene los siguientes valores de propiedades:

AllowUserToAddRows = False AllowUserToDeleteRows = False MultiSelect = False ReadOnly = True SelectionMode = FullRowSelect

Y como columnas tiene

codigoProducto o DataPropertyName = codigoProducto o HeaderText = codigoProducto o Visible = False Producto

DataPropertyName = Producto o HeaderText = Producto o Visible = True Cantidad o DataPropertyName = cantidad o HeaderText = Cantidad o Visible = True PU o DataPropertyName = PU o HeaderText = PU o Visible = True Descuento o DataPropertyName = Descuento o HeaderText = Descuento o Visible = True SubTotal o DataPropertyName = subTotal o HeaderText = SubTotal o Visible = True
o

Y como cdigo fuente tiene lo 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; //Comunicarse con la Capa de Negocios using CapaNegocios; //Desarollado por Henry Joe Wong Urquiza namespace CapaPresentacion { public partial class frmRegistrarVenta : Form { //DataTable que se encargara de guardar el detalle de la venta //de forma temporal private DataTable dtDetalle; //Codigo del producto seleccionado internal int codigoProductoSeleccionado = -1;

//Variable que almacena el total de la venta private decimal totalPagar = 0; //El constructor de la clase public frmRegistrarVenta() { InitializeComponent(); } //Metodo que se ejecuta al cargar el formulario private void frmRegistrarVenta_Load(object sender, EventArgs e) { this.Top = 0; this.Left = 0; this.crearTabla(); this.WindowState = FormWindowState.Maximized; } //Limpia todos los controles del formulario private void limpiarControles() { this.txtCliente.Text = string.Empty; this.codigoProductoSeleccionado = -1; this.txtProducto.Text = string.Empty; this.txtPrecio.Text = string.Empty; this.nudCantidad.Value = 1; this.crearTabla(); this.lblTotalPagar.Text = "Total Pagar: S/. 0.00"; } //Crea la tabla de Detalle private void crearTabla() { //Crea la tabla con el nombre de Detalle this.dtDetalle = new DataTable("Detalle"); //Agrega las columnas que tendra la tabla this.dtDetalle.Columns.Add("codigoProducto", System.Type.GetType("System.Int32")); this.dtDetalle.Columns.Add("Producto", System.Type.GetType("System.String")); this.dtDetalle.Columns.Add("cantidad", System.Type.GetType("System.Decimal")); this.dtDetalle.Columns.Add("PU", System.Type.GetType("System.Decimal")); this.dtDetalle.Columns.Add("Descuento", System.Type.GetType("System.Decimal"));

this.dtDetalle.Columns.Add("subTotal", System.Type.GetType("System.Decimal")); //Relacionamos nuestro datagridview con nuestro datatable this.dgvDetalle.DataSource = this.dtDetalle; } //Para mostrar mensaje de error private void mError(string mensaje) { MessageBox.Show(this, mensaje, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Warning); } //Para mostrar mensaje de confirmacin private void mOk(string mensaje) { MessageBox.Show(this, mensaje, "MENSAJE", MessageBoxButtons.OK, MessageBoxIcon.Information); } //Evento del clic del boton btnBuscar private void btnBuscar_Click(object sender, EventArgs e) { //Creamos una variable del tipo del formulario que deseamos abrir frmSeleccionarProducto frame = new frmSeleccionarProducto(); //Le pasamos como datos la informacin de nuestro formulario frame.estableceFormulario(this); //Mostrar el formulario que tiene los productos que hemos seleccionado frame.ShowDialog(); } //Evento clic del boton agregar private void btnAgregar_Click(object sender, EventArgs e) { //Valida que hemos seleccionado algun producto if (this.codigoProductoSeleccionado == -1) { this.mError("No ha seleccionado aun ningun producto"); } else { //Variable que va a indicar si podemos registrar el detalle bool registrar = true; foreach (DataRow row in dtDetalle.Rows) {

if (Convert.ToInt32(row["codigoProducto"]) == this.codigoProductoSeleccionado) { registrar = false; this.mError("Ya se encuentra el producto en el detalle"); } } //Si podemos registrar el producto en el detalle if (registrar) { //Calculamos el sub total del detalle sin descuento decimal subTotal = Convert.ToDecimal(this.txtPrecio.Text) * nudCantidad.Value; //Obtenemos el descuento decimal descuento = NegDetalleVenta.ObtenerDescuento( nudCantidad.Value, Convert.ToDecimal(this.txtPrecio.Text)); //Actualizamos el sub total con el descuento correspondiente subTotal = subTotal - descuento; //Aumentamos el total a pagar this.totalPagar += subTotal; this.lblTotalPagar.Text = "Total Pagar: S/." + totalPagar.ToString("#0.00#"); //Agregamos al fila a nuestro datatable DataRow row = this.dtDetalle.NewRow(); row["codigoProducto"] = this.codigoProductoSeleccionado; row["Producto"] = this.txtProducto.Text; row["cantidad"] = this.nudCantidad.Value; row["PU"] = this.txtPrecio.Text ; row["Descuento"] = descuento; row["subTotal"] = subTotal; this.dtDetalle.Rows.Add(row); } } } //Evento click del boton quitar private void btnQuitar_Click(object sender, EventArgs e) { try { //Indice dila actualmente seleccionado y que vamos a eliminar int indiceFila = this.dgvDetalle.CurrentCell.RowIndex; //Fila que vamos a eliminar DataRow row = this.dtDetalle.Rows[indiceFila];

//Disminuimos el total a pagar this.totalPagar = this.totalPagar Convert.ToDecimal(row["subTotal"].ToString()); this.lblTotalPagar.Text = "Total Pagar: S/." + totalPagar.ToString("#0.00#"); //Removemos la fila this.dtDetalle.Rows.Remove(row); } catch (Exception ex) { mError("No hay fila para remover"); } } private void btnGuardar_Click(object sender, EventArgs e) { //Debe de tener por almenos un detalle para poder registrar if (this.dtDetalle.Rows.Count > 0) { string rpta = NegVenta.Insertar(this.txtCliente.Text, this.dtDetalle); if (rpta.Equals("OK")) { mOk("Se inserto de manera correcta la venta"); this.limpiarControles(); } else { mError(rpta); } } else { mError("No agregado ningun detalle"); } }

} }

2. INTRODUCCIN 2.1. Programacin por capas La programacin por capas es un estilo de programacin en el que el objetivo primordial es la separacin de la lgica de negocios de la lgica de diseo. La ventaja principal de este estilo es que el desarrollo se puede llevar a cabo en varios niveles y, en caso de que sobrevenga algn cambio, slo se ataca al nivel requerido sin tener que revisar entre cdigo mezclado. Un buen ejemplo de este mtodo de programacin sera el modelo de interconexin de sistemas abiertos 2.2. Programacin en tres capas

Capa de presentacin: es la que ve el usuario (tambin se la denomina "capa de usuario"), presenta el sistema al usuario, le comunica la informacin y captura la informacin del usuario en un mnimo de proceso (realiza un filtrado previo para comprobar que no hay errores de formato). Esta capa se comunica nicamente con la capa de negocio. Tambin es conocida como interfaz grfica y debe tener la caracterstica de ser "amigable" (entendible y fcil de usar) para el usuario. Capa de negocio: es donde residen los programas que se ejecutan, se reciben las peticiones del usuario y se envan las respuestas tras el proceso. Se denomina capa de negocio (e incluso de lgica del negocio) porque es aqu donde se establecen todas las reglas que deben cumplirse. Esta capa se comunica con la capa de presentacin, para recibir las solicitudes y presentar los resultados, y con la capa de datos, para solicitar al gestor de base de datos para almacenar o recuperar datos de l. Tambin se consideran aqu los programas de aplicacin. Capa de datos: es donde residen los datos y es la encargada de acceder a los mismos. Est formada por uno o ms gestores de bases de datos que realizan todo el almacenamiento de datos, reciben solicitudes de almacenamiento o recuperacin de informacin desde la capa de negocio.

3. DESARROLLO 3.1. Creando el proyecto Primero debemos de crear un proyecto con Visual Studio 2008, para eso abrimos el Visual Studio 2008 y nos vamos al men de "Archivo-->Nuevo Proyecto". A nuestro proyecto le pondremos de nombre "SistemaVentas"

3.2. Agregando la Capa de Datos Debemos de agregar a nuestro proyecto la capa de datos, para eso nos vamos al menu de "Archivo-->Agregar Nuevo Proyecto"

Y le pondremos como nombre "CapaDatos"

3.3. La clase Conexion Para agregar una clase en C# debemos hacer clic derecho en la Capa de Datos y seleccionar la opcin "Agregar-->Clase" y la clase que creamos se llamara "Conexion", que se encargara de guardar la cadena de conexin para poder conectarnos con nuestra base de datos que esta en SQL Server 2008 y la cual se llama BDTutorial.

La clase Conexion tendr el siguiente cdigo en C#

using System; using System.Collections.Generic; using System.Linq; using System.Text; //Desarrollado por Henry Joe Wong Urquiza namespace CapaDatos { public class Conexion { //La base de datos se llama BDTutorial //La ubicacion de base de datos esta de modo local y en una instancia que se llama SQL2008 //Utiliza seguridad integrada para conectarse a la base de datos public static string cn = "Data Source=.\\SQL2008;Initial Catalog=BDTutorial;Integrated Security=True"; } } 3.2. La clase Producto Esta clase se encarga de conectar la tabla Producto con C# using System; using System.Collections.Generic; using System.Text; //Impotaciones necesarias using System.Data; using System.Data.SqlClient; //Desarrollado por Henry Joe Wong Urquiza namespace CapaDatos { public class Producto { private int var_codigoProducto; private string var_nombre; private decimal var_precio; //Constructor vacio

public Producto() { } //Constructor con parametros public Producto( int codigoProducto, string nombre, decimal precio ) { this.var_codigoProducto = codigoProducto; this.var_nombre = nombre; this.var_precio = precio; } //Metodo utilizado para insertar un Producto public string Insertar(Producto varProducto) { string rpta = ""; SqlConnection sqlCon = new SqlConnection(); try { //1. Establecer la cadena de conexion sqlCon.ConnectionString = Conexion.cn; //2. Abrir la conexion de la BD sqlCon.Open(); //3. Establecer el comando SqlCommand sqlCmd = new SqlCommand(); sqlCmd.Connection = sqlCon; sqlCmd.CommandText = "spI_Producto"; sqlCmd.CommandType = CommandType.StoredProcedure; //4. Agregar los parametros al comando //Establecemos los valores para el parametro @codigoProducto del Procedimiento Almacenado SqlParameter sqlParcodigoProducto = new SqlParameter(); sqlParcodigoProducto.ParameterName = "@codigoProducto"; sqlParcodigoProducto.SqlDbType = SqlDbType.Int; //Le declaramos que el parametro es de salida, porque obtendremos el codigo generado por la base de datos sqlParcodigoProducto.Direction = ParameterDirection.Output;

sqlCmd.Parameters.Add(sqlParcodigoProducto); //Agregamos el parametro al comando //Establecemos los valores para el parametro @nombre del Procedimiento Almacenado SqlParameter sqlParnombre = new SqlParameter(); sqlParnombre.ParameterName = "@nombre"; sqlParnombre.SqlDbType = SqlDbType.VarChar; sqlParnombre.Size = 100; sqlParnombre.Value = varProducto.nombre; sqlCmd.Parameters.Add(sqlParnombre); //Agregamos el parametro al comando //Establecemos los valores para el parametro @precio del Procedimiento Almacenado SqlParameter sqlParprecio = new SqlParameter(); sqlParprecio.ParameterName = "@precio"; sqlParprecio.SqlDbType = SqlDbType.Decimal; sqlParprecio.Precision=18; sqlParprecio.Scale=2; sqlParprecio.Value = varProducto.precio; sqlCmd.Parameters.Add(sqlParprecio); //Agregamos el parametro al comando //5. Ejecutamos el commando rpta = sqlCmd.ExecuteNonQuery() == 1 ? "OK" : "No se inserto el producto de forma correcta"; } catch (Exception ex) { rpta = ex.Message; } finally { //6. Cerramos la conexion con la BD if (sqlCon.State == ConnectionState.Open) sqlCon.Close(); } return rpta; }

//Metodo utilizado para actualizar un Producto public string Actualizar(Producto varProducto) {

string rpta = ""; SqlConnection sqlCon = new SqlConnection(); try { //1. Establecer la cadena de conexion sqlCon.ConnectionString = Conexion.cn; //2. Abrir la conexion de la BD sqlCon.Open(); //3. Establecer el comando SqlCommand sqlCmd = new SqlCommand(); sqlCmd.Connection = sqlCon; sqlCmd.CommandText = "spU_Producto"; sqlCmd.CommandType = CommandType.StoredProcedure; //4. Agregar los parametros al comando //Establecemos los valores para el parametro @codigoProducto del Procedimiento Almacenado SqlParameter sqlParcodigoProducto = new SqlParameter(); sqlParcodigoProducto.ParameterName = "@codigoProducto"; sqlParcodigoProducto.SqlDbType = SqlDbType.Int; sqlParcodigoProducto.Value = varProducto.codigoProducto; sqlCmd.Parameters.Add(sqlParcodigoProducto); //Agregamos el parametro al comando //Establecemos los valores para el parametro @nombre del Procedimiento Almacenado SqlParameter sqlParnombre = new SqlParameter(); sqlParnombre.ParameterName = "@nombre"; sqlParnombre.SqlDbType = SqlDbType.VarChar; sqlParnombre.Size = 100; sqlParnombre.Value = varProducto.nombre; sqlCmd.Parameters.Add(sqlParnombre); //Agregamos el parametro al comando //Establecemos los valores para el parametro @precio del Procedimiento Almacenado SqlParameter sqlParprecio = new SqlParameter(); sqlParprecio.ParameterName = "@precio"; sqlParprecio.SqlDbType = SqlDbType.Decimal; sqlParprecio.Precision = 18; sqlParprecio.Scale = 2; sqlParprecio.Value = varProducto.precio; sqlCmd.Parameters.Add(sqlParprecio); //Agregamos el parametro al comando

//5. Ejecutamos el commando rpta = sqlCmd.ExecuteNonQuery() == 1 ? "OK" : "No se actualizo el producto de forma correcta"; } catch (Exception ex) { rpta = ex.Message; } finally { //6. Cerramos la conexion con la BD if (sqlCon.State == ConnectionState.Open) sqlCon.Close(); } return rpta; } //Metodo utilizado para obtener todos los productos de la base de datos public DataTable ObtenerProducto() { DataTable dtProducto = new DataTable("Producto"); SqlConnection sqlCon = new SqlConnection(); try { //1. Establecer la cadena de conexion sqlCon.ConnectionString = Conexion.cn; //2. Establecer el comando SqlCommand sqlCmd = new SqlCommand(); sqlCmd.Connection = sqlCon;//La conexion que va a usar el comando sqlCmd.CommandText = "spF_Producto_All";//El comando a ejecutar sqlCmd.CommandType = CommandType.StoredProcedure;//Decirle al comando que va a ejecutar una sentencia SQL //3. No hay parametros //4. El DataAdapter que va a ejecutar el comando y es el encargado de llena el DataTable SqlDataAdapter sqlDat = new SqlDataAdapter(sqlCmd); sqlDat.Fill(dtProducto);//Llenamos el DataTable } catch (Exception ex) {

dtProducto = null; } return dtProducto; } #region Metodos Get y Set public int codigoProducto { get { return var_codigoProducto; } set { var_codigoProducto = value; } } public string nombre { get { return var_nombre; } set { var_nombre = value; } } public decimal precio { get { return var_precio; } set { var_precio = value; } } #endregion } } 3.3. Clase DetalleVenta Esta clase se encarga de conectar la tabla DetalleVenta con C# using System; using System.Collections.Generic; using System.Text; //Impotaciones necesarias using System.Data; using System.Data.SqlClient; //Desarrollado por Henry Joe Wong Urquiza namespace CapaDatos { public class DetalleVenta {

private int var_codigoVenta; private int var_codigoProducto; private decimal var_cantidad; private decimal var_descuento; //Constructor vacio public DetalleVenta() { } //Constructor con parametros public DetalleVenta( int codigoVenta , int codigoProducto , decimal cantidad , decimal descuento ) { this.var_codigoVenta=codigoVenta; this.var_codigoProducto=codigoProducto; this.var_cantidad=cantidad; this.var_descuento=descuento; } //Metodo utilizado para insertar un DetalleVenta //Le pasamos la conexion y la transaccion por referencia, debido a que esos datos lo obtenemos //de la clase Venta y no deberiamos crear una nueva Conexion o una nueva Transaccion //sino la creada por la clase Venta public string Insertar(DetalleVenta varDetalleVenta, ref SqlConnection sqlCon, ref SqlTransaction sqlTra) { string rpta = ""; try { //1. Establecer el comando SqlCommand sqlCmd = new SqlCommand(); sqlCmd.Connection = sqlCon; sqlCmd.Transaction = sqlTra; sqlCmd.CommandText = "spI_DetalleVenta"; sqlCmd.CommandType = CommandType.StoredProcedure;

//4. Agregar los parametros al comando //Establecemos los valores para el parametro @codigoVenta del Procedimiento Almacenado SqlParameter sqlParcodigoVenta = new SqlParameter(); sqlParcodigoVenta.ParameterName = "@codigoVenta"; sqlParcodigoVenta.SqlDbType = SqlDbType.Int; sqlParcodigoVenta.Value = varDetalleVenta.codigoVenta; sqlCmd.Parameters.Add(sqlParcodigoVenta); //Agregamos el parametro al comando //Establecemos los valores para el parametro @codigoProducto del Procedimiento Almacenado SqlParameter sqlParcodigoProducto = new SqlParameter(); sqlParcodigoProducto.ParameterName = "@codigoProducto"; sqlParcodigoProducto.SqlDbType = SqlDbType.Int; sqlParcodigoProducto.Size = 4; sqlParcodigoProducto.Value = varDetalleVenta.codigoProducto; sqlCmd.Parameters.Add(sqlParcodigoProducto); //Agregamos el parametro al comando //Establecemos los valores para el parametro @cantidad del Procedimiento Almacenado SqlParameter sqlParcantidad = new SqlParameter(); sqlParcantidad.ParameterName = "@cantidad"; sqlParcantidad.SqlDbType = SqlDbType.Decimal; sqlParcantidad.Precision = 18; sqlParcantidad.Scale = 2; sqlParcantidad.Value = varDetalleVenta.cantidad; sqlCmd.Parameters.Add(sqlParcantidad); //Agregamos el parametro al comando //Establecemos los valores para el parametro @descuento del Procedimiento Almacenado SqlParameter sqlPardescuento = new SqlParameter(); sqlPardescuento.ParameterName = "@descuento"; sqlPardescuento.SqlDbType = SqlDbType.Decimal; sqlParcantidad.Precision = 18; sqlParcantidad.Scale = 2; sqlPardescuento.Value = varDetalleVenta.descuento; sqlCmd.Parameters.Add(sqlPardescuento); //Agregamos el parametro al comando //5. Ejecutamos el commando rpta = sqlCmd.ExecuteNonQuery() == 1 ? "OK" : "No se inserto el detalle de venta de forma correcta";

} catch (Exception ex) { rpta = ex.Message; } return rpta; } #region Metodos Get y Set public int codigoVenta { get { return var_codigoVenta; } set { var_codigoVenta = value; } } public int codigoProducto { get { return var_codigoProducto; } set { var_codigoProducto = value; } } public decimal cantidad { get { return var_cantidad; } set { var_cantidad = value; } } public decimal descuento { get { return var_descuento; } set { var_descuento = value; } } #endregion } } 3.4. Clase Venta Esta clase se encarga de conectar la tabla Venta con C# using System; using System.Collections.Generic; using System.Text; //Impotaciones necesarias

using System.Data; using System.Data.SqlClient; //Desarrollado por Henry Joe Wong Urquiza namespace CapaDatos { public class Venta { private int var_codigoVenta; private string var_cliente; private DateTime var_fecha; //Constructor vacio public Venta() { } //Constructor con parametros public Venta(int codigoVenta,string cliente,DateTime fecha) { this.var_codigoVenta=codigoVenta; this.var_cliente=cliente; this.var_fecha=fecha; } //Metodo utilizado para insertar un Venta public string Insertar(Venta varVenta, List<DetalleVenta> detalles) { string rpta = ""; SqlConnection sqlCon = new SqlConnection(); try { //1. Establecer la cadena de conexion sqlCon.ConnectionString = Conexion.cn; //2. Abrir la conexion de la BD sqlCon.Open(); //3. Establecer la transaccion SqlTransaction sqlTra = sqlCon.BeginTransaction(); //4. Establecer el comando SqlCommand sqlCmd = new SqlCommand();

sqlCmd.Connection = sqlCon; sqlCmd.Transaction = sqlTra; sqlCmd.CommandText = "spI_Venta"; sqlCmd.CommandType = CommandType.StoredProcedure; //5. Agregar los parametros al comando //Establecemos los valores para el parametro @codigoVenta del Procedimiento Almacenado SqlParameter sqlParcodigoVenta = new SqlParameter(); sqlParcodigoVenta.ParameterName = "@codigoVenta"; sqlParcodigoVenta.SqlDbType = SqlDbType.Int; sqlParcodigoVenta.Direction = ParameterDirection.Output; sqlCmd.Parameters.Add(sqlParcodigoVenta); //Agregamos el parametro al comando //Establecemos los valores para el parametro @cliente del Procedimiento Almacenado SqlParameter sqlParcliente = new SqlParameter(); sqlParcliente.ParameterName = "@cliente"; sqlParcliente.SqlDbType = SqlDbType.VarChar; sqlParcliente.Size = 100; sqlParcliente.Value = varVenta.cliente; sqlCmd.Parameters.Add(sqlParcliente); //Agregamos el parametro al comando //6. Ejecutamos el commando rpta = sqlCmd.ExecuteNonQuery() == 1 ? "OK" : "No se inserto el detalle de venta de forma correcta"; if (rpta.Equals("OK")) { //Obtenemos el codigo de la venta que se genero por la base de datos this.codigoVenta=Convert.ToInt32(sqlCmd.Parameters["@codigoVenta"].Value); foreach(DetalleVenta det in detalles){ //Establecemos el codigo de la venta que se autogenero det.codigoVenta = this.codigoVenta; //Llamamos al metodo insertar de la clase DetalleVenta //y le pasamos la conexion y la transaccion que debe de usar rpta = det.Insertar(det, ref sqlCon, ref sqlTra); if (!rpta.Equals("OK")) { //Si ocurre un error al insertar un detalle de venta salimos del for break; } } }

if (rpta.Equals("OK")) { //Se inserto todo los detalles y confirmamos la transaccion sqlTra.Commit(); } else { //Algun detalle no se inserto y negamos la transaccion sqlTra.Rollback(); } } catch (Exception ex) { rpta = ex.Message; } finally { //6. Cerramos la conexion con la BD if (sqlCon.State == ConnectionState.Open) sqlCon.Close(); } return rpta; } //Obtenemos la venta por el codigo generado public DataTable ObtenerVenta(int codigoVenta) { DataTable dtVenta = new DataTable("Venta"); SqlConnection sqlCon = new SqlConnection(); try { //1. Establecer la cadena de conexion sqlCon.ConnectionString = Conexion.cn; //2. Establecer el comando SqlCommand sqlCmd = new SqlCommand(); sqlCmd.Connection = sqlCon;//La conexion que va a usar el comando sqlCmd.CommandText = "spF_Venta_One";//El comando a ejecutar sqlCmd.CommandType = CommandType.StoredProcedure;//Decirle al comando que va a ejecutar una sentencia SQL //3. Agregar los parametros al comando

//Establecemos los valores para el parametro @codigoVenta del Procedimiento Almacenado SqlParameter sqlParcodigoVenta = new SqlParameter(); sqlParcodigoVenta.ParameterName = "@codigoVenta"; sqlParcodigoVenta.SqlDbType = SqlDbType.Int; sqlParcodigoVenta.Value = codigoVenta; sqlCmd.Parameters.Add(sqlParcodigoVenta); //Agregamos el parametro al comando //4. El DataAdapter que va a ejecutar el comando y es el encargado de llena el DataTable SqlDataAdapter sqlDat = new SqlDataAdapter(sqlCmd); sqlDat.Fill(dtVenta);//Llenamos el DataTable } catch (Exception ex) { dtVenta = null; } return dtVenta; } //Obtener todas las ventas public DataTable ObtenerVenta() { DataTable dtVenta = new DataTable("Venta"); SqlConnection sqlCon = new SqlConnection(); try { //1. Establecer la cadena de conexion sqlCon.ConnectionString = Conexion.cn; //2. Establecer el comando SqlCommand sqlCmd = new SqlCommand(); sqlCmd.Connection = sqlCon;//La conexion que va a usar el comando sqlCmd.CommandText = "spF_Venta_All";//El comando a ejecutar sqlCmd.CommandType = CommandType.StoredProcedure;//Decirle al comando que va a ejecutar una sentencia SQL //3. No hay parametros //4. El DataAdapter que va a ejecutar el comando y es el encargado de llena el DataTable SqlDataAdapter sqlDat = new SqlDataAdapter(sqlCmd);

sqlDat.Fill(dtVenta);//Llenamos el DataTable } catch (Exception ex) { dtVenta = null; } return dtVenta; } #region Metodos Get y Set public int codigoVenta { get { return var_codigoVenta; } set { var_codigoVenta = value; } } public string cliente { get { return var_cliente; } set { var_cliente = value; } } public DateTime fecha { get { return var_fecha; } set { var_fecha = value; } } #endregion } } 4. RESUMEN Al final deberamos tener las siguientes clases

Publicado en: c#,capa de datos con c#,henry wong,henry wong urquiza,hwongu,ingenieria de computacion y sistemas,modelo de tres capas,upao,upao sistemas Direccin corta para compartir: 29 COMENTARIOS:
http://bit.ly/fE

Annimo dice: 2:55 p.m. Contestar MUY BUENO TU TUTORIAL AMIGO, LO ESTOY ANALIZANDO COMPLETAMENTE Y ME PARECE MUY INTERESANTE, HASTA DA TRISTEZA VER QUE NO HAY COMENTARIOS... TAL VEZ SEA PORQUE AL PONER UN COMENTARIO TE REDIRECCIONA A OTRA PGINA.... SALUDOS!!

Henry Wong dice: 3:04 p.m. Contestar Muchas gracias por lo saludos ... Y sguenos por facebook para que te avise cada vez que subimos un nuevo tutorial.

Annimo dice: 4:01 p.m. Contestar esta muy padre el tutorial me a ayudado mucho, muchas gracias

Annimo dice: 5:41 p.m. Contestar Excelente tutorial, me ah sido de gran ayuda para aprender a implementar capas y para algunos problemas que tenia para usar store procedures, gracias Henry.

Henry Wong dice: 7:45 p.m. Contestar Gracias a ustedes por la confianza :D

favitososispecial dice: 6:12 p.m. Contestar me gustaria implementar en la logica de negocio algo para en una tabla de la base de datos almacenar los errores menejo de errores graicas ojala me ayuden

iSaias_19 dice: 12:18 p.m. Contestar Interesante aunque porque ocupar DataSet y DataTables ??? por que no uno o lo otro saludos y gracias.

Henry Wong dice: 4:55 p.m. Contestar

Es por motivos didcticos, para que aprendan a usar los dos

Mueco dice: 1:25 p.m. Contestar Exelente tutorial Henry mira estoy probando el codigo y esta exelente para nosotros los novatos en el desarrollo solo tengo una duda no se sime podrias decir que signnifica esta barible rpta = ""; y anteMano muchas gracias aprendi cosas nuevas

Mueco dice: 1:31 p.m. Contestar Excelente tutorial, me ah sido de gran ayuda para comprender a la implementacion del procesode las capas y el uso de los procedimientos almacenados solo tengo una duda no si me podrias decir que significa la variable string rpta = ""; si no es mucha molestia, gracias Henry

Henry Wong dice: 9:54 a.m. Contestar rpta viene a ser como una variable que dice la RESPUESTA de lo que esta sucediendo con ese mtodo.

Cristyan Valera dice: 10:13 p.m. Contestar Revisando el tutorial, me ha parecido interesante el enfoque que le das, tambien que lo haces facil para los que talves no entendamos mucho..:D. Muy buen tutorial, continua asi. Saludos

Annimo dice: 10:20 a.m. Contestar

Como Te comente en la primera parte, excelente tutorial la verdad me dio todas las luces porque estoy apenas iniciando con asp.net y sql server. Gracias por dedicar tiempo a este tema...

Annimo dice: 5:02 p.m. Contestar hey muy buen aporte me servira mucho para mi proyecto Grasias !!!!!1

Mueco dice: 10:09 p.m. Contestar Buelvo acomentar exelente tutorial,pero analizandolo me surgio una duda como le ago para realizar esta misma aplicacion pero en web haciendo uso de ASP Con SQl Server.Espero una respuesta.

Henry Wong dice: 9:29 a.m. Contestar Solo tienes que cambiar la capa de

MARTES, FEBRERO 22, 2011 C# - APLICACIN DE ESCRITORIO, SISTEMAS DE VENTAS PART III CREACIN DE LA CAPA DE NEGOCIOS 10:15 P.M. HENRY JOE WONG URQUIZA 8 COMENTARIOS

"Si usa algn cdigo del siguiente tutorial, den el icono de ME GUSTA del Facebook que se encuentra en su mano derecha, para que se vuelva Seguidor del Blog y tambin comentenos que tal les pareci el tutorial"

1. ENTORNO

Visual Studio 2008 SQL Server 2008

2. INTRODUCCIN Ya vimos que en la Parte II del tutorial creamos la Capa de Dato de nuestro sistema, la cual es la encargada de comunicarse con la base de datos. Ahora nos tocara desarrollar la Capa de Negocios que es la capa en la cual se implementa la lgica del negocio de la empresa como obtener descuentos, aumentos, etc. 3. DESARROLLO 3.1. Creando el proyecto Ahora debemos de agregar a nuestro proyecto un proyecto del tipo biblioteca de clases que se llamara "CapaNegocios"

3.2. Agregando al referencia con la Capa de Datos Debemos de establecer la comunicacion entre la Capa de Negocios y la Capa de Datos. Para eso hacemos clic derecho en nuestro proyecto que se llama "CapaNegocios" y nos vamos a la opcion de "Agregar Referencia"

Y de ah seleccionamos que se comunique con el proyecto que se llama "CapaDatos"

3.3. Clase NegProducto La clase "NegProducto" se encarga de comunicarse con la clase "Producto" de la capa de datos using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; //Para que se comunique con la Capa de Datos using CapaDatos; //Desarollado por Henry Joe Wong Urquiza namespace CapaNegocios { public class NegProducto { //Metodo que llama al metodo Insertar de la Capa de Datos //de la clase Producto public static string Insertar(string Nombre, decimal Precio) { Producto pro = new Producto(); pro.nombre = Nombre; pro.precio = Precio; return pro.Insertar(pro); } //Metodo que llama al metodo Actualizar de la Capa de Datos //de la clase Producto public static string Actualizar(int CodigoProducto, string Nombre, decimal Precio) { Producto pro = new Producto(); pro.codigoProducto = CodigoProducto; pro.nombre = Nombre; pro.precio = Precio; return pro.Actualizar(pro);

} //Metodo que se encarga de llamar al metodo ObtenerProducto //de la clase Producto public static DataTable ObtenerProducto() { return new Producto().ObtenerProducto(); } } }

3.4. Clase NegDetalleVenta

La clase "NegDetalleVenta" se encarga de establecer los descuentos de los detalles de venta. Si el subtotal supera los 50 soles, dolares, euros, etc se le aplica un descuento del 5% del detalle de la venta. Y eso se aplica en la Capa de Negocios debido a que pertenece a la lgica de la empresa.

using System; using System.Collections.Generic; using System.Linq; using System.Text; //Desarollado por Henry Joe Wong Urquiza namespace CapaNegocios { public class NegDetalleVenta { //Metodo utilizado para obtener el descuento del detalle de la venta //si la venta supera los 50 soles, dolares, euros, etc //se le hace un descuento del 5% del detalle de la venta public static decimal ObtenerDescuento(decimal cantidad, decimal pu) { if ((cantidad * pu) > 50) { decimal porcentaje = Convert.ToDecimal(0.05); decimal descuento = ((cantidad * pu) * porcentaje); return descuento; } else {

return 0; } } } } 3.5. Clase NegVenta using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; //Para que se comunique con la Capa de Datos using CapaDatos; //Desarollado por Henry Joe Wong Urquiza namespace CapaNegocios { public class NegVenta { //Metodo que llama al metodo Insertar de la Capa de Datos //de la clase Venta public static string Insertar(string cliente, DataTable dtDetalles) { Venta venta = new Venta(); venta.cliente = cliente; List<DetalleVenta> detalles=new List<DetalleVenta>(); foreach (DataRow row in dtDetalles.Rows) { DetalleVenta detalle = new DetalleVenta(); detalle.codigoProducto = Convert.ToInt32(row["codigoProducto"].ToString()); detalle.cantidad = Convert.ToDecimal(row["cantidad"].ToString()); detalle.descuento = NegDetalleVenta.ObtenerDescuento(detalle.cantidad, Convert.ToDecimal(row["PU"].ToString())); detalles.Add(detalle); } return venta.Insertar(venta, detalles); } //Metodo que se encarga de llamar al metodo ObtenerProducto //de la clase Venta public static DataTable ObtenerVenta() {

return new Venta().ObtenerVenta(); } //Metodo que se encarga de llamar al metodo ObtenerProducto //por codigo de la clase Venta public static DataTable ObtenerVenta(int codigoVenta) { return new Venta().ObtenerVenta(codigoVenta); } } }

4. RESUMEN Al final deberamos tener las siguientes clases