import java.io.*;
import java.util.Date;
import jpos.JposConst;
import jpos.LineDisplay;
import jpos.CashDrawer;
import jpos.JposException;
import jpos.FiscalPrinter;
import jpos.FiscalPrinterConst;
import jpos.util.JposPropertiesConst;

public class FiscalReceipts
{	
	static String ESC = ((char) 0x1B) + "";
	static String CRLF = ((char) 0x0D) + "" + ((char) 0x0A) + "";

	static CashDrawer drawer = new CashDrawer(); 
	static LineDisplay display = new LineDisplay(); 
	static FiscalPrinter printer = new FiscalPrinter(); 
  
	public static void main(String args[]) 
	{
		try 
		{
			printer.open("EthernetFiscalPrinter");	// apertura della FiscalPrinter passando il nome logico del FiscalPrinter che e' presente nel jpos.xml
			printer.claim(5000); 
			printer.setDeviceEnabled(true); 

			display.open("EthernetLineDisplay");	// apertura del LineDisplay passando il nome logico del LineDisplay che e' presente nel jpos.xml
			display.claim(5000); 
			display.setDeviceEnabled(true); 

			drawer.open("EthernetCashDrawer");		// apertura del CashDrawer passando il nome logico del CashDrawer che e' presente nel jpos.xml
			drawer.claim(5000); 
			drawer.setDeviceEnabled(true); 

			long lPrice = 100;

			printer.resetPrinter();					// comando di reset della stampante per eliminare le eventuali transazioni aperte

			printer.setPreLine("NOHEADER"); // per aprire un documento non fiscale ssenza con la stampa dell'intestazione della stampante occorre
							// passare come PreLine la stringa NOHEADER prima della BeginNonFiscal
							// altrimenti non viene stampata  
			/***********************************************************************

					      		STAMPA SCONTRINO NON FISCALE

			************************************************************************/
	
			display.displayText("STAMPA SCONTRINO NON FISCALE            ",0); // invio messaggio di 40 caratteri al display 
				
			printer.beginNonFiscal(); // apertura dello scontrino non fiscale

			// invio di una riga non fiscale composta da varie righe, delimitate da CRLF e formattate con le varie sequenze escape stule OPOS
			// di seguito viene riportato un prospetto con le varie sequenza ammesse:
			// ESC|#B			stampa bitmap # va da 1 a 8
			// ESC|#F			esegue un numero di righe di Feed pari al valore #
			// 		formattazione testo
			// ESC|1C			testo normale
			// ESC|2C			testo testo doppia larghezza
			// ESC|3C			testo testo doppia altezza
			// ESC|5C			testo in 42/44 caratteri
			// ESC|6C			testo bold
			// 		allienamento testo
			// ESC|lA			allienamento a sinistra
			// ESC|cA			allienamento al centro
			// ESC|rA			allineamento a destra
			// 		stampa barcode
			// ESC|#R<T><CODICE> stampa barcode di tipo <T>. Il valore di # e' la lungheza del barcode + la luneghezza di <T>r
			//					T = 1 EAN13       [ESC]|14R11234567890128
			//					T = 2 EAN8	  	  [ESC]|9R212345678
			//					T = 3 ITF, I2/5	  [ESC]|13R3123456789012
			//					T = 4 CODE39	  [ESC]|15R412345ABC123ABC
			//					T = 5 EAN128	  [ESC]|15R512345ABC123ABC
			//					non tutte le stmapanti gestiscono gli ultimi codici a barre: T = 6 NON VIENE GESTITO DALLA I^A GENERAZIONE
			//					e i valori 7 E 8 sono gestiti SOLO NELLA III^A GENERAZIONE
			//					T = 6 QRCODE	  [ESC]|61R6123456789A123456789B123456789C123456789D123456789E123456789F
			//					T = 7 GS1DATABAR  [ESC]|83R7[01]00478001001256[10]12345[240]12345[11]150522[21]123456789[3902]002535[17]151231
			//					T = 8 PDF417	  [ESC]|13R8123456789012
			
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|1F" + ESC + "|cA" + ESC + "|6C" + "Inizio stampa scontrini di test:");
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|cA" + ESC + "|6C" + "verranno stampati una serie di");
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|cA" + ESC + "|6C" + "scontrini di test per mostrare");
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|cA" + ESC + "|6C" + "le funzioni del driver");  

			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|lA" + "riga giust.sx");
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|cA" + "riga centrata");
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|rA" + "riga giust.dx");
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|cA" + ESC + "|2C" + "doppia lerghezza");
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|cA" + ESC + "|3C" + "doppia altezza");
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|cA" + ESC + "|5C" + "riga stampata a 42/44 carratteri");
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|cA" + ESC + "|6C" + "bold");
			// stampa logo 1 se presente sulla stampante
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|cA" + "Logo 1" + CRLF + ESC + "|1B");
			// stampa barcode ean 13
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|cA" + "Ean 13" + CRLF + ESC + "|14R11234567890123");
			// stampa barcode ean 8
			printer.printNormal(FiscalPrinterConst.FPTR_S_RECEIPT, ESC + "|1F" + ESC + "|cA" + "Ean 8" + CRLF + ESC + "|9R212345678" + ESC + "|1F");
			printer.endNonFiscal(); // chiusura del documento non fiscale

			/***********************************************************************

					      			STAMPA SCONTRINO FISCALE

			************************************************************************/
			
			display.displayText("STAMPA SCONTRINO FISCALE                ",0);		// invio messaggio di 40 caratteri al display 			

			printer.setAdditionalHeader(ESC + "|cA" + "AdditionalHeader");			// impostazione additional Header
			printer.beginFiscalReceipt(true); 										// apertura documento fiscale, se viene passato true viene stampato
																					// l'additionaheader altrimenti no
			/***********************************************************************

									GESTIONE LOTTERIA
			printRecTaxID imposta il codice lotteria, può essere chiamata prima della BeginFiscalRecept
			o anche dopo ma PRIMA di aver pagato
			DEVE ESSERE ABILITATA LA GESTIONE DELLA LOTTERIA ALTRIMENTILA GESTIONE NON FUNZIONA

			************************************************************************/
			printer.printRecTaxID("ABCD1234");										// imposta codice lotteeria 8 cifre
			
			printer.printRecItem("Articolo test", lPrice, 1000, 1, lPrice, "Kg"); 	// riga di vendita
			printer.printRecMessage(ESC + "|cA" + "printRecMessage"); 				// invio messaggio non fiscale			
			printer.printRecTotal(lPrice, lPrice, "Contanti"); 						// invio pagamento
			printer.setAdditionalTrailer(ESC + "|cA" + "AdditionalTrailer");  		// impostazione riga di cortesia			
			printer.endFiscalReceipt(true);  										// chiusura documento fiscale se printheader � a true allora stampa
																					// SOLO per la terza generazione il dettagio pagamenti
					

			drawer.openDrawer(); 													// apertura cassetto, in alcune stampanti potrebbe essere attiva
																					// l'opzione aupertura casetto automatica, si prega di controllare
			printer.setAdditionalHeader("");			// resetta valore additional Header
			

			
			/***********************************************************************

					****************************************
					*			DOCUMENTO DI ANNULLO       *
			 		****************************************
	      			STAMPA DOCUMENTO DI ANNULLO LIBERO, CIOE' NON 
	      			PRESENTE SUL GIORNALE DI FONDO. ATTENZIONE LO CHE
	      			LO STESSO DOCUMENTO NON E' ANNULLABILE 2 VOLTE E QUINDI
	      			LA SECONDA VOLTA L'ESEMPIO ANDRA' IN ECCEZIONE

					SE INVECE IO DOCUMENTO E' PRESENTE SUL GIORNALE VIENE ANNULLATO 
					IMMEDIATAMENTE DOPO LA printer.beginFiscalReceipt E BASTA 
					CONTROLLARE LO STATO CON LA getPrinterState e se lo stato
					e' a FPTR_PS_MONITOR allora vuol dire che il documento e' 
					stato anche stampato

			************************************************************************/
			
			display.displayText("STAMPA DOCUCUMENTO DI ANNULLO           ",0);		// invio messaggio di 40 caratteri al display 			
			
			printer.setAdditionalHeader("<DOCUMENT>type = \"DOC_ANNULLO\" docref = \"0001-0002-010119\" matf = \"STMTE110306\"</DOCUMENT>");
			// impostazione additional Header dei dati per aprire in docume nto di annullo:
			// la stringa DEVE ESSERE FORMATTATA NEL SEGUENTE MODO
			// <DOCUMENT>type = \"DOC_ANNULLO\" docref = \"0001-0002-010119\" matf = \"STMTE110306\"</DOCUMENT>
			// dove i campi:
			//
			// 1) type: tipo di documento da produrre
			// type = "DOC_ANNULLO" per il documento di annullo
			// type = "DOC_RESO"    per il documento di reso
			//
			// 2) docref: riferimento al documento da annullare o da rendere
			// il formato e' ZZZZ-NNNN-DDMMYY
			// ZZZZ numero di azzeramento del docuemnto, se il documento e' riferito ad una matricola '83 DEVE ESSERE 0000
			// NNNN numero di scontrino del documento, sempre 4 cifre
			// DDMMYY e' la data di emissione espressa nel formato giorno-mese-anno
			//
			// esempio: "0001-0002-010119" dove ZZZZ=0001 NNNN=0002 e DDMMYY=010119 cioe' azzeramento1,scontrino 2 del primo gennaio 19
			//
			// 3) matf: marticola della macchina a cui e' riferito il documento di annullo
			
			printer.beginFiscalReceipt(true); 										// apertura documento fiscale, se viene passato true viene stampato
																					// l'additionaheader altrimenti no
			
			if (printer.getPrinterState()!= FiscalPrinterConst.FPTR_PS_MONITOR)
			{
				printer.printRecItem("Articolo test", lPrice, 1000, 1, lPrice, "Kg"); 	// riga di vendita			
				printer.printRecTotal(lPrice, lPrice, "Contanti"); 						// invio pagamento anche se per questo documento e' ininfluente			
				printer.endFiscalReceipt(false);  										// chiusura documento fiscale
			}
			
			/***********************************************************************

					****************************************
					*			DOCUMENTO DI RESO       *
			 		****************************************
		  			STAMPA DOCUMENTO DI RESO LIBERO, CIOE' NON 
		  			PRESENTE SUL GIORNALE DI FONDO. ATTENZIONE LO CHE
		  			LO STESSO DOCUMENTO NON E' ANNULLABILE 2 VOLTE E QUINDI
		  			LA SECONDA VOLTA L'ESEMPIO ANDRA' IN ECCEZIONE
		
			************************************************************************/
			
			display.displayText("STAMPA DOCUCUMENTO DI RESO              ",0);		// invio messaggio di 40 caratteri al display 			
			
			printer.setAdditionalHeader("<DOCUMENT>type = \"DOC_RESO\" docref = \"0001-0003-010119\" matf = \"STMTE110306\"</DOCUMENT>");
			// impostazione additional Header dei dati per aprire in docume nto di annullo:
			// la stringa DEVE ESSERE FORMATTATA NEL SEGUENTE MODO
			// <DOCUMENT>type = \"DOC_ANNULLO\" docref = \"0001-0002-010119\" matf = \"STMTE110306\"</DOCUMENT>
			// dove i campi:
			//
			// 1) type: tipo di documento da produrre
			// type = "DOC_ANNULLO" per il documento di annullo
			// type = "DOC_RESO"    per il documento di reso
			//
			// 2) docref: riferimento al documento da annullare o da rendere
			// il formato e' ZZZZ-NNNN-DDMMYY
			// ZZZZ numero di azzeramento del docuemnto, se il documento e' riferito ad una matricola '83 DEVE ESSERE 0000
			// NNNN numero di scontrino del documento, sempre 4 cifre
			// DDMMYY e' la data di emissione espressa nel formato giorno-mese-anno
			//
			// esempio: "0001-0002-010119" dove ZZZZ=0001 NNNN=0002 e DDMMYY=010119 cioe' azzeramento1,scontrino 2 del primo gennaio 19
			//
			// 3) matf: marticola della macchina a cui e' riferito il documento di annullo
			
			printer.beginFiscalReceipt(true); 										// apertura documento fiscale, se viene passato true viene stampato
																					// l'additionaheader altrimenti no
			printer.printRecItem("Articolo test", lPrice, 1000, 1, lPrice, "Kg"); 	// riga di vendita			
			printer.printRecTotal(lPrice, lPrice, "Contanti"); 						// invio pagamento anche se per questo documento e' ininfluente			
			printer.endFiscalReceipt(false);  										// chiusura documento fiscale
			
			/***********************************************************************

					      			STAMPA FATTURA FISCALE

			************************************************************************/

			display.displayText("STAMPA FATTURA                          ",0);			 // invio messaggio di 40 caratteri al display
			try
			{
				printer.setFiscalReceiptType(FiscalPrinterConst.FPTR_RT_SIMPLE_INVOICE); // impostazione tipo di documento a simple invoice
			}catch(JposException e)
			{
				// le stampanti di prima generazione non gestiscono la fattura e la nota di cresica
				display.displayText("DOCUMENTO NON GESTITO! STAMPA SCONTRINO ",0);		 // invio messaggio di 40 caratteri al display 	
			}
			// nella preline, se il tipo di documento e' una fattura, vengono impostati i dati relativi alla fattura:
			// - riga 1: numero della fattura, se è 0 la gestione del progressivo della fattura viene demanfato alla stmpante
			// - riga 2: codice fiscale/partita iva
			// - riga 3-6: riga descrizione cliente
			printer.setPreLine("0" + CRLF + 
								"12312312312" + CRLF + 
								"Descrizione Cliente Riga 1" + CRLF + 
								"Descrizione Cliente Riga 2" + CRLF +
								"Descrizione Cliente Riga 3" + CRLF + 
					   			"Descrizione Cliente Riga 4" + CRLF + 
								"Descrizione Cliente Riga 5" + CRLF + 
								"Descrizione Cliente Riga 6" + CRLF +
								"Descrizione Cliente Riga 7"+ CRLF + 
					   			"Descrizione Cliente Riga 8");
			printer.setAdditionalHeader(ESC + "|cA" + "AdditionalHeader"); 				// impostazione additional Header
			printer.beginFiscalReceipt(true); 											// apertura documento fiscale, se viene passato true viene 
																						// stampato l'additionaheader altrimenti no
			printer.printRecItem("Articolo test", lPrice, 1000, 1, lPrice, "Kg");  		// riga di vendita
			printer.printRecMessage(ESC + "|cA" + "printRecMessage");					// invio messaggio non fiscale			
			printer.printRecTotal(lPrice, lPrice, "Contanti"); 							// invio pagamento
			printer.setAdditionalTrailer(ESC + "|cA" + "AdditionalTrailer"); 			// impostazione riga di cortesia			
			printer.endFiscalReceipt(false);											// chiusura documento fiscale

			drawer.openDrawer(); 														// apertura cassetto, in alcune stampanti potrebbe essere 
																						// attiva l'opzione aupertura casetto automatica, 
																						// si prega di controllare

			/***********************************************************************

										NOTA DI CREDITO

			************************************************************************/
			display.displayText("STAMPA NOTA DI CREDITO                  ",0); 			// invio messaggio di 40 caratteri al display
			try
			{
				printer.setFiscalReceiptType(FiscalPrinterConst.FPTR_RT_REFUND); 		// impostazione tipo di documento a refund
			}catch(JposException e)
			{
				// le stampanti di prima generazione non gestiscono la fattura e la nota di cresica
				display.displayText("DOCUMENTO NON GESTITO! STAMPA SCONTRINO ",0);		// invio messaggio di 40 caratteri al display 	
			}			

			// nella preline, se il tipo di documento e' una nota di credito, viene passato il dato relativo alla PRATICA DI RESO
			printer.setPreLine("12345678");
			printer.setAdditionalHeader(ESC + "|cA" + "AdditionalHeader"); 				// impostazione additional Header
			printer.beginFiscalReceipt(true);											// apertura documento fiscale, se viene passato true viene
																						// stampato l'additionaheader altrimenti no
			printer.printRecItem("Articolo test", lPrice, 1000, 1, lPrice, "Kg");  		// riga di vendita
			printer.printRecMessage(ESC + "|cA" + "printRecMessage"); 					// invio messaggio non fiscale			
			printer.printRecTotal(lPrice, lPrice, "Contanti"); 							// invio pagamento
			printer.setAdditionalTrailer(ESC + "|cA" + "AdditionalTrailer");			// impostazione riga di cortesia			
			printer.endFiscalReceipt(false); 											// chiusura documento fiscale
			
			drawer.openDrawer(); 														// apertura cassetto, in alcune stampanti potrebbe essere
																						// attiva l'opzione aupertura casetto automatica,
																						// si prega di controllare
  
			display.displayText("STAMPA CHIUSURA GIORNALIERA             ",0); 			// invio messaggio di 40 caratteri al display 			

			printer.printZReport(); 													// stampa chiusura giornaliera

			display.clearText(); 														// cancellazione testo a display

			display.release();
			display.setDeviceEnabled(false);
			display.close();

			drawer.release();
			drawer.setDeviceEnabled(false);
			drawer.close();

			printer.release();
			printer.setDeviceEnabled(false);
			printer.close();
		}
		catch(JposException e)
		{
			
			System.out.println("ErrorCode " + e.getErrorCode());
			System.out.println("ErrorCodeExtended " + e.getErrorCodeExtended());
			System.out.println("Message " + e.getMessage());
			
			e.printStackTrace();
			
			return;
		}
		catch (Throwable thr) 
		{

			thr.printStackTrace(System.out);			
		}
		return;
	}
}

