PDF delivery note : v1.5

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
14 years ago
It's basically a customized version of pdfInvoice ...

It's designed to fold neatly and fit inside one of those A7 sized clear sticky backed plastic 'documents enclosed' envelopes -  clearly displaying the store name, return address, contact telephone number and the customers shipping address to the carrier.

It won't be of use to everyone of course, but it is to me and if anyone else can make use of it, then all the better.

it uses several new resource strings which would need to be created in admin-->localisation - some of them may be redundant for some users. If you prefer, you can replace the resource strings.

features:
no prices
a place to tick off as the item is packed
a place for the customer to tick off when checking the contents on receipt
a place where it can be signed by the person who packed the order.

it also displays a banner logo - obviously a different style of logo would necessitate customisation (and the file path of the image will also need to be altered to suit )

originally, i had the banner logo in the header (it looked better nearer the top of the page), but on subsequent pages it was partially overwritten by the product grid - if anyone knows how to alter the default size of the header, i'd like to know how ! EDIT : thanks for answering this mb

i wanted to use the smart new 'display order note to customer' function in admin so that if an order note is marked to be displayed to the customer then that order note will also be published to the pdf but I did not do this - i put up a separate post about this to try and find out how to ...


here's how its implemented

============================================================================


In File admin/modules    OrderDetails.ascx      add the following (just before the pdf invoice button) - notice there are resourcestrings here - replace them with text if it's easier
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


        <!-- Delivery note button  -->
        <asp:Button ID="btnGetDeliveryPDF" runat="server" CssClass="adminButtonBlue" Text="<% $NopResources:Admin.OrderDetails.DeliveryPDF.Text %>"
            OnClick="btnGetDeliveryPDF_Click" CausesValidation="false" ToolTip="<% $NopResources:Admin.OrderDetails.DeliveryPDF.Tooltip %>" />



============================================================================


In File admin/modules    OrderDetails.ascx.cs      add the following


//
//   Delivery note
//
        protected void btnGetDeliveryPDF_Click(object sender, EventArgs e)
        {
            try
            {
                Order order = OrderManager.GetOrderByID(this.OrderID);

                string fileName = string.Format("order_{0}_{1}.pdf", order.OrderGUID, DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"));
                string filePath = string.Format("{0}files\\ExportImport\\{1}", HttpContext.Current.Request.PhysicalApplicationPath, fileName);

                PDFHelper.PrintDeliveryNoteToPDF(order, NopContext.Current.WorkingLanguage.LanguageID, filePath);
                CommonHelper.WriteResponsePDF(filePath, fileName);
            }
            catch (Exception ex)
            {
                ProcessException(ex);
            }
        }



============================================================================
EDITED to include MB's alterations (see following post) - thanks mb :)

In File   libraries/Nop.businesslogic/utils   PDFHelper.cs       - add the following
~~~~~~~~~~~~~~


       /// <summary>
        /// Print a Delivery Note to PDF                      
        /// </summary>
        /// <param name="order">Order</param>
        /// <param name="LanguageID">Language identifier</param>
        /// <param name="FilePath">File path</param>

        public static void PrintDeliveryNoteToPDF(Order order, int LanguageID, string FilePath)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            if (String.IsNullOrEmpty(FilePath))
                throw new ArgumentNullException("FilePath");

            Document doc = new Document();

            doc.DefaultPageSetup.LeftMargin = Unit.FromCentimeter(1.7);
            doc.DefaultPageSetup.RightMargin = Unit.FromCentimeter(1.7);
            doc.DefaultPageSetup.BottomMargin = Unit.FromCentimeter(1.91);
            doc.DefaultPageSetup.TopMargin = Unit.FromCentimeter(2.76); // adjust to fit your image
            doc.DefaultPageSetup.HeaderDistance = Unit.FromCentimeter(.76); // adjust to fit your image

            Section sec = doc.AddSection();

//sec.PageSetup.PageFormat = PageFormat.Letter; // Uncomment to use Letter size instead of A4
            sec.PageSetup.OddAndEvenPagesHeaderFooter = false;
            HeaderFooter pageHeader = sec.Headers.Primary;

// places logo  ( this example uses a banner logo whose original dimensions are 527px x 59px )
            string imageFilePath = System.Web.HttpContext.Current.Server.MapPath("..") + "/images/graphics/pdflogo.png";            
            Image image = pageHeader.AddImage(imageFilePath);
            image.Height = Unit.FromCentimeter(1.7);
            image.LockAspectRatio = true;
            image.RelativeVertical = RelativeVertical.Line;
            image.RelativeHorizontal = RelativeHorizontal.Margin;
            image.Top = ShapePosition.Top;
            image.Left = ShapePosition.Right;
            image.WrapFormat.Style = WrapStyle.Through;



// create top table
            var RefDetailsTable = sec.AddTable();
            RefDetailsTable.AddColumn(Unit.FromCentimeter(9));
            RefDetailsTable.AddColumn(Unit.FromCentimeter(9));
            RefDetailsTable.Borders.Visible = false;
            Row rowRef = RefDetailsTable.AddRow();

// build top table col 1
            //  my own resource string - reads:      Delivery Advice
            Paragraph dp1 = rowRef.Cells[0].AddParagraph(LocalizationManager.GetLocaleResourceString("PDFDeliveryNote.Title"));
            dp1.Format.Font.Bold = true;
            dp1.Format.Font.Color = Colors.Black;
            Paragraph dp2 = rowRef.Cells[0].AddParagraph(String.Format(LocalizationManager.GetLocaleResourceString("PDFInvoice.Order#", LanguageID), order.OrderID));
            dp2.Format.Font.Bold = true;
            dp2.Format.Font.Color = Colors.Black;
            rowRef.Cells[0].AddParagraph(String.Format(LocalizationManager.GetLocaleResourceString("PDFInvoice.OrderDate", LanguageID), order.CreatedOn));
            rowRef.Cells[0].AddParagraph(SettingManager.StoreURL.Trim(new char[] { '/' })).AddHyperlink(SettingManager.StoreURL, HyperlinkType.Url);

// build top table col 2
            Paragraph dp3 = rowRef.Cells[1].AddParagraph(SettingManager.StoreName);
            dp3.Format.Font.Size = 14;
            dp3.Format.Font.Bold = true;
            dp3.Format.Font.Italic = true;
            // my own resource string -  used for the store contact email address - its different from the one used by the store but you could add that one programmatically if you prefer      
            rowRef.Cells[1].AddParagraph(LocalizationManager.GetLocaleResourceString("PDFDeliveryNote.LineOne.Text"));
            // my own resource string - used for the return address for not delivered items
            rowRef.Cells[1].AddParagraph(LocalizationManager.GetLocaleResourceString("PDFDeliveryNote.LineTwo.Text"));
            // my own resource string - used for the store contact telephone number
            rowRef.Cells[1].AddParagraph(LocalizationManager.GetLocaleResourceString("PDFDeliveryNote.LineThree.Text"));
            rowRef.Cells[1].Format.Alignment = ParagraphAlignment.Right;




            var addressTable = sec.AddTable();

            if (order.ShippingStatus != ShippingStatusEnum.ShippingNotRequired)
            {
                addressTable.AddColumn(Unit.FromCentimeter(9));
                addressTable.AddColumn(Unit.FromCentimeter(9));
            }
            else
            {
                addressTable.AddColumn(Unit.FromCentimeter(18));
            }
            addressTable.Borders.Visible = false;
            Row row = addressTable.AddRow();


//billing info

            Paragraph p2 = row.Cells[0].AddParagraph(LocalizationManager.GetLocaleResourceString("PDFInvoice.BillingInformation", LanguageID));
            p2.Format.Font.Bold = true;
            p2.Format.Font.Color = Colors.Black;

            if (!String.IsNullOrEmpty(order.BillingCompany))
            {
                row.Cells[0].AddParagraph(order.BillingCompany);
            }
            row.Cells[0].AddParagraph(order.BillingFullName);
            row.Cells[0].AddParagraph(order.BillingAddress1);
            if (!String.IsNullOrEmpty(order.BillingAddress2))
                row.Cells[0].AddParagraph(order.BillingAddress2);
            row.Cells[0].AddParagraph(order.BillingStateProvince);
            row.Cells[0].AddParagraph(order.BillingCity);
            row.Cells[0].AddParagraph(order.BillingZipPostalCode);
            row.Cells[0].AddParagraph(order.BillingCountry);
            row.Cells[0].AddParagraph(order.BillingPhoneNumber);


//shipping info

                Paragraph p3 = row.Cells[1].AddParagraph(LocalizationManager.GetLocaleResourceString("PDFInvoice.ShippingInformation", LanguageID));
                p3.Format.Font.Bold = true;
                p3.Format.Font.Color = Colors.Black;

                if (!String.IsNullOrEmpty(order.ShippingCompany))
                    row.Cells[1].AddParagraph(order.ShippingCompany);
                row.Cells[1].AddParagraph(order.ShippingFullName);
                row.Cells[1].AddParagraph(order.ShippingAddress1);
                if (!String.IsNullOrEmpty(order.ShippingAddress2))
                    row.Cells[1].AddParagraph(order.ShippingAddress2);
                row.Cells[1].AddParagraph(order.ShippingStateProvince);
                row.Cells[1].AddParagraph(order.ShippingCity);
                row.Cells[1].AddParagraph(order.ShippingZipPostalCode);
                row.Cells[1].AddParagraph(order.ShippingCountry);
                row.Cells[1].AddParagraph("Tel:" + order.ShippingPhoneNumber);

            sec.AddParagraph();

//products
            Paragraph p4 = sec.AddParagraph(LocalizationManager.GetLocaleResourceString("PDFInvoice.Product(s)", LanguageID));
            p4.Format.Font.Bold = true;
            p4.Format.Font.Color = Colors.Black;

            sec.AddParagraph();

            var productCollection = order.OrderProductVariants;
            var tbl = sec.AddTable();

            tbl.Borders.Visible = true;
            tbl.Borders.Width = 1;

            tbl.AddColumn(Unit.FromCentimeter(8));
            tbl.AddColumn(Unit.FromCentimeter(4));
            tbl.AddColumn(Unit.FromCentimeter(2));
            tbl.AddColumn(Unit.FromCentimeter(4));

            Row header = tbl.AddRow();

            header.Cells[0].AddParagraph(LocalizationManager.GetLocaleResourceString("PDFDeliveryNote.ProductName", LanguageID));
            header.Cells[0].Format.Alignment = ParagraphAlignment.Center;
            // my own resource string - reads:       packed
            header.Cells[1].AddParagraph(LocalizationManager.GetLocaleResourceString("PDFDeliveryNote.ColTwo.Title", LanguageID));
            header.Cells[1].Format.Alignment = ParagraphAlignment.Center;

            header.Cells[2].AddParagraph(LocalizationManager.GetLocaleResourceString("PDFDeliveryNote.ProductQuantity", LanguageID));
            header.Cells[2].Format.Alignment = ParagraphAlignment.Center;
            // my own resource string - reads:       recieved
            header.Cells[3].AddParagraph(LocalizationManager.GetLocaleResourceString("PDFDeliveryNote.ColFour.Title", LanguageID));
            header.Cells[3].Format.Alignment = ParagraphAlignment.Center;

            for (int i = 0; i < productCollection.Count; i++)
            {
                var orderProductVariant = productCollection[i];
                int rowNum = i + 1;
                Row prodRow = tbl.AddRow();

                string name = String.Format("Not available. ID={0}", orderProductVariant.ProductVariantID);
                var pv = ProductManager.GetProductVariantByID(orderProductVariant.ProductVariantID);
                if (pv != null)
                {
                    name = pv.FullProductName;
                }

                prodRow.Cells[0].AddParagraph(name);
                Paragraph p5 = prodRow.Cells[0].AddParagraph(HtmlHelper.ConvertHtmlToPlainText(orderProductVariant.AttributeDescription, true));
                p5.Format.Font.Italic = true;
                prodRow.Cells[0].Format.Alignment = ParagraphAlignment.Left;
                prodRow.Cells[1].AddParagraph();
                prodRow.Cells[2].AddParagraph(orderProductVariant.Quantity.ToString());
                prodRow.Cells[2].Format.Alignment = ParagraphAlignment.Center;
                prodRow.Cells[3].AddParagraph();
            }

            sec.AddParagraph();
            sec.AddParagraph();
            // my own resource string - reads:       Packed By : ___________________________
            sec.AddParagraph(LocalizationManager.GetLocaleResourceString("PDFPackedBy.Text", LanguageID));
            sec.AddParagraph();
            // my own resource string - a space where store owner could enter additional writing  eg. damaged goods must be reported within 3 days of receipt
            sec.AddParagraph(LocalizationManager.GetLocaleResourceString("PDFDeliveryNote.OtherText", LanguageID));
            sec.AddParagraph();
            // my own resource string - just used as a place to hand write a note on the pdf order   reads:    note(s)
            // ideally instead of this, i'd like the ability to add something here from the admin section using 'show order note to customer' function
            sec.AddParagraph(String.Format(LocalizationManager.GetLocaleResourceString("Order.Notes", LanguageID), order.OrderNotes));

// Create footer
            Paragraph pdfFooter = sec.Footers.Primary.AddParagraph();
            // my own resource string - the stores physical address
            // i think it would be useful to have a place in admin where you could provide the store address
            pdfFooter.AddText(LocalizationManager.GetLocaleResourceString("StoreOwner.Address"));
            pdfFooter.Format.Font.Size = 9;
            pdfFooter.Format.Alignment = ParagraphAlignment.Center;


            PdfDocumentRenderer renderer = new PdfDocumentRenderer(true, PdfSharp.Pdf.PdfFontEmbedding.Always);
            renderer.Document = doc;
            renderer.RenderDocument();
            renderer.PdfDocument.Save(FilePath);
        }
14 years ago
haydie wrote:
originally, i had the banner logo in the header (it looked better nearer the top of the page), but on subsequent pages it was partially overwritten by the product grid - if anyone knows how to alter the default size of the header, i'd like to know how !


You can use an image in the header and not have additional pages' content overlap the image by setting the page margins.  Try the following (new/changed lines are in bold):

double margin = 1.91;  // about .75 inches

Document doc = new Document();
doc.DefaultPageSetup.LeftMargin = Unit.FromCentimeter(margin);
doc.DefaultPageSetup.RightMargin = Unit.FromCentimeter(margin);
doc.DefaultPageSetup.BottomMargin = Unit.FromCentimeter(margin);
doc.DefaultPageSetup.TopMargin = Unit.FromCentimeter(2.76); // adjust to fit your image
doc.DefaultPageSetup.HeaderDistance = Unit.FromCentimeter(.76); // adjust to fit your image


Section sec = doc.AddSection();
//sec.PageSetup.PageFormat = PageFormat.Letter; // Uncomment to use Letter size instead of A4
sec.PageSetup.OddAndEvenPagesHeaderFooter = false;
HeaderFooter pageHeader = sec.Headers.Primary;


// places logo  ( this example uses a banner logo whose original dimensions are 527px x 59px )
string imageFilePath = System.Web.HttpContext.Current.Server.MapPath("..") + "/images/graphics/pdflogo.png";
//Image image = sec.AddImage(imageFilePath);
Image image = pageHeader.AddImage(imageFilePath);
image.Height = Unit.FromCentimeter(1.7);
image.LockAspectRatio = true;
image.RelativeVertical = RelativeVertical.Line;
image.RelativeHorizontal = RelativeHorizontal.Margin;
image.Top = ShapePosition.Top;
image.Left = ShapePosition.Right;
image.WrapFormat.Style = WrapStyle.Through;

// Remove the following
// put some spacing between the header and the first table
//sec.AddParagraph();
//sec.AddParagraph();
//sec.AddParagraph();
//sec.AddParagraph();
//sec.AddParagraph();


.
14 years ago
Thanks a lot
14 years ago
mb, thanks again - that looks much better :)

i altered the original post to reflect your advice.  I'll dig in to my invoice now and sweeten that up too
13 years ago
Thanks you for all !

My site accepts two different paypal payments methods. Complete payment method and 20% payment method.
In the pdfInvoice I would like to add 4 lines:
- Payment method: ---
- Payment status: ---
- Paid amount: ---
- Rest to be paid:---

I changed my PDFHelper.ca as follows:

sec.AddParagraph();
            
            //----- Information sur la methode de paiement :
            Paragraph p13 = sec.AddParagraph(LocalizationManager.GetLocaleResourceString("PDFInvoice.OrderDetails", languageId));
            p13.Format.Font.Bold = true;
            p13.Format.Font.Color = Colors.Black;

                      
            var p14 = sec.AddParagraph(LocalizationManager.GetLocaleResourceString("Admin.OrderDetails.PaymentMethod", languageId) + ": " + order.PaymentMethodName);
            p14.Format.Font.Color = Colors.Black;
            
            var p15 = sec.AddParagraph(LocalizationManager.GetLocaleResourceString("Admin.OrderDetails.PaymentStatus", languageId) + order.PaymentStatus);
            p15.Format.Font.Color = Colors.Black;

            var p16 = sec.AddParagraph(LocalizationManager.GetLocaleResourceString("PDFInvoice.Paidamount", languageId) + ": " + /* ??? Paid amount attribute ???*/);
            p16.Format.Font.Color = Colors.Black;

            var p17 = sec.AddParagraph(LocalizationManager.GetLocaleResourceString("PDFInvoice.Remainingamount", languageId) + ": " + /* ??? Remainingamount ???*/);
            p17.Format.Font.Color = Colors.Black;
            
            sec.AddParagraph();
            sec.AddParagraph();
            sec.AddParagraph();
            sec.AddParagraph();

            //----- Numéro de TAX sur la facture
            var p18 = sec.AddParagraph(LocalizationManager.GetLocaleResourceString("TAX.TPS.TITRE") + " : " + LocalizationManager.GetLocaleResourceString("TAX.TPS.NUM"));
            var p19 = sec.AddParagraph(LocalizationManager.GetLocaleResourceString("TAX.TVQ.TITRE") + " : " + LocalizationManager.GetLocaleResourceString("TAX.TVQ.NUM"));


I'm stuck on how I can get my paid amount and what remains to be paid ???
I thought to calcul it from the total amount and the payment method except that I'm sure this is not the best idea to do

thank you for your help ;)
13 years ago
haydie thanks for the code.

I am trying to edit the PDFHelper for the invoice in Nop 1.7. I have changed the page to letter size and it works fine.


            Document doc = new Document();

            doc.DefaultPageSetup.LeftMargin = Unit.FromCentimeter(1.7);
            doc.DefaultPageSetup.RightMargin = Unit.FromCentimeter(1.7);
            doc.DefaultPageSetup.BottomMargin = Unit.FromCentimeter(1.91);
            doc.DefaultPageSetup.TopMargin = Unit.FromCentimeter(2.76); // adjust to fit your image
            doc.DefaultPageSetup.HeaderDistance = Unit.FromCentimeter(.76); // adjust to fit your image

            Section sec = doc.AddSection();

            sec.PageSetup.PageFormat = PageFormat.Letter; // Uncomment to use Letter size instead of A4
            sec.PageSetup.OddAndEvenPagesHeaderFooter = false;
            HeaderFooter pageHeader = sec.Headers.Primary;


            Table table = sec.AddTable();


Now I am tryng to add an image for the header. When I place your code in and rebuild the solution, it will not generate a PDF. When I click on the PDF Invoice button it looks like it is loading, then nothing. I created a pdflogo.png and the directory graphics  images directory.

This is what the code looks like after I copy yours in.


            Document doc = new Document();

            doc.DefaultPageSetup.LeftMargin = Unit.FromCentimeter(1.7);
            doc.DefaultPageSetup.RightMargin = Unit.FromCentimeter(1.7);
            doc.DefaultPageSetup.BottomMargin = Unit.FromCentimeter(1.91);
            doc.DefaultPageSetup.TopMargin = Unit.FromCentimeter(2.76); // adjust to fit your image
            doc.DefaultPageSetup.HeaderDistance = Unit.FromCentimeter(.76); // adjust to fit your image

            Section sec = doc.AddSection();

            //sec.PageSetup.PageFormat = PageFormat.Letter; // Uncomment to use Letter size instead of A4
            sec.PageSetup.OddAndEvenPagesHeaderFooter = false;
            HeaderFooter pageHeader = sec.Headers.Primary;

            // places logo  ( this example uses a banner logo whose original dimensions are 527px x 59px )
            string imageFilePath = System.Web.HttpContext.Current.Server.MapPath("..") + "/images/graphics/pdflogo.png";
            Image image = pageHeader.AddImage(imageFilePath);
            image.Height = Unit.FromCentimeter(1.7);
            image.LockAspectRatio = true;
            image.RelativeVertical = RelativeVertical.Line;
            image.RelativeHorizontal = RelativeHorizontal.Margin;
            image.Top = ShapePosition.Top;
            image.Left = ShapePosition.Right;
            image.WrapFormat.Style = WrapStyle.Through;

            Table table = sec.AddTable();
            table.Borders.Visible = false;

            bool logoExists = File.Exists(PDFHelper.LogoFilePath);


Any ideas would help. Thanks
10 years ago
Is this still the only way to customize an invoice?  Seems a bit much to need to modify the website code to implement a change.  For instance, I just launched a site and I don't want to have to compile the website and go through the re-launch process again, but it is a legal requirement to have "Tax Invoice" at the top of the invoice (so I can't just use the Footer, like I did for the ABN, but that should (doesn't have to) be at the top as well.
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.