Imprimir Facturas con C# Sharp . NET (Microsoft Visual Studio 2008)

Aclaracion:

Este documento esta creado como recordatorio de viejos trabajos personales y para poder ayudar a los que esten aprendiendo el lenguaje, me voy a focalizar en que sea una ayuda memoria con explicaciones basicas y minimas, no le daré suma importancia a la ortografica ni al vocabulario utilizado por ende puede haber muchos errores ortográficos y espero serle de ayuda a los que me ayudaron. (La comunidad de programadores independientes o freelance)

Ticket.cs (codigo fuente de la dll)
Ticket.dll (Clase que se agrega a la solucion)
Ticket.txt (ejemplo de como implementar la dll)

Mucho credito a este buen hombre que a gracias a Ticket.cs pude crea mi propia clase para imprimir facturas en facturas preimpresas. (en un futuro creare la dll para impresoras fiscales Argentinas)

Lo que en el foro anteriomente mensionado no encontre fue que cuando incorporas solo la dll al tu solucion tenes que escribir la siguiente linea al principio de tu solucion:

using BarControls; // esta linea es para que funcione todo lo que esta en el Ticket.txt

Esto es el contenido del txt y se puede poner en un boton_click que diga Imprimir Ticket, pero no voy a explicar mucho sobre este proyecto porque en el link del propietario esta bastante claro.

Ticket ticket = new Ticket();

ticket.HeaderImage = "C:\imagen.jpg"; //esta propiedad no es obligatoria

ticket.AddHeaderLine("STARBUCKS COFFEE TAMAULIPAS" );
ticket.AddHeaderLine("EXPEDIDO EN:" );
ticket.AddHeaderLine("AV. TAMAULIPAS NO. 5 LOC. 101" );
ticket.AddHeaderLine("MEXICO, DISTRITO FEDERAL" );
ticket.AddHeaderLine("RFC: CSI-020226-MV4" );

//El metodo AddSubHeaderLine es lo mismo al de AddHeaderLine con la diferencia
//de que al final de cada linea agrega una linea punteada "=========="
ticket.AddSubHeaderLine("Caja # 1 - Ticket # 1" );
ticket.AddSubHeaderLine("Le atendió: Prueba" );
ticket.AddSubHeaderLine(DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString());

//El metodo AddItem requeire 3 parametros, el primero es cantidad, el segundo es la descripcion
//del producto y el tercero es el precio
ticket.AddItem("1", "Articulo Prueba", "15.00" );
ticket.AddItem("2", "Articulo Prueba", "25.00" );

//El metodo AddTotal requiere 2 parametros, la descripcion del total, y el precio
ticket.AddTotal("SUBTOTAL", "29.75" );
ticket.AddTotal("IVA", "5.25" );
ticket.AddTotal("TOTAL", "35.00" );
ticket.AddTotal("", "" ); //Ponemos un total en blanco que sirve de espacio
ticket.AddTotal("RECIBIDO", "50.00" );
ticket.AddTotal("CAMBIO", "15.00" );
ticket.AddTotal("", "" );/Ponemos un total en blanco que sirve de espacio
ticket.AddTotal("USTED AHORRO", "0.00" );

//El metodo AddFooterLine funciona igual que la cabecera
ticket.AddFooterLine("EL CAFE ES NUESTRA PASION..." );
ticket.AddFooterLine("VIVE LA EXPERIENCIA EN STARBUCKS" );
ticket.AddFooterLine("GRACIAS POR TU VISITA" );

//Y por ultimo llamamos al metodo PrintTicket para imprimir el ticket, este metodo necesita un
//parametro de tipo string que debe de ser el nombre de la impresora.
ticket.PrintTicket("Epson 720X" );

Bueno los tres archivos siguientes son para imprimir una factura en una factura preimpresa.

Los tres archivos son:

Factura.cs (Clase para imprimir facturas, codigo fuente)
Factura.dll (dll para incorporar a cualquier proyecto)
Factura.txt (txt con la forma y ejemplo de como se implementa en en un proyecto)

Como implementarlo:

Como primera medida incluimos en las directivas de preprocesador (o al menos asi se llamaba cuando programaba en C):

using FacturaControl; //para que funcione todo lo que esta en la dll e incluir el contenido del txt

Este es el contenido de Factura.css

using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Printing;
using System.Runtime.InteropServices;

namespace FacturaControl
{
class Factura
{
String[,] datos = new String[100, 3];
String[,] items = new String[1000, 6];
int contador_datos = 0;
int contador_items = 0;
int contador = 1;
int posItemsY = 0;

Font printFont = null;
SolidBrush myBrush = new SolidBrush(Color.Black);
string fontName = "Lucida Console";
int fontSize = 8;
Graphics gfx = null;

public Factura()
{

}

public bool PrinterExists(string impresora)
{
foreach (String strPrinter in PrinterSettings.InstalledPrinters)
{
if (impresora == strPrinter)
return true;
}
return false;
}

public void PrintFactura(string impresora)
{
printFont = new Font(fontName, fontSize, FontStyle.Regular);
PrintDocument pr = new PrintDocument();
pr.PrinterSettings.PrinterName = impresora;
pr.DocumentName = "Impresion de Factura";
pr.PrintPage += new PrintPageEventHandler(pr_PrintPage);
pr.Print();
}

private void pr_PrintPage(Object sender, PrintPageEventArgs e)
{
e.Graphics.PageUnit = GraphicsUnit.Millimeter;
gfx = e.Graphics;
DrawDatos();
DrawItems();
}

private void DrawDatos()
{
for (int i = 0; i < contador_datos; i++)
{
int PosX = int.Parse(datos[i, 1].ToString());
int PosY = int.Parse(datos[i, 2].ToString());
gfx.DrawString(datos[i, 0], printFont, myBrush, PosX, PosY, new StringFormat());
}
}

private void DrawItems()
{
for (int i = 0; i < contador_items; i++)
{
int PosX = int.Parse(items[i, 1]);
int PosY = int.Parse(items[i, 2]);
gfx.DrawString(items[i, 0], printFont, myBrush, PosX, PosY + posItemsY, new StringFormat());
if (contador == 6)
{
posItemsY += 4; //incremento en 4 milimitros para la proxima linea
contador = 0;
}
contador++;
}
}

public void AddDatos(string datoTexto, string PosX, string PosY)
{
datos[contador_datos, 0] = datoTexto;
datos[contador_datos, 1] = PosX;
datos[contador_datos, 2] = PosY;
contador_datos++;
}

public void AddItems(string AdditemTexto)
{
string[] itemsDatos = AdditemTexto.Split(',');
items[contador_items, 0] = AlignRightText(itemsDatos[0].Length, int.Parse(ConfigurationSettings.AppSettings["textBox_ImpCanMC"])) + itemsDatos[0];
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpCanX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpCanY"];
contador_items++;
items[contador_items, 0] = AlignRightText(itemsDatos[2].Length, int.Parse(ConfigurationSettings.AppSettings["textBox_ImpPreMC"])) + itemsDatos[2];
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpPreX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpPreY"];
contador_items++;
items[contador_items, 0] = AlignRightText(itemsDatos[3].Length, int.Parse(ConfigurationSettings.AppSettings["textBox_ImpAliMC"])) + itemsDatos[3];
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpAliX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpAliY"];
contador_items++;
items[contador_items, 0] = AlignRightText(itemsDatos[4].Length, int.Parse(ConfigurationSettings.AppSettings["textBox_ImpBivMC"])) + itemsDatos[4];
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpBivX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpBivY"];
contador_items++;
items[contador_items, 0] = AlignRightText(itemsDatos[5].Length, int.Parse(ConfigurationSettings.AppSettings["textBox_ImpImpMC"])) + itemsDatos[5];
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpImpX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpImpY"];
// Al detalle lo mando a comprobar y dividir en dos o mas lineas si es necesario
DivideItemDet(itemsDatos[1].Length, int.Parse(ConfigurationSettings.AppSettings["textBox_ImpDetMC"]), itemsDatos[1]);
// Continuo almacenando
contador_items++;
}

private string AlignRightText(int lenght, int maxChar)
{
string espacios = "";
int spaces = maxChar - lenght;
for (int x = 0; x < spaces; x++)
espacios += " ";
return espacios;
}

private void DivideItemDet(int lenghtDet, int maxCharDet, string detalleText)
{
if (lenghtDet > maxCharDet)
{
string[] splitDetalle = detalleText.Split(' ');
string linea = "";
int i = 0;
int contador_lineas = 0;

while (i < splitDetalle.Length)
{
while ((linea.Length < maxCharDet) && (i < splitDetalle.Length))
{
linea += splitDetalle[i] + " ";
i++;
}

if (contador_lineas < 1)
{
contador_items++;
items[contador_items, 0] = linea;
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpDetX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpDetY"];
contador_lineas++;
linea = "";
}
else
{
contador_items++;
items[contador_items, 0] = "";
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpCanX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpCanY"];
contador_items++;
items[contador_items, 0] = linea;
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpDetX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpDetY"];
contador_items++;
items[contador_items, 0] = "";
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpPreX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpPreY"];
contador_items++;
items[contador_items, 0] = "";
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpAliX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpAliY"];
contador_items++;
items[contador_items, 0] = "";
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpBivX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpBivY"];
contador_items++;
items[contador_items, 0] = "";
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpImpX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpImpY"];
linea = "";
}
}
}
else
{
contador_items++;
items[contador_items, 0] = detalleText;
items[contador_items, 1] = ConfigurationSettings.AppSettings["textBox_ImpDetX"];
items[contador_items, 2] = ConfigurationSettings.AppSettings["textBox_ImpDetY"];
}
}
}

}

Bien si esto lo copian al Visual Studio 2008 lo tabula automaticamente. Cosa que por aca me dio fiaca hacerlo y se entinede mucho mejor tabulado.

Como veran es muy pero muy similar al que hizo el buen hombre del foro yo creo que lo hice un poco mas sensillo y con menos lineas de codigo.

Este es el codigo para implementarlo yo lo incorpore a un boton que se llama "Imprimir Prueba". Es lo que esta en archivo Factura.txt

private void button_Prueba_Click(object sender, EventArgs e)
{
Factura factura = new Factura();
string[] DateArray = DateTime.Now.ToShortDateString().Split('/');
//Datos de Factura
factura.AddDatos(DateArray[0], ConfigurationSettings.AppSettings["textBox_ImpDiaX"], ConfigurationSettings.AppSettings["textBox_ImpDiaY"]);
factura.AddDatos(DateArray[1], ConfigurationSettings.AppSettings["textBox_ImpMesX"], ConfigurationSettings.AppSettings["textBox_ImpMesY"]);
factura.AddDatos(DateArray[2], ConfigurationSettings.AppSettings["textBox_ImpAnoX"], ConfigurationSettings.AppSettings["textBox_ImpAnoY"]);
factura.AddDatos(DateTime.Now.ToShortTimeString(), ConfigurationSettings.AppSettings["textBox_ImpHorX"], ConfigurationSettings.AppSettings["textBox_ImpHorY"]);
factura.AddDatos("Manuel Belgrano", ConfigurationSettings.AppSettings["textBox_ImpSenX"], ConfigurationSettings.AppSettings["textBox_ImpSenY"]);
factura.AddDatos("Av. San Martin 2477 piso 7 dto A", ConfigurationSettings.AppSettings["textBox_ImpDomX"], ConfigurationSettings.AppSettings["textBox_ImpDomY"]);
factura.AddDatos("Capital Federal", ConfigurationSettings.AppSettings["textBox_ImpLocX"], ConfigurationSettings.AppSettings["textBox_ImpLocY"]);
factura.AddDatos("X", ConfigurationSettings.AppSettings["textBox_ImpRiX"], ConfigurationSettings.AppSettings["textBox_ImpRiY"]);
factura.AddDatos("X", ConfigurationSettings.AppSettings["textBox_ImpCfX"], ConfigurationSettings.AppSettings["textBox_ImpCfY"]);
factura.AddDatos("X", ConfigurationSettings.AppSettings["textBox_ImpNorX"], ConfigurationSettings.AppSettings["textBox_ImpNorY"]);
factura.AddDatos("X", ConfigurationSettings.AppSettings["textBox_ImpExeX"], ConfigurationSettings.AppSettings["textBox_ImpExeY"]);
factura.AddDatos("15-29058877-5", ConfigurationSettings.AppSettings["textBox_ImpCuiX"], ConfigurationSettings.AppSettings["textBox_ImpCuiY"]);
factura.AddDatos("00022451", ConfigurationSettings.AppSettings["textBox_ImpRemX"], ConfigurationSettings.AppSettings["textBox_ImpRemY"]);
factura.AddDatos("X", ConfigurationSettings.AppSettings["textBox_ImpConX"], ConfigurationSettings.AppSettings["textBox_ImpConY"]);
factura.AddDatos("X", ConfigurationSettings.AppSettings["textBox_ImpCcoX"], ConfigurationSettings.AppSettings["textBox_ImpCcoY"]);
//Items

factura.AddItems("01,Gorrita Adidas,15.500,(10.50),***,15.50");
factura.AddItems("22,DISCO rigido WesTern DIGITAL 500GB - continuacion del primer item en algun momento me lo deberia cortar y crear nuevas lineas que no importa la cantidad siempre las tiene que dividir siempre y cuadno yo ponga mucho texto en el casillero de detalle,600.6669,(10.50),***,600.00");
factura.AddItems("01,Medias Adidas,6.0000,(10.50),***,6.00");
factura.AddItems("05,Pantalones Acrilicos Nike MOD. 65544,12.0000,(10.50),***,12.00");

//Totales
factura.AddDatos("0.0000", ConfigurationSettings.AppSettings["textBox_ImpSu1X"], ConfigurationSettings.AppSettings["textBox_ImpSu1Y"]);
factura.AddDatos("0.0000", ConfigurationSettings.AppSettings["textBox_ImpDesX"], ConfigurationSettings.AppSettings["textBox_ImpDesY"]);
factura.AddDatos("21%", ConfigurationSettings.AppSettings["textBox_ImpIpsX"], ConfigurationSettings.AppSettings["textBox_ImpIpsY"]);
factura.AddDatos("0.0000", ConfigurationSettings.AppSettings["textBox_ImpSu2X"], ConfigurationSettings.AppSettings["textBox_ImpSu2Y"]);
factura.AddDatos("21%", ConfigurationSettings.AppSettings["textBox_ImpIvaX"], ConfigurationSettings.AppSettings["textBox_ImpIvaY"]);
factura.AddDatos("0.0000", ConfigurationSettings.AppSettings["textBox_ImpTotX"], ConfigurationSettings.AppSettings["textBox_ImpTotY"]);
//Mando a Imprimir
factura.PrintFactura(ConfigurationSettings.AppSettings["textBox_ImpNOMBRE"]);
}

Explico un poco porque quedo medio confuso para la vista por el hecho de las cordenadas XY de cada elemento. Aclaracion: con esta dll se puede modificar la posicion en X y en Y de cada elemento que en mi caso lo hice para mis facturas preimpresas.

1 - Creamos una instacia que se llama Factura dentro de la accion de un boton (en mi caso) button_Prueba_Click, pero se puede poner en cualquier lado de nuestro programa.

2- Con este codigo: DateTime.Now.ToShortDateString().Split('/'); dividimos el dia de formato DD/MM/AAAA en un Array de strings para poderlos usar luego.

3 - Ahora con cada una de estas lineas: factura.AddDatos(DateArray[0], ConfigurationSettings.AppSettings["textBox_ImpDiaX"], ConfigurationSettings.AppSettings["textBox_ImpDiaY"]);

factura.AddDatos es el metodo que incorpora datos de la siguiente manera: AddDatos(sting Texto, Int PosX, Int PosY)

DataArray[0] es el texto que se va a imprimir en la factura en este caso es el DD (dia) del array que creamos al principio, pero en ese lugar va cualquier cadena de texto.

ConfigurationSettings.AppSettings["textBox_ImpDiaX"] es la posicion en X en donde queremos que vaya nuestro elemento (Dia en este caso)

ConfigurationSettings.AppSettings["textBox_ImpDiaY"] es la posicion en Y en donde queremos que vaya nuestro elemento (Dia en este caso)

Porque un codigo tan extraño para una posicion? Porque yo los datos de posicion X e Y los estoy tomando de la hoja de configuracion de mi programa. (App.config). Es por eso que mi codigo quedo medio engorroso a la vista pero si reeplazamos "ConfigurationSettings.AppSettings["textBox_ImpDiaY"]" por un numero entero podran ver que es lo mismo ya que mi textBox_ImpDiaY guarda un nuemero entero que es la coordenada del elemento a imprimir.

Bueno y asi incorporamos toda la info que sea necesario imprimir en la factura que no sean los items a facturar ya que para ello esta el metodo AddItems que se explica luego.

Elementos que se imprimen por separado con sus propias coordenadas cada uno en mi ejemplo:

-- Datos de Encabezamiento --
DIA (DD)
MES (MM)
AÑO (AAAA)
HORA (formato HH:MM p.m.)
NOMBRE Sr/s (String)
DIRECCION (String)
LOCALIDAD (String)
RESP INSC (String)
CONS FINAL (String)
NO RESP (String)
EXENTO (String)
CUIT (String)
REMITO N° (String)
COND DE PAGO (String)
CUENTA CORRIENTE (String)

-- Items--
CANTIDAD --- DETALLE --- PRECIO UNI. --- ALICUOTA --- IMPORTE

-- Importes Finales --
SUBTOTAL 1 (String)
DESCUENTO (String)
SUBTOTAL 2 (String)
IMPUESTO (String)
IVA INSC % (String)
TOTAL (String)

4 - Al igual que AddDatos cree un metodo factura.AddItems("01,Gorrita Adidas,15.500,(10.50),***,15.50"); que envia un string con los 6 campos separdos por "," (comas) y que habra un metodo que se encargue de dividirlos cada uno en una posicion de un array con su determinada posicion XY.

Este metodo tiene sus cositas para verlas detalladamente para el que le interese. Como veran en mi ejemplo uno de los items es muy largo y para ello el metodo se encarga de dividirlo en lineas sin cortar las palabras de la descripcion del producto a facturar.

5 - Agregamos los totales de la misma manera que los datos con AddDatos

6 - Mandamos a imprimir con factura.PrintFactura(ConfigurationSettings.AppSettings["textBox_ImpNOMBRE"]); donde el valor que recibe es el nombre de la impresora que se usara para imprimir que en mi caso esta guardado en la hoja de configuracion.

7 - Asi me quedo mi impresion en una hoja blanca A4 disculpen la calidad - Descargar en tamaño grande.

impresion

 

Si quedaron dudas no duden en escribirme por el formulario de contacto Presionando AQUI y haciendo referencia a este tema.

 
 
Free Web Hosting