using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Printing; using System.Globalization; using System.Linq; using System.Reflection; using System.Resources; using System.Text; using System.Windows.Forms; namespace Neo.LegitimateLicences.ActiveX.Printing { public class AppReceiptPrinter { #region Properties private string division; private string receiptNumber; private string receiptHeading; private string cashierName; private string paymentType; private string applicantData; private string receiptItems; private double total; private string province; private string printedBy; private DateTime printedDate; private string associationName; private short copies; private string printerPath; private int height; private int width; private int leftMargin; private bool preview; private bool isReprint; private int printCounter; private int pageNumber; private int totalPages; private Font normal = new Font("Arial", 8); private Font bold = new Font("Arial", 8, FontStyle.Bold); //delegate to do the count of total number of pages private delegate void GetPageCount(Object sender, PrintPageEventArgs e); private bool pageCountCompleted; //private #endregion #region ReceiptPrinter public AppReceiptPrinter(string division, string receiptNumber, string receiptHeading, string cashierName, string paymentType, string applicantData, string receiptItems, string province, double totalCoast, string associationName, string printedBy, short copies, string printerPath, int height, int width, bool preview, bool isReprint) { this.division = division; this.receiptNumber = receiptNumber; this.receiptHeading = receiptHeading; this.associationName = associationName; this.cashierName = cashierName; this.paymentType = paymentType; this.applicantData = applicantData; this.receiptItems = receiptItems; this.province = province; this.total = totalCoast; this.printedBy = printedBy; this.printedDate = System.DateTime.Now; this.copies = copies; this.printerPath = printerPath; this.height = height; //in mm this.width = width; //in mm leftMargin = 20; this.preview = preview; this.isReprint = isReprint; } #endregion #region Print public void Print() { printCounter = 0; pageNumber = 1; totalPages = 1; pageCountCompleted = false; PrintDocument tmpprndoc = new PrintDocument(); tmpprndoc.PrinterSettings.Copies = this.copies; tmpprndoc.PrintPage += new PrintPageEventHandler(toPrinter); tmpprndoc.DocumentName = "Receipt"; tmpprndoc.PrinterSettings.PrinterName = printerPath; PaperSize CustomSize1 = new PaperSize("A4", Convert.ToInt32(width / 0.254), Convert.ToInt32(height / 0.254)); //convert to 100ths of an inch //, 394, 197); tmpprndoc.DefaultPageSettings.PaperSize = CustomSize1; if (preview) { PrintPreviewDialog tmpprdiag = new PrintPreviewDialog(); tmpprdiag.Document = tmpprndoc; tmpprdiag.ShowDialog(); } else { tmpprndoc.Print(); } } #endregion #region toPrinter private void toPrinter(Object sender, PrintPageEventArgs e) { if (!pageCountCompleted) { PictureBox pictureBox = new PictureBox(); GetPageCount getPageCount = new GetPageCount(PageCounter); getPageCount.Invoke(new Object(), new PrintPageEventArgs(pictureBox.CreateGraphics(), e.MarginBounds, new Rectangle(), new PageSettings())); } var receiptItems = fillArray(); Graphics g = e.Graphics; Brush br = new SolidBrush(Color.Black); Pen pen = new Pen(br, 2); Pen recPen = new Pen(br, 1); Rectangle rec = new Rectangle(leftMargin, 380, 115, 30); Rectangle textRec = new Rectangle(leftMargin + 10, rec.Y + 8, rec.Width - 15, rec.Height); var currentY = 0; #region Receipt Item Index variables var rdApplicationNumberIndex = 0; var rdIDNumberOrBusinessRegistrationNoIndex = 1; var rdApplicationDescriptionIndex = 3; var rdCostIndex = 5; var rdAssociationNameIndex = 6; var rdVehicleRegNumberIndex = 7; var rdVehicleChassisNumberIndex = 8; var rdRegionIndex = 9; var rdExistingVehicleRegNumberIndex = 10; var rdExistingVehicleChassisNumberIndex = 11; #endregion #region Table column width variables var applicationNumberColumnWidth = 105; var paymentForColumnWidth = 150; var vehicleColumnWidth = 180; var amountColumnWidth = 120; #endregion #region Page Header currentY += 5; var logo = (Image)Properties.Resources.ResourceManager.GetObject("TransportDepartmentLogo"); if (logo != null) g.DrawImage(logo, leftMargin - 5, currentY); currentY += 140; g.DrawLine(pen, leftMargin, currentY, leftMargin + 740, currentY); currentY += 10; g.DrawString(receiptHeading, new Font("Arial", 14, FontStyle.Bold), br, leftMargin + 165, currentY); currentY += 30; g.DrawString("RECEIPT OF PAYMENT", bold, br, 345, currentY); currentY += 30; #endregion #region Sumarry block at the top g.DrawString("Receipt Number :", bold, br, leftMargin, currentY); g.DrawString(receiptNumber, normal, br, leftMargin + 175, currentY); currentY += 15; g.DrawString("Payment Type: ", bold, br, leftMargin, currentY); g.DrawString(paymentType.ToUpper(), normal, br, leftMargin + 175, currentY); currentY += 15; g.DrawString("Applicant Name: ", bold, br, leftMargin, currentY); g.DrawString(applicantData, normal, br, leftMargin + 175, currentY); currentY += 15; g.DrawString("ID No./Bus Reg No.: ", bold, br, leftMargin, currentY); g.DrawString(receiptItems[0, rdIDNumberOrBusinessRegistrationNoIndex], normal, br, leftMargin + 175, currentY); if (!string.IsNullOrEmpty(receiptItems[0, rdAssociationNameIndex]) && receiptItems[0, rdAssociationNameIndex] != "Unknown") { currentY += 15; g.DrawString("Association Name: ", bold, br, leftMargin, currentY); g.DrawString(receiptItems[0, rdAssociationNameIndex], normal, br, leftMargin + 175, currentY); } if (!string.IsNullOrEmpty(province) && province != "") { currentY += 15; g.DrawString("Province: ", bold, br, leftMargin, currentY); g.DrawString(province.ToUpper(), normal, br, leftMargin + 175, currentY); } if (!string.IsNullOrEmpty(receiptItems[0, rdRegionIndex]) && receiptItems[0, rdRegionIndex] != "Not Available") { currentY += 15; g.DrawString("Region: ", bold, br, leftMargin, currentY); g.DrawString(receiptItems[0, rdRegionIndex], normal, br, leftMargin + 175, currentY); } #endregion #region table header currentY += 30; rec.Y = currentY; textRec.Y = currentY + 10; rec.Width = applicationNumberColumnWidth; textRec.Width = applicationNumberColumnWidth - 10; g.DrawRectangle(recPen, rec); g.DrawString("Application No.", bold, br, textRec); rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = paymentForColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString("Application Type", bold, br, textRec); rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = vehicleColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString("Existing Vehicle", bold, br, textRec); rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = vehicleColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString("New Vehicle", bold, br, textRec); rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = amountColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString("Amount Received", bold, br, textRec); #endregion rec.X = leftMargin; textRec.X = rec.X + 10; rec.Y = rec.Bottom; textRec.Y = rec.Y + 4; rec.Height = 35; textRec.Height = 35; total = 0; while (printCounter < receiptItems.Length / 12) { var amount = Double.Parse(receiptItems[printCounter, rdCostIndex], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture); total += amount; if (receiptItems[printCounter, rdApplicationDescriptionIndex].Length > 35) { var tempCheck = Math.Round((double)(receiptItems[printCounter, rdApplicationDescriptionIndex].Length - 35) / 17); rec.Height = (int)(rec.Height + (15 * tempCheck)); textRec.Height = rec.Height; } #region Applicaton number rec.Width = applicationNumberColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString(receiptItems[printCounter, rdApplicationNumberIndex], normal, br, textRec); #endregion #region Application description rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = paymentForColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString(receiptItems[printCounter, rdApplicationDescriptionIndex], normal, br, textRec); #endregion #region Existing vehicle rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = vehicleColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); if (!string.IsNullOrEmpty(receiptItems[printCounter, rdExistingVehicleRegNumberIndex]) && receiptItems[printCounter, rdExistingVehicleRegNumberIndex] != "Not Available") { g.DrawString("Registration No. " + receiptItems[printCounter, rdExistingVehicleRegNumberIndex] + Environment.NewLine + "VIN No. " + receiptItems[printCounter, rdExistingVehicleChassisNumberIndex], normal, br, textRec); } else { g.DrawString("Not Available", normal, br, textRec); } #endregion #region New vehicle rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = vehicleColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); if (!string.IsNullOrEmpty(receiptItems[printCounter, rdVehicleRegNumberIndex]) && receiptItems[printCounter, rdVehicleRegNumberIndex] != "Not Available") { g.DrawString("Registration No. " + receiptItems[printCounter, rdVehicleRegNumberIndex] + Environment.NewLine + "VIN No. " + receiptItems[printCounter, rdVehicleChassisNumberIndex], normal, br, textRec); } else { g.DrawString("Not Available", normal, br, textRec); } #endregion #region Amount rec.X = rec.Right; textRec.X = rec.X + ((amount < 1000) ? 62 : 50); rec.Width = amountColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString(amount.ToString("C", CultureInfo.GetCultureInfo("en-ZA")), normal, br, textRec); #endregion if (rec.Y > e.MarginBounds.Bottom - 200) { //Print the footer PrintFooter(e, g, br, pen, rec,pageNumber); e.HasMorePages = true; #region Reset row rec.X = leftMargin; textRec.X = rec.X + 10; rec.Y = rec.Bottom; textRec.Y = rec.Y + 4; rec.Height = 35; textRec.Height = rec.Height; #endregion printCounter++; pageNumber++; return; } else { e.HasMorePages = false; } #region Reset row rec.X = leftMargin; textRec.X = rec.X + 10; rec.Y = rec.Bottom; textRec.Y = rec.Y + 4; rec.Height = 35; textRec.Height = rec.Height; printCounter++; #endregion } rec.Width = leftMargin + 595; textRec.Width = rec.Width - 10; textRec.Y = rec.Y + 12; g.DrawRectangle(recPen, rec); g.DrawString("Total Amount Received", normal, br, textRec); rec.X = rec.Right; textRec.X = rec.X + ((total < 1000) ? 62 : 50); ; rec.Width = amountColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString(total.ToString("C", CultureInfo.GetCultureInfo("en-ZA")), normal, br, textRec); //Print the footer PrintFooter(e, g, br, pen, rec, pageNumber); } #region Delegate method to do the total page count private void PageCounter(Object sender, PrintPageEventArgs e) { var receiptItems = fillArray(); Graphics g = e.Graphics; Brush br = new SolidBrush(Color.Black); Pen pen = new Pen(br, 2); Pen recPen = new Pen(br, 1); Rectangle rec = new Rectangle(leftMargin, 380, 115, 30); Rectangle textRec = new Rectangle(leftMargin + 10, rec.Y + 8, rec.Width - 15, rec.Height); var currentY = 0; #region Receipt Item Index variables var rdApplicationNumberIndex = 0; var rdIDNumberOrBusinessRegistrationNoIndex = 1; var rdApplicationDescriptionIndex = 3; var rdCostIndex = 5; var rdAssociationNameIndex = 6; var rdVehicleRegNumberIndex = 7; var rdVehicleChassisNumberIndex = 8; var rdRegionIndex = 9; var rdExistingVehicleRegNumberIndex = 10; var rdExistingVehicleChassisNumberIndex = 11; #endregion #region Table column width variables var applicationNumberColumnWidth = 105; var paymentForColumnWidth = 150; var vehicleColumnWidth = 180; var amountColumnWidth = 120; #endregion #region Page Header currentY += 5; var logo = (Image)Properties.Resources.ResourceManager.GetObject("TransportDepartmentLogo"); if (logo != null) g.DrawImage(logo, leftMargin - 5, currentY); currentY += 140; g.DrawLine(pen, leftMargin, currentY, leftMargin + 740, currentY); currentY += 10; g.DrawString(receiptHeading, new Font("Arial", 14, FontStyle.Bold), br, leftMargin + 165, currentY); currentY += 30; g.DrawString("RECEIPT OF PAYMENT", bold, br, 345, currentY); currentY += 30; #endregion #region Sumarry block at the top g.DrawString("Receipt Number :", bold, br, leftMargin, currentY); g.DrawString(receiptNumber, normal, br, leftMargin + 175, currentY); currentY += 15; g.DrawString("Payment Type: ", bold, br, leftMargin, currentY); g.DrawString(paymentType.ToUpper(), normal, br, leftMargin + 175, currentY); currentY += 15; g.DrawString("Applicant Name: ", bold, br, leftMargin, currentY); g.DrawString(applicantData, normal, br, leftMargin + 175, currentY); currentY += 15; g.DrawString("ID No./Bus Reg No.: ", bold, br, leftMargin, currentY); g.DrawString(receiptItems[0, rdIDNumberOrBusinessRegistrationNoIndex], normal, br, leftMargin + 175, currentY); if (!string.IsNullOrEmpty(receiptItems[0, rdAssociationNameIndex]) && receiptItems[0, rdAssociationNameIndex] != "Unknown") { currentY += 15; g.DrawString("Association Name: ", bold, br, leftMargin, currentY); g.DrawString(receiptItems[0, rdAssociationNameIndex], normal, br, leftMargin + 175, currentY); } if (!string.IsNullOrEmpty(province) && province != "") { currentY += 15; g.DrawString("Province: ", bold, br, leftMargin, currentY); g.DrawString(province.ToUpper(), normal, br, leftMargin + 175, currentY); } if (!string.IsNullOrEmpty(receiptItems[0, rdRegionIndex]) && receiptItems[0, rdRegionIndex] != "Not Available") { currentY += 15; g.DrawString("Region: ", bold, br, leftMargin, currentY); g.DrawString(receiptItems[0, rdRegionIndex], normal, br, leftMargin + 175, currentY); } #endregion #region table header currentY += 30; rec.Y = currentY; textRec.Y = currentY + 10; rec.Width = applicationNumberColumnWidth; textRec.Width = applicationNumberColumnWidth - 10; g.DrawRectangle(recPen, rec); g.DrawString("Application No.", bold, br, textRec); rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = paymentForColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString("Application Type", bold, br, textRec); rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = vehicleColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString("Existing Vehicle", bold, br, textRec); rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = vehicleColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString("New Vehicle", bold, br, textRec); rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = amountColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString("Amount Received", bold, br, textRec); #endregion rec.X = leftMargin; textRec.X = rec.X + 10; rec.Y = rec.Bottom; textRec.Y = rec.Y + 4; rec.Height = 35; textRec.Height = 35; total = 0; while (printCounter < receiptItems.Length / 12) { var amount = Double.Parse(receiptItems[printCounter, rdCostIndex], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture); total += amount; if (receiptItems[printCounter, rdApplicationDescriptionIndex].Length > 35) { var tempCheck = Math.Round((double)(receiptItems[printCounter, rdApplicationDescriptionIndex].Length - 35) / 17); rec.Height = (int)(rec.Height + (15 * tempCheck)); textRec.Height = rec.Height; } #region Applicaton number rec.Width = applicationNumberColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString(receiptItems[printCounter, rdApplicationNumberIndex], normal, br, textRec); #endregion #region Application description rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = paymentForColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString(receiptItems[printCounter, rdApplicationDescriptionIndex], normal, br, textRec); #endregion #region Existing vehicle rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = vehicleColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); if (!string.IsNullOrEmpty(receiptItems[printCounter, rdExistingVehicleRegNumberIndex]) && receiptItems[printCounter, rdExistingVehicleRegNumberIndex] != "Not Available") { g.DrawString("Registration No. " + receiptItems[printCounter, rdExistingVehicleRegNumberIndex] + Environment.NewLine + "VIN No. " + receiptItems[printCounter, rdExistingVehicleChassisNumberIndex], normal, br, textRec); } else { g.DrawString("Not Available", normal, br, textRec); } #endregion #region New vehicle rec.X = rec.Right; textRec.X = rec.X + 10; rec.Width = vehicleColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); if (!string.IsNullOrEmpty(receiptItems[printCounter, rdVehicleRegNumberIndex]) && receiptItems[printCounter, rdVehicleRegNumberIndex] != "Not Available") { g.DrawString("Registration No. " + receiptItems[printCounter, rdVehicleRegNumberIndex] + Environment.NewLine + "VIN No. " + receiptItems[printCounter, rdVehicleChassisNumberIndex], normal, br, textRec); } else { g.DrawString("Not Available", normal, br, textRec); } #endregion #region Amount rec.X = rec.Right; textRec.X = rec.X + ((amount < 1000) ? 62 : 50); rec.Width = amountColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString(amount.ToString("C", CultureInfo.GetCultureInfo("en-ZA")), normal, br, textRec); #endregion if (rec.Y > e.MarginBounds.Bottom - 200) { //Print the footer //PrintFooter(e, g, br, pen, rec, totalPages); e.HasMorePages = true; #region Reset row rec.X = leftMargin; textRec.X = rec.X + 10; rec.Y = 390; textRec.Y = rec.Y + 4; rec.Height = 35; textRec.Height = rec.Height; #endregion //printCounter++; totalPages++; //pageCountCompleted = true; //return ; } else { e.HasMorePages = false; } #region Reset row rec.X = leftMargin; textRec.X = rec.X + 10; rec.Y = rec.Bottom; textRec.Y = rec.Y + 4; rec.Height = 35; textRec.Height = rec.Height; printCounter++; #endregion } rec.Width = leftMargin + 595; textRec.Width = rec.Width - 10; textRec.Y = rec.Y + 12; g.DrawRectangle(recPen, rec); g.DrawString("Total Amount Received", normal, br, textRec); rec.X = rec.Right; textRec.X = rec.X + ((total < 1000) ? 62 : 50); ; rec.Width = amountColumnWidth; textRec.Width = rec.Width - 10; g.DrawRectangle(recPen, rec); g.DrawString(total.ToString("C", CultureInfo.GetCultureInfo("en-ZA")), normal, br, textRec); //Print the footer //PrintFooter(e, g, br, pen, rec, totalPages); pageCountCompleted = true; printCounter = 0; } #endregion #region Print footer details private void PrintFooter(PrintPageEventArgs e, Graphics g, Brush br, Pen pen, Rectangle rec, int pageNumber) { g.DrawString("This receipt does not authorize the conveyance of passengers", bold, br, 250, e.MarginBounds.Bottom - 85); if (isReprint) { g.DrawString("Duplicate issued by:", normal, br, leftMargin, e.MarginBounds.Bottom - 40); } else { g.DrawString("Receipt issued by:", normal, br, leftMargin, e.MarginBounds.Bottom -40); } g.DrawLine(pen, leftMargin, e.MarginBounds.Bottom , leftMargin + 180, e.MarginBounds.Bottom ); g.DrawString(printedBy, normal, br, leftMargin, e.MarginBounds.Bottom +10); g.DrawString(printedDate.ToString("dd MMM yyyy"), normal, br, leftMargin + 550, e.MarginBounds.Bottom - 20); g.DrawLine(pen, leftMargin + 550, e.MarginBounds.Bottom , leftMargin + 740, e.MarginBounds.Bottom ); if (isReprint) { g.DrawString("Date re-printed", normal, br, leftMargin + 550, e.MarginBounds.Bottom +10); } else { g.DrawString("Date issued", normal, br, leftMargin + 550, e.MarginBounds.Bottom +10); } g.DrawString("Page "+ pageNumber.ToString() + " of " + totalPages.ToString(), normal, br, e.MarginBounds.Right -5, e.MarginBounds.Bottom + 50 ); #region Test Watermark if (isReprint) { g.TranslateTransform(200, 175); g.RotateTransform(e.PageSettings.Landscape ? 30 : 45); g.DrawString("DUPLICATE", new Font("Arial", 100, FontStyle.Regular), new SolidBrush(Color.FromArgb(64, Color.Black)), 0, 0); } #endregion } #endregion #endregion #region fillArray private string[,] fillArray() { var numItems = 1 + receiptItems.Count(c => c == '#'); var rItems = new string[numItems, 12]; var temp = receiptItems.Split('#'); for (var i = 0; i < temp.Length; i++) { var temp2 = temp[i].Split(','); rItems[i, 0] = temp2[0]; rItems[i, 1] = temp2[1]; rItems[i, 2] = temp2[2]; rItems[i, 3] = temp2[3]; rItems[i, 4] = temp2[4]; rItems[i, 5] = temp2[5]; rItems[i, 6] = temp2[6]; rItems[i, 7] = temp2[7]; rItems[i, 8] = temp2[8]; if (temp2.Length >= 10) //some of the legacy data did not have all the fields { rItems[i, 9] = temp2[9]; } else { rItems[i, 9] = "Not Available"; } if (temp2.Length >= 11) { rItems[i, 10] = temp2[10]; } else { rItems[i, 10] = "Not Available"; } if (temp2.Length >= 12) { rItems[i, 11] = temp2[11]; } else { rItems[i, 11] = "Not Available"; } } return rItems; } } #endregion }