Você está na página 1de 55

C# - APLICACIÓN DE ESCRITORIO, SISTEMAS DE

VENTAS PARTE I - CREACIÓN DE LA BASE


DATOS

1. ENTORNO
• SQL Server 2008
• Visual Studio 2008

2. INTRODUCCIÓN

En el siguiente tutorial vamos a desarrollar un sistema de ventas usando el lenguaje de


programación C# y como base de datos vamos a usar el SQL Server 2008 y tambien
crearemos un reporte con Crystal Report. La base de datos que vamos a crear es una base de
datos con fines didácticos, dado que nos faltaría crear mas tablas, como la tabla cliente,
categoría, unidad de medida, etc pero si nos explayamos mucho nos quedaría muy largo el
tutorial. Ademas en el ejemplo no se explica como disminuir un stock, debido a que eso
siempre se les pide a los alumnos universitario que investiguen como hacerlo, pero si quieren
una ayudita lo pueden hacer creando Triggers en la base de datos.

3. DESARROLLO

En esta primera parte del tutorial vamos a crear la base de datos en SQL Server 2008, la base
de datos se llamara BDTutorial

3.1. Diseño de la base de datos

La base de datos tendría las siguientes tablas: Venta, Producto y DetalleVenta


Ademas la columna "codigoVenta" de la tabla "Venta" tiene un valor de identidad, eso quiere
decir que su valor es auto incremental que comienza en uno e incrementa de uno en uno.
Lo mismo sucedería con la columna "codigoProducto" de la tabla Producto

3.2. Creando los procedimientos almacenados


Según Wikipedia un procedimiento almacenado (stored procedure en inglés) es un programa (o
procedimiento) el cual es almacenado físicamente en una base de datos. Su implementación
varía de un manejador de bases de datos a otro. La ventaja de un procedimiento almacenado
es que al ser ejecutado, en respuesta a una petición de usuario, es ejecutado directamente en
el motor de bases de datos, el cual usualmente corre en un servidor separado. Como tal, posee
acceso directo a los datos que necesita manipular y sólo necesita enviar sus resultados de
regreso al usuario, deshaciéndose de la sobrecarga resultante de comunicar grandes
cantidades de datos salientes y entrantes.

3.2.1. Procedimientos Almacenados para la tabla Producto

/*
----------------------------------------------------
CREADO:
POR :HENRY JOE WONG URQUIZA
FECHA:22FEB2011
PROCEDIMIENTO ALMACENADO UTILIZADO PARA INSERTAR UN
PRODUCTO A LA BASE DE DATOS
----------------------------------------------------
*/
CREATE PROC dbo.spI_Producto
@codigoProducto int = Null OUTPUT,
@nombre varchar(100) = Null,
@precio decimal(18, 2) = Null
AS
insert into Producto
(
nombre,
precio
)
VALUES(
@nombre,
@precio
)
--Obteniendo el codigo autogenerado de producto
SET @codigoProducto = @@IDENTITY;
GO
/*
----------------------------------------------------
CREADO:
POR :HENRY JOE WONG URQUIZA
FECHA:22FEB2011
PROCEDIMIENTO ALMACENADO UTILIZADO PARA ACTUALIZAR UN
PROCEDUCTO A LA BASE DE DATOS
----------------------------------------------------
*/
CREATE PROC dbo.spU_Producto
@codigoProducto int = Null,
@nombre varchar(100) = Null,
@precio decimal(18, 2) = Null
AS

UPDATE Producto
SET
nombre = @nombre,
precio = @precio
WHERE
codigoProducto = @codigoProducto
GO
/*
----------------------------------------------------
CREADO:
POR :HENRY JOE WONG URQUIZA
FECHA:22FEB2011
PROCEDIMIENTO ALMACENADO UTILIZADO PARA OBTENER TODOS
LOS PRODUCTOS DE LA BASE DE DATOS
----------------------------------------------------
*/
CREATE PROC dbo.spF_Producto_All
AS
SELECT
p.codigoProducto,
p.nombre,
p.precio
FROM
Producto p
ORDER BY
P.nombre

3.2.2. Procedimientos Almacenados para la tabla Venta

/*
----------------------------------------------------
CREADO:
POR :HENRY JOE WONG URQUIZA
FECHA:22FEB2011
PROCEDIMIENTO ALMACENADO UTILIZADO PARA INSERTAR UNA
VENTA A LA BASE DE DATOS
----------------------------------------------------
*/
CREATE PROC dbo.spI_Venta
@codigoVenta int = Null OUTPUT,
@cliente varchar(100) = Null
AS

insert into Venta


(
cliente,
fecha
)
VALUES(
@cliente,
GETDATE()
)
--Obteniendo el codigo autogenerado de la venta
SET @codigoVenta = @@IDENTITY
GO

/*
----------------------------------------------------
CREADO:
POR :HENRY JOE WONG URQUIZA
FECHA:22FEB2011
PROCEDIMIENTO ALMACENADO UTILIZADO PARA OBTENER EL
REPORTE DE LA VENTA DE LA BASE DE DATOS
----------------------------------------------------
*/
CREATE PROCEDURE dbo.spF_Venta_One
@codigoVenta int
AS
SELECT
v.codigoVenta AS CodigoVenta,
v.cliente AS Cliente,
v.fecha AS Fecha,
d.codigoProducto AS CodigoProducto,
p.nombre AS Nombre,
p.precio AS Precio,
d.cantidad AS Cantidad,
d.descuento AS Descuento,
p.precio*d.cantidad AS Parcial,
((p.precio*d.cantidad)-d.descuento) AS SubTotal,
(
SELECT
SUM((dT.cantidad * pT.precio)-dT.descuento) AS TotalPagar
FROM
DetalleVenta AS dT INNER JOIN
Producto AS pT ON dT.codigoProducto = pT.codigoProducto
WHERE
dT.codigoVenta=v.codigoVenta
) AS TotalPagar
FROM
Venta AS v INNER JOIN
DetalleVenta AS d ON v.codigoVenta = d.codigoVenta INNER JOIN
Producto AS p ON d.codigoProducto = p.codigoProducto
WHERE
v.codigoVenta=@codigoVenta
ORDER BY
Nombre

GO

/*
----------------------------------------------------
CREADO:
POR :HENRY JOE WONG URQUIZA
FECHA:22FEB2011
PROCEDIMIENTO ALMACENADO UTILIZADO PARA OBTENER TODAS
LAS VENTAS DE LA BASE DE DATOS
----------------------------------------------------
*/
CREATE PROCEDURE dbo.spF_Venta_All
AS
SELECT
v.codigoVenta AS CodigoVenta,
v.cliente AS Cliente,
v.fecha AS Fecha,
d.codigoProducto AS CodigoProducto,
p.nombre AS Nombre,
p.precio AS Precio,
d.cantidad AS Cantidad,
d.descuento AS Descuento,
p.precio*d.cantidad AS Parcial,
((p.precio*d.cantidad)-d.descuento) AS SubTotal,
(
SELECT
SUM((dT.cantidad * pT.precio)-dT.descuento) AS TotalPagar
FROM
DetalleVenta AS dT INNER JOIN
Producto AS pT ON dT.codigoProducto = pT.codigoProducto
WHERE
dT.codigoVenta=v.codigoVenta
) AS TotalPagar
FROM
Venta AS v INNER JOIN
DetalleVenta AS d ON v.codigoVenta = d.codigoVenta INNER JOIN
Producto AS p ON d.codigoProducto = p.codigoProducto
ORDER BY
CodigoVenta, Nombre

3.2.3. Procedimientos Almacenados para la tabla DetalleVenta

/*
----------------------------------------------------
CREADO:
POR :HENRY JOE WONG URQUIZA
FECHA:22FEB2011
PROCEDIMIENTO ALMACENADO UTILIZADO PARA INSERTAR UN
DETALLE DE VENTA A LA BASE DE DATOS
----------------------------------------------------
*/
CREATE PROC dbo.spI_DetalleVenta
@codigoVenta int = Null,
@codigoProducto int = Null,
@cantidad decimal(18, 2) = Null,
@descuento decimal(18, 2) = Null
AS
insert into DetalleVenta
(
codigoVenta,
codigoProducto,
cantidad,
descuento
)
VALUES(
@codigoVenta,
@codigoProducto,
@cantidad,
@descuento
)

C# - APLICACIÓN DE ESCRITORIO, SISTEMAS DE


VENTAS PARTE II - CREACIÓN DE LA CAPA DE
DATOS

1. ENTORNO

• SQL Server 2008


• Visual Studio 2008

2. INTRODUCCIÓN

2.1. Programación por capas

La programación por capas es un estilo de programación en el que el objetivo primordial es la


separación de la lógica de negocios de la lógica de diseño. La ventaja principal de este estilo
es que el desarrollo se puede llevar a cabo en varios niveles y, en caso de que sobrevenga
algún cambio, sólo se ataca al nivel requerido sin tener que revisar entre código mezclado. Un
buen ejemplo de este método de programación sería el modelo de interconexión de sistemas
abiertos

2.2. Programación en tres capas

• Capa de presentación: es la que ve el usuario (también se la denomina "capa de


usuario"), presenta el sistema al usuario, le comunica la información y captura la
información del usuario en un mínimo de proceso (realiza un filtrado previo para
comprobar que no hay errores de formato). Esta capa se comunica únicamente con la
capa de negocio. También es conocida como interfaz gráfica y debe tener la
característica de ser "amigable" (entendible y fácil de usar) para el usuario.
• Capa de negocio: es donde residen los programas que se ejecutan, se reciben las
peticiones del usuario y se envían las respuestas tras el proceso. Se denomina capa de
negocio (e incluso de lógica del negocio) porque es aquí donde se establecen todas las
reglas que deben cumplirse. Esta capa se comunica con la capa de presentación, 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. También se
consideran aquí los programas de aplicación.
• Capa de datos: es donde residen los datos y es la encargada de acceder a los
mismos. Está formada por uno o más gestores de bases de datos que realizan todo el
almacenamiento de datos, reciben solicitudes de almacenamiento o recuperación de
información 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 opción "Agregar-->Clase" y la clase que creamos se llamara "Conexion", que se encargara
de guardar la cadena de conexión 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 código 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["@codigoV
enta"].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 deberíamos tener las siguientes clases
C# - APLICACIÓN DE ESCRITORIO, SISTEMAS DE
VENTAS PART III - CREACIÓN DE LA CAPA DE
NEGOCIOS
10:15 PM HENRY WONG 2 COMENTARIOS

"Si usa algún código 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 también
comentenos que tal les pareció el tutorial"

1. ENTORNO

• Visual Studio 2008


• SQL Server 2008

2. INTRODUCCIÓN

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 tocaría desarrollar la Capa de
Negocios que es la capa en la cual se implementa la lógica 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 lógica 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 deberíamos tener las siguientes clases


C# - APLICACIÓN DE ESCRITORIO, SISTEMAS DE
VENTAS PART IV - CREACIÓN DE LA CAPA DE
PRESENTACIÓN
10:27 AM HENRY WONG NO HAY COMENTARIOS

"Si usa algún código 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 también
comentenos que tal les pareció el tutorial"

1. ENTORNO

• SQL Server 2008


• Visual Studio 2008

2. INTRODUCCIÓN

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 aplicación, 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 Presentación 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 diseñada en SQL Server 2008. A mantenimiento
me refiero a los procesos de inserción, actualización y consulta de datos de la tabla Producto.
Debemos de diseñar 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 pestaña del tabControl tenemos los siguientes componentes:

Y su código 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.Tex
t),
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 diseño
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 código 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"].Va
lue);
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 diseño 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
o 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

Y como código 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 confirmación
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 información 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");
}
}

}
}

C# - APLICACIÓN DE ESCRITORIO, SISTEMAS DE


VENTAS PART V - CREACIÓN DE REPORTE
(CRYSTAL REPORT)
4:30 PM HENRY WONG NO HAY COMENTARIOS

"Si usa algún código 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 también
comentenos que tal les pareció el tutorial"

1. ENTORNO
• SQL Server 2008
• Visual Studio 2008

2. INTRODUCCIÓN

Continuando con el tutorial del sistemas de ventas con C#, ahora crearemos el reporte con
Crystal Report que nos mostrara el documento creado producto de la venta que hemos
realizado. Como este es un tutorial con un fin didáctico, para crear el reporte nosotros
escribiremos el código auto generado por la inserción de la venta, aunque lo ideal seria que
desde la capa de negocios obtengamos el código que se genero y se muestre el reporte de
forma automática.

3. DESARROLLO

3.1. Diseño del formulario

Ahora debemos de modificar nuestro formulario que hemos creado anteriormente que se
llamaba frmRegistrarVenta. Si recordamos este formulario tenia un Tab Control con dos
pestañas, una que se llamaba Registrar y otro que se llama Reporte. Y justo en esta ultima
pestaña es donde vamos a poner nuestro reporte. Para poder mostrar los reportes en C#,
debemos de agregar un componente que se llama CrystalReportViewer que se encuentra en
nuestro cuadro de herramientas en el grupo de Informe
Y luego en nuestro formulario hacemos el siguiente diseño
3.2. Creando nuestro DataSet

Para poder crear un reporte para Crystal Reporte, lo primero que se tiene que hacer es crear
un DataSet en donde se almacenara todo nuestro datos de la consulta y nos servira para llenar
nuestro reporte y para eso les prepare el siguiente video para que puedan crear un DataSet de
la manera mas rápida y sencilla.

3.3. Creando nuestro Reporte en Crystal Report

Ahora debemos de diseñar nuestro reporte con la información que obtenemos de nuestro
DataSet que hemos creado anteriormente, para eso también les prepare otro vídeo.

El reporte al final debería tener el siguiente diseño

3.4. Código Fuente

Ahora nos vamos a ir al evento clic del botón "btnReporte" de nuestro formulario
"frmRegistrarVenta" y pondremos el siguiente código fuente

private void btnReporte_Click(object sender, EventArgs e)


{
try
{
//Creamos el documento
CrystalDecisions.CrystalReports.Engine.ReportDocument rpt=new
CrystalDecisions.CrystalReports.Engine.ReportDocument();
//Obtenemos el documento que se encuentra en nustra carpeta
bin\debug\crReporte.rpt
rpt.Load( Application.StartupPath + "\\crReporte.rpt");
//Lleanamos el reporte con la información que obtenemos de la base
de datos
rpt.SetDataSource(NegVenta.ObtenerVenta(Convert.ToInt32(this.txtCo
digoVenta.Text)));
//Establecemos los datos al reporte
this.crvReporte.ReportSource=rpt;
//Refrescamos nuestro reporte
this.crvReporte.RefreshReport();
}
catch (Exception ex)
{
}
}