Introducción
Hola a todos, ahora veremos cómo crear reportes en una arquitectura en capas con Windows Forms, C#, VB.NET, SQL Server, SSRS (SQL Server Reporting Services – RDLC – Report Viewer) y Full Programación Orientada a Objetos.
En esta ocasión crearemos un reporte de ventas por rango de fechas y periodos, divididos en dos partes: un resumen general y las ventas a detalle, por ejemplo, las ventas de la fecha actual, los últimos 7 días, del mes actual, los últimos 30 días, del año actual o cualquier fecha personalizada. Ademas de agrupar las ventas netas por periodos, es decir, agrupar por días, semanas, meses o años, dependiendo al rango de fechas del reporte. Por otro lado las funciones de búsqueda de datos y exportar a PDF, Excel, Word o poder imprimir el reporte.
Observaciones
Reportes y Arquitectura en Capas
Ya mencioné en varios vídeos y artículos: La arquitectura en capas generalmente se divide en tres capas de aplicación y está destinada para aplicaciones complejas, puedes utilizar cualquier otra arquitectura según necesidades y complejidad de la aplicación, por ejemplo, si la aplicación es pequeña y con poca lógica de negocio bastará utilizar la arquitectura MVC, MVP, o uno personalizado. Solo recuerda en separar responsabilidades agrupar clases o componentes y organizar el código para obtener una buena estructura.
En este caso usaremos la arquitectura en capas ya que es la estructura más popular entre los programadores, bien recuerden que:
- La capa de presentación solamente es responsable de manejar la interfaz gráfica de usuario como vistas renderizadas , archivos HTML, la interfaz de línea de comandos o los formularios de una aplicación de escritorio.
- La capa de dominio o negocio es responsable de las reglas comerciales y el flujo de trabajo, que determina como se puede crear, validar, realizar cálculos, almacenar y cambiar los datos de un objeto comercial.
- La capa de acceso a datos es responsable de almacenar u obtener datos desde un almacén de datos, como una base de datos, un servicio externo o un archivo plano.
El conjunto de datos, archivo y diseño de los reportes se crean en la capa de presentación (Visor de reportes y los archivos de datos del generador de informes). Sin embargo en muchas ocasiones cuando somos principiantes, accedemos a la base de datos y ejecutamos comandos SQL directamente desde los reportes de la capa de presentación, además de colocar algunas reglas comerciales como validaciones, cálculos complejos u otras actividades relacionado a negocios.
Esto es un grave error, estamos en contra de los principios de la arquitectura en capas y la programación orientada a objetos.
Acceder a la base de datos y ejecutar comandos SQL es responsabilidad de la capa de acceso a datos, y realizar cálculos o validaciones es responsabilidad de la capa de dominio, en cuanto al conjunto de datos, archivo y diseño de los reportes es responsabilidad de la capa de presentación . Del mismo modo si utilizas la arquitectura MVC, el modelo es quien se encarga de gestionar todos los datos e implementar las reglas del negocio.
Si bien es cierto que cualquier generador de reportes permite acceder a la base de datos y realizar validaciones y cálculos, entonces puedes usarlos con fines de prueba práctica o aplicaciones muy simples que trabajan a una sola capa.
Por otro lado, tener en cuenta que las imágenes mostradas de la arquitectura en capas es una representación gráfica muy superficial. En una aplicación muy compleja con muchas reglas de negocio, cada capa puede tener muchos componentes o sub-capas, además de agregar otras capas con sus propias responsabilidades, por ejemplo, la capa de aplicación, la capa de infraestructura, en ella la capa de soporte, acceso a datos, servicios externos o servicios de correo electrónico.
Recuerden que la estructura de las capas puede cambiar según necesidades y complejidad de la aplicación, en donde cada capa puede tener su propia arquitectura, cada componente puede tener su propio micro-arquitectura o cada clase o conjunto de clases puede tener su propia estructura, por ejemplo, puedes estructurar la capa de presentación utilizando el patrón modelo vista controlador (MVC) y si es una aplicación de escritorio, puedes usar el patrón modelo vista presentador (MVP). Pero a menudo, las aplicaciones que realizamos con fines de práctica o formación, son pequeñas, con poca lógica de negocio, entonces bastará utilizar únicamente estas tres capas, sin ningún componente, sub-capa o capas adicionales.
Tutorial
Bueno, espero que la introducción haya aclarado algunas cosas sobre crear reportes con un arquitectura en capas, ahora empecemos a crear la base de datos y aplicación.
Base de Datos
Tenemos 4 tablas relacionadas de una orden de venta y los miles y miles de inserciones de datos. Puedes descargar desde el botón de abajo el script completo de la base de datos y así puedas y realizar la práctica.
Crear Base de Datos Relacional (BDR)
Diagrama
Script
create database BikeStore create table products ( product_id int identity (1,1) primary key, product_name varchar (200) NOT NULL, model_year smallint NOT NULL, price decimal (10, 2) NOT NULL ); CREATE TABLE customers ( customer_id INT IDENTITY (1, 1) PRIMARY KEY, first_name VARCHAR (255) NOT NULL, last_name VARCHAR (255) NOT NULL, phone VARCHAR (25), email VARCHAR (255) NOT NULL, street VARCHAR (255), city VARCHAR (50), state VARCHAR (25), zip_code VARCHAR (5) ); create table orders ( order_id int identity (1,1) primary key, customer_id int not null, order_date date not null, constraint FK_Customer foreign key (customer_id) references customers(customer_id) ); create table order_items ( order_item_id int identity (1,1) primary key, order_id int not null, product_id INT NOT NULL, quantity INT NOT NULL, price DECIMAL (10, 2) NOT NULL, discount DECIMAL (4, 2) NOT NULL DEFAULT 0, constraint fk_Order foreign key (order_id) references orders(order_id), constraint fk_Product foreign key (product_id) references products(product_id) );
Consulta SQL/Procedimiento – Reporte de Ventas Detallada por Rango de Fechas
Para realizar reportes, es simplemente hacer consultas a la base de datos, por ejemplo, un reporte de listado y stock de productos, reporte de productos que sean del modelo 2019, un reporte de clientes o un reporte general de ventas.
En este caso, en una única consulta , mostraremos un reporte de ventas a todo detalle, es decir, el ID de la venta, la fecha, el cliente, el nombre del producto, la cantidad del producto vendido y el monto total de la venta en un rango de fechas. Además de esta única consulta; desde la capa de dominio de la aplicación, agruparemos las ventas netas totales por períodos, ya sea por días, semanas, meses o años, dependiendo del rango de fecha.
Si deseas puedes crear un procedimiento almacenado para mostrar la consulta ( ver pestaña 2) e invocar el procedimiento desde la capa de acceso a datos de la aplicación.
select o.order_id, o.order_date, c.first_name+', '+c.last_name as customer, products=stuff((select ' - ' +'x'+convert(varchar (10),oi2.quantity)+' '+ product_name from order_items oi2 inner join products on products.product_id= oi2.product_id where oi2.order_id = oi1.order_id for xml path('')), 1, 2, ''), sum((quantity*price)-discount) as total_amount from orders o inner join customers c on c.customer_id=o.customer_id inner join order_items oi1 on oi1.order_id =o.order_id where o.order_date between '2017/01/01' and '2017/12/30' group by o.order_id, oi1.order_id, o.order_date, c.first_name, c.last_name order by o.order_id asc
create proc getSalesOrder @fromDate Date, @toDate Date as select o.order_id, o.order_date, c.first_name+', '+c.last_name as customer, products=stuff((select ' - ' +'x'+convert(varchar (10),oi2.quantity)+' '+ product_name from order_items oi2 inner join products on products.product_id= oi2.product_id where oi2.order_id = oi1.order_id for xml path('')), 1, 2, ''), sum((quantity*price)-discount) as total_amount from orders o inner join customers c on c.customer_id=o.customer_id inner join order_items oi1 on oi1.order_id =o.order_id where o.order_date between @fromDate and @toDate group by o.order_id, oi1.order_id, o.order_date, c.first_name, c.last_name order by o.order_id asc go
Aplicación
Una vez creado la base de datos, crear las 4 tablas relacionadas, insertar los registros de la orden de venta, haber probado la consulta anterior para obtener las ventas a detalle o haber creado el procedimiento almacenado, pasemos a estructurar la aplicación.
Crear Proyecto en Capas – Visual Studio
- Creamos una solución en blanco de Visual Studio (Archivo-> Nuevo-> Proyecto-> Plantillas-> Otros tipos de proyectos -> Soluciones de Visual Studio-> Solución en Blanco) y asígnele el nombre que desee.
- Agregamos un proyecto nuevo de tipo Aplicación de Windows Forms para la Capa de Presentación.
- Agregamos un proyecto nuevo de tipo Biblioteca de Clases para la Capa de Dominio o Negocio.
- Agregamos un proyecto nuevo de tipo Biblioteca de Clases para la Capa de Acceso a Datos o Persistencia.
Agregar referencias entre capas (Dependecias)
- Agregamos las referencias entre capas según la arquitectura tradicional en capas, donde una capa superior sólo conoce la capa inmediatamente debajo de ella.
- En Capa de Presentación: Referenciamos a la Capa de Dominio.
- En Capa de Dominio: Referenciamos a la Capa de Acceso a Datos.
Una vez creado y agregar las referencias entre capas, pasemos a codificar las capas.
Capa de acceso a Datos
Clase Conexión (ConnectionSql.cs/vb)
- Agreguemos una clase abstracta para la conexión a SQL Server.
- Importamos la librería System.Data.SqlClient.
- Creamos un método protegido de tipo SqlConnection para obtener la conexión.
- En el método creado, simplemente retornamos una instancia de conexión a sql, como parámetro, enviamos la cadena de conexión, servidor local, indicamos la base de datos, y nos conectamos mediante las credenciales de Windows.
public abstract class ConnectionSql { protected SqlConnection getConnection() { return new SqlConnection( "Server=(local); DataBase=BikeStore; integrated security=true" ); } }
Public MustInherit Class ConnectionSql Protected Function getConnection() As SqlConnection Return New SqlConnection( "Server=(local); DataBase=BikeStore; integrated security=true") End Function End Class
Clase Objeto de Acceso a Datos Orden (OrderDao.cs)
- Agregamos otra clase publica para el objeto de acceso a datos de la entidad órdenes de venta.
- Indicamos que la clase hereda de la clase conexión a SQL.
- Importamos las librería System.Data y System.DataSqlClient.
- Creamos un método de tipo DataTable o List<Object> para obtener las órdenes de venta por rango de fecha, para ello creamos 2 parámetros,una para la fecha de inicio y la otra para fecha final de la consulta.
- Agregamos lo siguiente códigos para realizar la consulta.
public class OrderDao:ConnectionSql { public DataTable getSalesOrder(DateTime fromDate, DateTime toDate) { using (var connection = getConnection()) { connection.Open(); using (var command = new SqlCommand()) { command.Connection = connection; command.CommandText = @"getSalesOrder"; command.Parameters.AddWithValue("@fromDate", fromDate ); command.Parameters.AddWithValue("@toDate", toDate ); command.CommandType = CommandType.StoredProcedure; var reader = command.ExecuteReader(); var table = new DataTable(); table.Load(reader ); reader.Dispose(); return table; } } } }
public DataTable getSalesOrder(DateTime fromDate, DateTime toDate) { using (var connection = getConnection()) { connection.Open(); using (var command = new SqlCommand()) { command.Connection = connection; command.CommandText = @"select o.order_id, o.order_date, c.first_name+', '+c.last_name as customer, products=stuff((select ' , ' +'x'+convert(varchar (10),oi2.quantity)+' '+ product_name from order_items oi2 inner join products on products.product_id= oi2.product_id where oi2.order_id = oi1.order_id for xml path('')), 1, 2, ''), sum((quantity*price)-discount) as total_amount from orders o inner join customers c on c.customer_id=o.customer_id inner join order_items oi1 on oi1.order_id =o.order_id where o.order_date between @fromDate and @toDate group by o.order_id, oi1.order_id, o.order_date, c.first_name, c.last_name order by o.order_id asc"; command.CommandType = CommandType.Text; command.Parameters.Add("@fromDate", SqlDbType.Date).Value=fromDate; command.Parameters.Add("@toDate", SqlDbType.Date).Value = toDate; SqlDataReader reader = command.ExecuteReader(); var table = new DataTable(); table.Load(reader); reader.Dispose(); return table; } } } }
Public Class OrderDao Inherits ConnectionSql Public Function getSalesOrder(fromDate As DateTime, toDate As DateTime) As DataTable Using connection = getConnection() connection.Open() Using command = New SqlCommand() command.Connection = connection command.CommandText = "getSalesOrder" command.Parameters.AddWithValue("@fromDate", fromDate) command.Parameters.AddWithValue("@toDate", toDate) command.CommandType = CommandType.StoredProcedure Dim reader = command.ExecuteReader() Dim table = New DataTable() table.Load(reader) reader.Dispose() Return table End Using End Using End Function End Class
Public Function getSalesOrder(fromDate As DateTime, toDate As DateTime) As DataTable Using connection = getConnection() connection.Open() Using command = New SqlCommand() command.Connection = connection command.CommandText = "select o.order_id, o.order_date, c.first_name+', '+c.last_name as customer, products=stuff((select ' , ' +'x'+convert(varchar (10),oi2.quantity)+' '+ product_name from order_items oi2 inner join products on products.product_id= oi2.product_id where oi2.order_id = oi1.order_id for xml path('')), 1, 2, ''), sum((quantity*price)-discount) as total_amount from orders o inner join customers c on c.customer_id=o.customer_id inner join order_items oi1 on oi1.order_id =o.order_id where o.order_date between @fromDate and @toDate group by o.order_id, oi1.order_id, o.order_date, c.first_name, c.last_name order by o.order_id asc" command.CommandType = CommandType.Text command.Parameters.Add("@fromDate", SqlDbType.Date).Value = fromDate command.Parameters.Add("@toDate", SqlDbType.Date).Value = toDate Dim reader As SqlDataReader = command.ExecuteReader() Dim table = New DataTable() table.Load(reader) reader.Dispose() Return table End Using End Using End Function
Capa de Dominio – Negocio
Ahora codificaremos la capa de dominio o negocio, agregamos las siguientes clases/Objetos para guardar el listado de ventas a detalle y para agrupar las ventas netas por periodo.
Clase Listado de Ventas (SalesListing.cs)
public class SalesListing { public int orderId { get; set; } public DateTime orderDate { get; set; } public string customer { get; set; } public string products { get; set; } public double totalAmount { get; set; } }
Public Class SalesListing Public Property orderId As Integer Public Property orderDate As DateTime Public Property customer As String Public Property products As String Public Property totalAmount As Double End Class
Clase Ventas Netas Por Periodo (NetSalesByPeriod.cs)
public class NetSalesByPeriod { public string period { get; set; } public double netSales { get; set; } }
Public Class NetSalesByPeriod Public Property period As String Public Property netSales As Double End Class
Clase Reporte de Ventas (SalesReport.cs)
- Agregamos una clase para el reporte de ventas.
- Importamos la capa de acceso a datos
- Declaramos los atributos y propiedades necesarios para el reporte.
- Declaramos una lista de objetos de tipo listado de ventas para almacenar la consulta de la base de datos.
- Declaramos una lista de objetos de tipo ventas netas por periodo para agrupar las ventas netas por periodo según rango de fechas del reporte.
- Finalmente creamos un método para crear el reporte e inicializar los objetos.
public class SalesReport { //Attributes-Properties public DateTime reportDate { get; private set; } public DateTime startDate { get; private set; } public DateTime endDate{ get; private set; } public List <SalesListing> salesListing { get; private set; } public List<NetSalesByPeriod> netSalesByPeriod { get; private set; } public double totalNetSales { get; private set; } //Methods public void createSalesOrderReport(DateTime fromDate, DateTime toDate) { //implement dates reportDate = DateTime.Now; startDate = fromDate; endDate = toDate; //create sales listing var orderDao = new OrderDao(); var result = orderDao.getSalesOrder(fromDate,toDate ); salesListing = new List<SalesListing>(); foreach (System.Data.DataRow rows in result.Rows) { var salesModel = new SalesListing() { orderId = Convert.ToInt32(rows[0]), orderDate = Convert.ToDateTime(rows[1]), customer = Convert.ToString(rows[2]), products = Convert.ToString(rows[3]), totalAmount = Convert.ToDouble(rows[4]) }; salesListing.Add(salesModel); //calculate total net sales totalNetSales += Convert.ToDouble(rows[4]); } //create net sales by period ////create temp list net sales by date var listSalesByDate = (from sales in salesListing group sales by sales.orderDate into listSales select new { date = listSales.Key, amount = listSales.Sum(item => item.totalAmount) }).AsEnumerable(); ////get number of days int totalDays = Convert.ToInt32((toDate-fromDate ).Days); ////group period by days if (totalDays <= 7) { netSalesByPeriod = (from sales in listSalesByDate group sales by sales.date.ToString("dd-MMM-yyyy") into listSales select new NetSalesByPeriod { period = listSales.Key, netSales = listSales.Sum(item => item.amount) }).ToList(); } ////group period by weeks else if (totalDays <= 30) { netSalesByPeriod = (from sales in listSalesByDate group sales by System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear( sales.date, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Monday) into listSales select new NetSalesByPeriod { period = "Week " + listSales.Key.ToString(), netSales = listSales.Sum(item => item.amount) }).ToList(); } ////group period by months else if (totalDays <= 365) { netSalesByPeriod = (from sales in listSalesByDate group sales by sales.date.ToString("MMM-yyyy") into listSales select new NetSalesByPeriod { period = listSales.Key, netSales = listSales.Sum(item => item.amount) }).ToList(); } ////group period by years else { netSalesByPeriod = (from sales in listSalesByDate group sales by sales.date.ToString("yyyy") into listSales select new NetSalesByPeriod { period = listSales.Key, netSales = listSales.Sum(item => item.amount) }).ToList(); } } }
Public Class SalesReport 'Attributes-Properties Public Property reportDate As Date Public Property startDate As Date Public Property endDate As Date Public Property salesListing As List(Of SalesListing) Public Property netSalesByPeriod As List(Of NetSalesByPeriod) Public Property totalNetSales As Double 'Methods Public Sub createSalesOrderReport(fromDate As Date, toDate As Date) 'implement dates reportDate = Date.Now startDate = fromDate endDate = toDate 'create sales listing Dim orderDao = New OrderDao Dim result = orderDao.getSalesOrder(fromDate, toDate) salesListing = New List(Of SalesListing) For Each row As DataRow In result.Rows Dim salesModel = New SalesListing With { .orderId = Convert.ToInt32(row(0)), .orderDate = Convert.ToDateTime(row(1)), .customer = Convert.ToString(row(2)), .products = Convert.ToString(row(3)), .totalAmount = Convert.ToDouble(row(4)) } salesListing.Add(salesModel) 'calculate total net sales totalNetSales += Convert.ToDouble(row(4)) Next 'create net sales by period 'create temp list net sales by date Dim listSalesByDate = (From sales In salesListing Group sales By keyDateGroup = sales.orderDate Into listSales = Group Select New With { .date = keyDateGroup, .amount = listSales.Sum(Function(item) item.totalAmount) }).AsEnumerable '////get number of days Dim totalDays = Convert.ToInt32((toDate - fromDate).Days) '////group period by days If totalDays <= 7 Then netSalesByPeriod = (From sales In listSalesByDate Group sales By keyDateGroup = sales.date.ToString("dd-MMM-yyyy") Into listSales = Group Select New NetSalesByPeriod With { .period = keyDateGroup, .netSales = listSales.Sum(Function(item) item.amount) }).ToList '////group period by weeks ElseIf totalDays <= 30 Then netSalesByPeriod = (From sales In listSalesByDate Group sales By keyDateGroup = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear( sales.date, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Monday) Into listSales = Group Select New NetSalesByPeriod With { .period = "Week " & keyDateGroup.ToString, .netSales = listSales.Sum(Function(item) item.amount) }).ToList '////group period by months ElseIf totalDays <= 365 Then netSalesByPeriod = (From sales In listSalesByDate Group sales By keyDateGroup = sales.date.ToString("MMM-yyyy") Into listSales = Group Select New NetSalesByPeriod With { .period = keyDateGroup, .netSales = listSales.Sum(Function(item) item.amount) }).ToList '////group period by years Else netSalesByPeriod = (From sales In listSalesByDate Group sales By keyDateGroup = sales.date.ToString("yyyy") Into listSales = Group Select New NetSalesByPeriod With { .period = keyDateGroup, .netSales = listSales.Sum(Function(item) item.amount) }).ToList End If End Sub End Class
Capa de Presentación
Una vez terminado de codificar la capa de dominio, ahora agregaremos los conjuntos de datos para el reporte, crearemos el archivo de reporte y agregaremos un formulario para inicializar el visor de reporte y crear los botones con un rango de fechas en específicos o personalizado.
Generador de Reportes
Puedes utilizar cualquier generador de reportes, ya sea Crystal Reports, Report Viewer-SSRS, Component One, DevExpress, Jasper Reports o cualquier otro, ya que simplemente lo usaremos como diseñador y visor de reportes, y la capa de dominio ya dispone de todos los datos listos para ser mostrados.
En este caso usaremos el control REPORT VIEWER con modo de procesamiento local (RDLC) perteneciente a SSRS de Microsoft (SQL Server Reporting Services), personalmente prefiero este generador de informes porque es muy flexible, ligero, rápido, gratuito y muy fácil de usar e integrar en tu aplicación de .NET.
Reporting Services con Report Viewer-RDLC
Report Viewer es un control para visual studio, que permite visualizar reportes RDL y RDLC en nuestra aplicación web o de escritorio.
- RDLC (Lenguaje de Definición de Informes del lado del Cliente), se utiliza para crear archivos de «informes locales» en Visual Studio. Estos archivos se retienen localmente y no se almacenan en un servidor SSRS, es decir, se ejecuta en el lado de cliente a partir de un conjunto de datos.
- RDL, son archivos de informes que están diseñados para usarse con SQL Server Reporting Services (SSRS), y se almacenan en el servidor de informes y se ejecutan desde allí.
En este tutorial utilizaremos Reporting Services con modo de procesamiento local (RDLC) y mostraremos el informe mediante el control Report Viewer. A partir de Visual Studio 2015, este control y los servicios de reporte local ya no están integrados en la instalación por defecto de Visual Studio, tienes que instalarlo desde Nuget o Extensiones de Visual Studio.
Archivo de Informes de Ventas (SalesReport.rdlc)
- Agregamos el archivo / diseñador de reportes local RDLC en blanco, si deseas puedes usar el asistente de informes.
- Compilamos la capa de presentación para cargar las referencias.
- Ajustamos el tamaño de pagina del informe (en este caso A4->21cm x 29.7 cm) y el cuerpo del informe (21cm x 15cm, el alto del cuerpo debe ser ajustado a los componentes del informe).
- Agregamos los objetos (clases) Reporte de ventas (salesReport), Listado de Ventas (salesListing) y Ventas netas por periodo (netSalesByPeriod) al conjunto de datos del reporte local.
- Finalmente diseñamos el informe de la siguiente manera y en ello, agregamos los campos a mostrar (Campos de nuestros objetos de reporte).
Diseño de Formulario
- Una vez terminado de diseñar el reporte local, agregamos los botones con fechas especificas para el reporte y 2 controles selector de fecha (DateTimePicker) para el reporte de fechas personalizados.
- Agregamos el control Report Viewer y acoplamos a todo el contenedor.
- En el visor de reporte, elegimos el archivo del reporte a mostrar, en este caso, el reporte de ventas (SalesReport.rdlc)
- Una vez elegido el reporte, en la parte baja se creará los 3 fuentes enlace a datos para los 3 objetos del conjunto de datos del informe.
Código de Formulario
- Importamos la capa de dominio o negocio.
- Creamos el método obtener reporte de ventas (getSalesReport), con 2 parámetros para la fecha de inicio y final del reporte.
- En el método, instanciamos a la clase reporte de venta de la capa de dominio e invocamos el método crear reporte de ordenes de venta.
- Inicializamos la fuente de datos del enlace de datos del visor de reporte (SalesReportBindingSource, SalesListingBindingSource, NetSalesByPeriodBindingSource) con el objeto reporte y sus propiedades (reportModel, reportModel.salesListing, reportModel.netSalesByPeriod).
- Finalmente invocamos el método anterior desde los botones con los respectivos rango de fechas.
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { } private void getSalesReport(DateTime startDate, DateTime endDate) { SalesReport reportModel = new SalesReport(); reportModel.createSalesOrderReport(startDate, endDate); SalesReportBindingSource.DataSource = reportModel; SalesListingBindingSource.DataSource = reportModel.salesListing; NetSalesByPeriodBindingSource.DataSource = reportModel.netSalesByPeriod; this.reportViewer1.RefreshReport(); } private void btnToday_Click(object sender, EventArgs e) { var fromDate = DateTime.Today; var toDate = DateTime.Now; getSalesReport(fromDate,toDate); } private void btnLast7Days_Click(object sender, EventArgs e) { var fromDate = DateTime.Today.AddDays(-7); var toDate = DateTime.Now; getSalesReport(fromDate, toDate); } private void btnThisMonth_Click(object sender, EventArgs e) { var fromDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1); var toDate = DateTime.Now; getSalesReport(fromDate, toDate); } private void btnLast30Days_Click(object sender, EventArgs e) { var fromDate = DateTime.Today.AddDays(-30); var toDate = DateTime.Now; getSalesReport(fromDate, toDate); } private void btnThisYear_Click(object sender, EventArgs e) { var fromDate = new DateTime(DateTime.Now.Year, 1, 1); var toDate = DateTime.Now; getSalesReport(fromDate, toDate); } private void btnApplyCustomDate_Click(object sender, EventArgs e) { var fromDate = dateTimePickerFromDate.Value; var toDate = dateTimePickerToDate.Value; getSalesReport(fromDate, new DateTime(toDate.Year,toDate.Month, toDate.Day,23,59,59)); } }
Public Class Form1 Private Sub getSalesReport(ByVal startDate As DateTime, ByVal endDate As DateTime) Dim reportModel As SalesReport = New SalesReport() reportModel.createSalesOrderReport(startDate, endDate) SalesReportBindingSource.DataSource = reportModel SalesListingBindingSource.DataSource = reportModel.salesListing NetSalesByPeriodBindingSource.DataSource = reportModel.netSalesByPeriod Me.ReportViewer1.RefreshReport() End Sub Private Sub btnToday_Click(sender As Object, e As EventArgs) Handles btnToday.Click Dim fromDate = DateTime.Today Dim toDate = DateTime.Now getSalesReport(fromDate, toDate) End Sub Private Sub btnLast7Days_Click(sender As Object, e As EventArgs) Handles btnLast7Days.Click Dim fromDate = DateTime.Today.AddDays(-7) Dim toDate = DateTime.Now getSalesReport(fromDate, toDate) End Sub Private Sub btnThisMonth_Click(sender As Object, e As EventArgs) Handles btnThisMonth.Click Dim fromDate = New DateTime(DateTime.Now.Year, DateTime.Now.Month, 1) Dim toDate = DateTime.Now getSalesReport(fromDate, toDate) End Sub Private Sub btnLast30Days_Click(sender As Object, e As EventArgs) Handles btnLast30Days.Click Dim fromDate = DateTime.Today.AddDays(-30) Dim toDate = DateTime.Now getSalesReport(fromDate, toDate) End Sub Private Sub btnThisYear_Click(sender As Object, e As EventArgs) Handles btnThisYear.Click Dim fromDate = New DateTime(DateTime.Now.Year, 1, 1) Dim toDate = DateTime.Now getSalesReport(fromDate, toDate) End Sub Private Sub btnApplyCustomDate_Click(sender As Object, e As EventArgs) Handles btnApplyCustomDate.Click Dim fromDate = dateTimePickerFromDate.Value Dim toDate = dateTimePickerToDate.Value getSalesReport(fromDate, New DateTime(toDate.Year, toDate.Month, toDate.Day, 23, 59, 59)) End Sub Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Me.ReportViewer1.RefreshReport() End Sub End Class
Y eso es todo 🙂
Los comentarios están cerrados.