001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.module.purap.pdf;
017    
018    import java.io.ByteArrayOutputStream;
019    import java.io.FileNotFoundException;
020    import java.io.FileOutputStream;
021    import java.io.IOException;
022    import java.math.BigDecimal;
023    import java.text.NumberFormat;
024    import java.text.SimpleDateFormat;
025    import java.util.ArrayList;
026    import java.util.Collection;
027    import java.util.List;
028    import java.util.Locale;
029    
030    import org.apache.commons.lang.ArrayUtils;
031    import org.apache.commons.lang.StringUtils;
032    import org.apache.commons.logging.Log;
033    import org.apache.commons.logging.LogFactory;
034    import org.kuali.kfs.module.purap.PurapConstants;
035    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderItem;
036    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderVendorStipulation;
037    import org.kuali.kfs.module.purap.document.PurchaseOrderDocument;
038    import org.kuali.kfs.module.purap.document.PurchaseOrderRetransmitDocument;
039    import org.kuali.kfs.module.purap.exception.PurError;
040    import org.kuali.kfs.module.purap.util.PurApDateFormatUtils;
041    import org.kuali.kfs.sys.KFSConstants;
042    import org.kuali.rice.kns.util.KualiDecimal;
043    
044    import com.lowagie.text.Chunk;
045    import com.lowagie.text.Document;
046    import com.lowagie.text.DocumentException;
047    import com.lowagie.text.Element;
048    import com.lowagie.text.ExceptionConverter;
049    import com.lowagie.text.Image;
050    import com.lowagie.text.Paragraph;
051    import com.lowagie.text.Phrase;
052    import com.lowagie.text.pdf.BaseFont;
053    import com.lowagie.text.pdf.PdfPCell;
054    import com.lowagie.text.pdf.PdfPTable;
055    import com.lowagie.text.pdf.PdfWriter;
056    
057    /**
058     * Base class to handle pdf for purchase order documents.
059     */
060    public class PurchaseOrderPdf extends PurapPdf {
061        private static Log LOG = LogFactory.getLog(PurchaseOrderPdf.class);
062    
063        /** headerTable pieces need to be public */
064    
065        public PurchaseOrderPdf() {
066            super();
067        }
068    
069        /**
070         * Overrides the method in PdfPageEventHelper from itext to create and set the headerTable and set its logo image if 
071         * there is a logoImage to be used, creates and sets the nestedHeaderTable and its content.
072         * 
073         * @param writer    The PdfWriter for this document.
074         * @param document  The document.
075         * @see com.lowagie.text.pdf.PdfPageEventHelper#onOpenDocument(com.lowagie.text.pdf.PdfWriter, com.lowagie.text.Document)
076         */
077        public void onOpenDocument(PdfWriter writer, Document document) {
078            LOG.debug("onOpenDocument() started. isRetransmit is " + isRetransmit);
079            try {
080                float[] headerWidths = { 0.20f, 0.80f };
081                headerTable = new PdfPTable(headerWidths);
082                headerTable.setWidthPercentage(100);
083                headerTable.setHorizontalAlignment(Element.ALIGN_CENTER);
084                headerTable.setSplitLate(false);
085                headerTable.getDefaultCell().setBorderWidth(0);
086                headerTable.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
087                headerTable.getDefaultCell().setVerticalAlignment(Element.ALIGN_CENTER);
088                
089                Image logo = null;
090                if (StringUtils.isNotBlank(logoImage)) {
091                    try {
092                        logo = Image.getInstance(logoImage);
093                    }
094                    catch (FileNotFoundException e) {
095                        LOG.info("The logo image [" + logoImage + "] is not available.  Defaulting to the default image.");
096                    }            
097                }
098                
099                if (logo == null) {
100                    // if we don't use images
101                    headerTable.addCell(new Phrase(new Chunk("")));
102                }
103                else {
104                    logo.scalePercent(3, 3);
105                    headerTable.addCell(new Phrase(new Chunk(logo, 0, 0)));
106                }
107                // Nested table for titles, etc.
108                float[] nestedHeaderWidths = { 0.70f, 0.30f };
109                nestedHeaderTable = new PdfPTable(nestedHeaderWidths);
110                nestedHeaderTable.setSplitLate(false);
111                PdfPCell cell;
112    
113                // New nestedHeaderTable row
114                cell = new PdfPCell(new Paragraph(po.getBillingName(), ver_15_normal));
115                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
116                cell.setBorderWidth(0);
117                nestedHeaderTable.addCell(cell);
118                cell = new PdfPCell(new Paragraph(" ", ver_15_normal));
119                cell.setBorderWidth(0);
120                nestedHeaderTable.addCell(cell);
121                // New nestedHeaderTable row
122                if (isRetransmit) {
123                    cell = new PdfPCell(new Paragraph(po.getRetransmitHeader(), ver_15_normal));
124                }
125                else {
126                    cell = new PdfPCell(new Paragraph("PURCHASE ORDER", ver_15_normal));
127                }
128                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
129                cell.setBorderWidth(0);
130                nestedHeaderTable.addCell(cell);
131                Paragraph p = new Paragraph();
132                p.add(new Chunk("PO Number: ", ver_11_normal));
133                p.add(new Chunk(po.getPurapDocumentIdentifier().toString(), cour_7_normal));
134    
135                cell = new PdfPCell(p);
136                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
137                cell.setBorderWidth(0);
138                nestedHeaderTable.addCell(cell);
139                if (!po.getPurchaseOrderAutomaticIndicator()) { // Contract manager name goes on non-APOs.
140                    // New nestedHeaderTable row, spans both columns
141                    p = new Paragraph();
142                    p.add(new Chunk("Contract Manager: ", ver_11_normal));
143                    p.add(new Chunk(po.getContractManager().getContractManagerName(), cour_7_normal));
144                    cell = new PdfPCell(p);
145                    cell.setColspan(2);
146                    cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
147                    cell.setBorderWidth(0);
148                    nestedHeaderTable.addCell(cell);
149                }
150                // Add the nestedHeaderTable to the headerTable
151                cell = new PdfPCell(nestedHeaderTable);
152                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
153                cell.setBorderWidth(0);
154                headerTable.addCell(cell);
155    
156                // initialization of the template
157                tpl = writer.getDirectContent().createTemplate(100, 100);
158                // initialization of the font
159                helv = BaseFont.createFont("Helvetica", BaseFont.WINANSI, false);
160            }
161            catch (Exception e) {
162                throw new ExceptionConverter(e);
163            }
164        }
165    
166        /**
167         * Gets a PageEvents object.
168         * 
169         * @return a new PageEvents object
170         */
171        public PurchaseOrderPdf getPageEvents() {
172            LOG.debug("getPageEvents() started.");
173            return new PurchaseOrderPdf();
174        }
175    
176        /**
177         * Generates the pdf document based on the data in the given PurchaseOrderDocument, the pdf parameters, 
178         * environment, retransmit items, creates a pdf writer using the given byteArrayOutputStream then
179         * write the pdf document into the writer.
180         * 
181         * @param po                     The PurchaseOrderDocument to be used to generate the pdf.
182         * @param pdfParameters          The PurchaseOrderPdfParameters to be used to generate the pdf.
183         * @param byteArrayOutputStream  The ByteArrayOutputStream where the pdf document will be written to.
184         * @param isRetransmit           The boolean to indicate whether this is for a retransmit purchase order document.
185         * @param environment            The current environment used (e.g. DEV if it is a development environment).
186         * @param retransmitItems        The items selected by the user to be retransmitted.
187         */
188        public void generatePdf(PurchaseOrderDocument po, PurchaseOrderTransmitParameters pdfParameters, ByteArrayOutputStream byteArrayOutputStream, boolean isRetransmit, String environment, List<PurchaseOrderItem> retransmitItems) {
189            LOG.debug("generatePdf() started for po number " + po.getPurapDocumentIdentifier());
190    
191            this.isRetransmit = isRetransmit;
192            String statusInquiryUrl = pdfParameters.getStatusInquiryUrl();
193            String campusName = pdfParameters.getCampusParameter().getCampus().getCampusName();
194            String contractLanguage = pdfParameters.getContractLanguage();
195            String logoImage = pdfParameters.getLogoImage();
196            String directorSignatureImage = pdfParameters.getDirectorSignatureImage();
197            String directorName = pdfParameters.getCampusParameter().getCampusPurchasingDirectorName();
198            String directorTitle = pdfParameters.getCampusParameter().getCampusPurchasingDirectorTitle();
199            String contractManagerSignatureImage = pdfParameters.getContractManagerSignatureImage();
200    
201            try {
202                Document doc = this.getDocument(9, 9, 70, 36);
203                PdfWriter writer = PdfWriter.getInstance(doc, byteArrayOutputStream);
204                this.createPdf(po, doc, writer, statusInquiryUrl, campusName, contractLanguage, logoImage, directorSignatureImage, directorName, directorTitle, contractManagerSignatureImage, isRetransmit, environment, retransmitItems);
205            }
206            catch (DocumentException de) {
207                LOG.error("generatePdf() DocumentException: " + de.getMessage(), de);
208                throw new PurError("Document Exception when trying to save a Purchase Order PDF", de);
209            }
210            catch (IOException i) {
211                LOG.error("generatePdf() IOException: " + i.getMessage(), i);
212                throw new PurError("IO Exception when trying to save a Purchase Order PDF", i);
213            }
214            catch (Exception t) {
215                LOG.error("generatePdf() EXCEPTION: " + t.getMessage(), t);
216                throw new PurError("Exception when trying to save a Purchase Order PDF", t);
217            }
218        }
219    
220        /**
221         * Invokes the createPdf method to create a pdf document and saves it into a file 
222         * which name and location are specified in the pdfParameters.
223         * 
224         * @param po             The PurchaseOrderDocument to be used to create the pdf.
225         * @param pdfParameters  The pdfParameters containing some of the parameters information needed by the pdf for example, the pdf file name and pdf file location, purchasing director name, etc.
226         * @param isRetransmit   The boolean to indicate whether this is for a retransmit purchase order document.
227         * @param environment    The current environment used (e.g. DEV if it is a development environment).
228         */
229        public void savePdf(PurchaseOrderDocument po, PurchaseOrderParameters pdfParameters, boolean isRetransmit, String environment) {
230            LOG.debug("savePdf() started for po number " + po.getPurapDocumentIdentifier());
231    
232            PurchaseOrderTransmitParameters pdfTransmitParameters = (PurchaseOrderTransmitParameters)pdfParameters;        
233            
234            this.isRetransmit = isRetransmit;
235            String statusInquiryUrl = pdfTransmitParameters.getStatusInquiryUrl();
236            String campusName = pdfTransmitParameters.getCampusParameter().getCampus().getCampusName();
237            String contractLanguage = pdfTransmitParameters.getContractLanguage();
238            String logoImage = pdfTransmitParameters.getLogoImage();
239            String directorSignatureImage = pdfTransmitParameters.getDirectorSignatureImage();
240            String directorName = pdfTransmitParameters.getCampusParameter().getCampusPurchasingDirectorName();
241            String directorTitle = pdfTransmitParameters.getCampusParameter().getCampusPurchasingDirectorTitle();
242            String contractManagerSignatureImage = pdfTransmitParameters.getContractManagerSignatureImage();
243            String pdfFileLocation = pdfTransmitParameters.getPdfFileLocation();
244            String pdfFileName = pdfTransmitParameters.getPdfFileName();
245    
246            try {
247                Document doc = this.getDocument(9, 9, 70, 36);
248                PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(pdfFileLocation + pdfFileName));
249                this.createPdf(po, doc, writer, statusInquiryUrl, campusName, contractLanguage, logoImage, directorSignatureImage, directorName, directorTitle, contractManagerSignatureImage, isRetransmit, environment);
250            }
251            catch (DocumentException de) {
252                LOG.error("savePdf() DocumentException: " + de.getMessage(), de);
253                throw new PurError("Document Exception when trying to save a Purchase Order PDF", de);
254            }
255            catch (FileNotFoundException f) {
256                LOG.error("savePdf() FileNotFoundException: " + f.getMessage(), f);
257                throw new PurError("FileNotFound Exception when trying to save a Purchase Order PDF", f);
258            }
259            catch (IOException i) {
260                LOG.error("savePdf() IOException: " + i.getMessage(), i);
261                throw new PurError("IO Exception when trying to save a Purchase Order PDF", i);
262            }
263            catch (Exception t) {
264                LOG.error("savePdf() EXCEPTION: " + t.getMessage(), t);
265                throw new PurError("Exception when trying to save a Purchase Order PDF", t);
266            }
267        }
268    
269        /**
270         * Creates the purchase order pdf, and pass in null as the retransmitItems List because it doesn't need retransmit.
271         * 
272         * @param po                             The PurchaseOrderDocument to be used to create the pdf.
273         * @param document                       The pdf document whose margins have already been set.
274         * @param writer                         The PdfWriter to write the pdf document into.
275         * @param statusInquiryUrl               The status inquiry url to be displayed on the pdf document.
276         * @param campusName                     The campus name to be displayed on the pdf document.
277         * @param contractLanguage               The contract language to be displayed on the pdf document.
278         * @param logoImage                      The logo image file name to be displayed on the pdf document.
279         * @param directorSignatureImage         The director signature image to be displayed on the pdf document.
280         * @param directorName                   The director name to be displayed on the pdf document.
281         * @param directorTitle                  The director title to be displayed on the pdf document.
282         * @param contractManagerSignatureImage  The contract manager signature image to be displayed on the pdf document.
283         * @param isRetransmit                   The boolean to indicate whether this is for a retransmit purchase order document.
284         * @param environment                    The current environment used (e.g. DEV if it is a development environment).
285         * @throws DocumentException
286         * @throws IOException
287         */
288        private void createPdf(PurchaseOrderDocument po, Document document, PdfWriter writer, String statusInquiryUrl, String campusName, String contractLanguage, String logoImage, String directorSignatureImage, String directorName, String directorTitle, String contractManagerSignatureImage, boolean isRetransmit, String environment) throws DocumentException, IOException {
289            createPdf(po, document, writer, statusInquiryUrl, campusName, contractLanguage, logoImage, directorSignatureImage, directorName, directorTitle, contractManagerSignatureImage, isRetransmit, environment, null);
290        }
291    
292        /**
293         * Create a PDF using the given input parameters.
294         * 
295         * @param po                             The PurchaseOrderDocument to be used to create the pdf.
296         * @param document                       The pdf document whose margins have already been set.
297         * @param writer                         The PdfWriter to write the pdf document into.
298         * @param statusInquiryUrl               The status inquiry url to be displayed on the pdf document.
299         * @param campusName                     The campus name to be displayed on the pdf document.
300         * @param contractLanguage               The contract language to be displayed on the pdf document.
301         * @param logoImage                      The logo image file name to be displayed on the pdf document.
302         * @param directorSignatureImage         The director signature image to be displayed on the pdf document.
303         * @param directorName                   The director name to be displayed on the pdf document.
304         * @param directorTitle                  The director title to be displayed on the pdf document.
305         * @param contractManagerSignatureImage  The contract manager signature image to be displayed on the pdf document.
306         * @param isRetransmit                   The boolean to indicate whether this is for a retransmit purchase order document.
307         * @param environment                    The current environment used (e.g. DEV if it is a development environment).
308         * @param retransmitItems                The items selected by the user to be retransmitted.
309         * @throws DocumentException
310         * @throws IOException
311         */
312        private void createPdf(PurchaseOrderDocument po, Document document, PdfWriter writer, String statusInquiryUrl, String campusName, String contractLanguage, String logoImage, String directorSignatureImage, String directorName, String directorTitle, String contractManagerSignatureImage, boolean isRetransmit, String environment, List<PurchaseOrderItem> retransmitItems) throws DocumentException, IOException {
313            LOG.debug("createPdf() started for po number " + po.getPurapDocumentIdentifier().toString());
314    
315            // These have to be set because they are used by the onOpenDocument() and onStartPage() methods.
316            this.campusName = campusName;
317            this.po = po;
318            this.logoImage = logoImage;
319            this.environment = environment;
320    
321            NumberFormat numberFormat = NumberFormat.getCurrencyInstance(Locale.US);
322            Collection errors = new ArrayList();
323    
324            // Date format pattern: MM-dd-yyyy
325            SimpleDateFormat sdf = PurApDateFormatUtils.getSimpleDateFormat(PurapConstants.NamedDateFormats.KUALI_SIMPLE_DATE_FORMAT_2);
326    
327            // This turns on the page events that handle the header and page numbers.
328            PurchaseOrderPdf events = new PurchaseOrderPdf().getPageEvents();
329            writer.setPageEvent(this); // Passing in "this" lets it know about the po, campusName, etc.
330    
331            document.open();
332    
333            PdfPCell cell;
334            Paragraph p = new Paragraph();
335    
336            // ***** Info table (vendor, address info) *****
337            LOG.debug("createPdf() info table started.");
338            float[] infoWidths = { 0.50f, 0.50f };
339            PdfPTable infoTable = new PdfPTable(infoWidths);
340    
341            infoTable.setWidthPercentage(100);
342            infoTable.setHorizontalAlignment(Element.ALIGN_CENTER);
343            infoTable.setSplitLate(false);
344    
345            StringBuffer vendorInfo = new StringBuffer();
346            vendorInfo.append("\n");
347            if (StringUtils.isNotBlank(po.getVendorName())) {
348                vendorInfo.append("     " + po.getVendorName() + "\n");
349            }
350           
351            vendorInfo.append("     ATTN: " + po.getVendorAttentionName() + "\n");
352           
353            if (StringUtils.isNotBlank(po.getVendorLine1Address())) {
354                vendorInfo.append("     " + po.getVendorLine1Address() + "\n");
355            }
356            if (StringUtils.isNotBlank(po.getVendorLine2Address())) {
357                vendorInfo.append("     " + po.getVendorLine2Address() + "\n");
358            }
359            if (StringUtils.isNotBlank(po.getVendorCityName())) {
360                vendorInfo.append("     " + po.getVendorCityName());
361            }
362            if (StringUtils.isNotBlank(po.getVendorStateCode())) {
363                vendorInfo.append(", " + po.getVendorStateCode());
364            }
365            if (StringUtils.isNotBlank(po.getVendorAddressInternationalProvinceName())) {
366                vendorInfo.append(", " + po.getVendorAddressInternationalProvinceName());
367            }
368            if (StringUtils.isNotBlank(po.getVendorPostalCode())) {
369                vendorInfo.append(" " + po.getVendorPostalCode() + "\n");
370            }
371            else {
372                vendorInfo.append("\n");
373            }
374            if (!KFSConstants.COUNTRY_CODE_UNITED_STATES.equalsIgnoreCase(po.getVendorCountryCode()) && po.getVendorCountry() != null) {
375                vendorInfo.append("     " + po.getVendorCountry().getPostalCountryName() + "\n\n");
376            }
377            else {
378                vendorInfo.append("\n\n");
379            }
380            p = new Paragraph();
381            p.add(new Chunk(" Vendor", ver_5_normal));
382            p.add(new Chunk(vendorInfo.toString(), cour_7_normal));
383            cell = new PdfPCell(p);
384            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
385            infoTable.addCell(cell);
386    
387            StringBuffer shipToInfo = new StringBuffer();
388            shipToInfo.append("\n");
389            
390            if (po.getAddressToVendorIndicator()) { // use receiving address
391                shipToInfo.append("     " + po.getReceivingName() + "\n");
392                shipToInfo.append("     " + po.getReceivingLine1Address() + "\n");
393                if (StringUtils.isNotBlank(po.getReceivingLine2Address())) {
394                    shipToInfo.append("     " + po.getReceivingLine2Address() + "\n");
395                }
396                shipToInfo.append("     " + po.getReceivingCityName() + ", " + po.getReceivingStateCode() + " " + po.getReceivingPostalCode() + "\n");
397                if (StringUtils.isNotBlank(po.getReceivingCountryName()) && !KFSConstants.COUNTRY_CODE_UNITED_STATES.equalsIgnoreCase(po.getReceivingCountryName())) {
398                    shipToInfo.append("     " + po.getReceivingCountryName() + "\n\n");
399                }
400                else {
401                    shipToInfo.append("\n\n");
402                }            
403            }
404            else { // use delivery address
405                shipToInfo.append("     " + po.getDeliveryToName() + "\n");
406                // extra space needed below to separate other text going on same PDF line
407                String deliveryBuildingName = po.getDeliveryBuildingName() + " ";
408                if (po.isDeliveryBuildingOtherIndicator()) {
409                    deliveryBuildingName = "";
410                }
411                shipToInfo.append("     " + deliveryBuildingName + "Room #" + po.getDeliveryBuildingRoomNumber() + "\n");
412                shipToInfo.append("     " + po.getDeliveryBuildingLine1Address() + "\n");
413                if (StringUtils.isNotBlank(po.getDeliveryBuildingLine2Address())) {
414                    shipToInfo.append("     " + po.getDeliveryBuildingLine2Address() + "\n");
415                }
416                shipToInfo.append("     " + po.getDeliveryCityName() + ", " + po.getDeliveryStateCode() + " " + po.getDeliveryPostalCode() + "\n");
417                if (StringUtils.isNotBlank(po.getDeliveryCountryName()) && !KFSConstants.COUNTRY_CODE_UNITED_STATES.equalsIgnoreCase(po.getDeliveryCountryName())) {
418                    shipToInfo.append("     " + po.getDeliveryCountryName() + "\n\n");
419                }
420                else {
421                    shipToInfo.append("\n\n");
422                }
423            }
424            
425            p = new Paragraph();
426            p.add(new Chunk("  Shipping Address", ver_5_normal));
427            p.add(new Chunk(shipToInfo.toString(), cour_7_normal));
428            cell = new PdfPCell(p);
429            infoTable.addCell(cell);
430    
431            p = new Paragraph();
432            p.add(new Chunk("  Shipping Terms\n", ver_5_normal));
433            if (po.getVendorShippingPaymentTerms() != null && po.getVendorShippingTitle() != null) {
434                p.add(new Chunk("     " + po.getVendorShippingPaymentTerms().getVendorShippingPaymentTermsDescription(), cour_7_normal));
435                p.add(new Chunk(" - " + po.getVendorShippingTitle().getVendorShippingTitleDescription(), cour_7_normal));
436            }
437            else if (po.getVendorShippingPaymentTerms() != null && po.getVendorShippingTitle() == null) {
438                p.add(new Chunk("     " + po.getVendorShippingPaymentTerms().getVendorShippingPaymentTermsDescription(), cour_7_normal));
439            }
440            else if (po.getVendorShippingTitle() != null && po.getVendorShippingPaymentTerms() == null) {
441                p.add(new Chunk("     " + po.getVendorShippingTitle().getVendorShippingTitleDescription(), cour_7_normal));
442            }
443            cell = new PdfPCell(p);
444            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
445            infoTable.addCell(cell);
446    
447            p = new Paragraph();
448            p.add(new Chunk("  Payment Terms\n", ver_5_normal));
449            if (po.getVendorPaymentTerms() != null) {
450                p.add(new Chunk("     " + po.getVendorPaymentTerms().getVendorPaymentTermsDescription(), cour_7_normal));
451            }
452            cell = new PdfPCell(p);
453            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
454            infoTable.addCell(cell);
455    
456            p = new Paragraph();
457            p.add(new Chunk("  Delivery Required By\n", ver_5_normal));
458    
459            if (po.getDeliveryRequiredDate() != null && po.getDeliveryRequiredDateReason() != null) {
460                p.add(new Chunk("     " + sdf.format(po.getDeliveryRequiredDate()), cour_7_normal));
461                p.add(new Chunk(" - " + po.getDeliveryRequiredDateReason().getDeliveryRequiredDateReasonDescription(), cour_7_normal));
462            }
463            else if (po.getDeliveryRequiredDate() != null && po.getDeliveryRequiredDateReason() == null) {
464                p.add(new Chunk("     " + sdf.format(po.getDeliveryRequiredDate()), cour_7_normal));
465            }
466            else if (po.getDeliveryRequiredDate() == null && po.getDeliveryRequiredDateReason() != null) {
467                p.add(new Chunk("     " + po.getDeliveryRequiredDateReason().getDeliveryRequiredDateReasonDescription(), cour_7_normal));
468            }
469            cell = new PdfPCell(p);
470            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
471            infoTable.addCell(cell);
472    
473            p = new Paragraph();
474            p.add(new Chunk("  ", ver_5_normal));
475            cell = new PdfPCell(p);
476            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
477            infoTable.addCell(cell);
478    
479            // Nested table for Order Date, etc.
480            float[] nestedInfoWidths = { 0.50f, 0.50f };
481            PdfPTable nestedInfoTable = new PdfPTable(nestedInfoWidths);
482            nestedInfoTable.setSplitLate(false);
483    
484            p = new Paragraph();
485            p.add(new Chunk("  Order Date\n", ver_5_normal));
486    
487            String orderDate = "";
488            if (po.getPurchaseOrderInitialOpenTimestamp() != null) {
489                orderDate = sdf.format(po.getPurchaseOrderInitialOpenTimestamp());
490            }
491            else { 
492                // This date isn't set until the first time this document is printed, so will be null the first time; use today's date.
493                orderDate = sdf.format(getDateTimeService().getCurrentSqlDate());
494            }
495    
496            p.add(new Chunk("     " + orderDate, cour_7_normal));
497            cell = new PdfPCell(p);
498            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
499            nestedInfoTable.addCell(cell);
500    
501            p = new Paragraph();
502            p.add(new Chunk("  Customer #\n", ver_5_normal));
503            if (po.getVendorCustomerNumber() != null) {
504                p.add(new Chunk("     " + po.getVendorCustomerNumber(), cour_7_normal));
505            }
506            cell = new PdfPCell(p);
507            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
508            nestedInfoTable.addCell(cell);
509    
510            p = new Paragraph();
511            p.add(new Chunk("  Delivery Instructions\n", ver_5_normal));
512            if (StringUtils.isNotBlank(po.getDeliveryInstructionText())) {
513                p.add(new Chunk("     " + po.getDeliveryInstructionText(), cour_7_normal));
514            }
515            cell = new PdfPCell(p);
516            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
517            nestedInfoTable.addCell(cell);
518    
519            p = new Paragraph();
520            p.add(new Chunk("  Contract ID\n", ver_5_normal));
521            if (po.getVendorContract() != null) {
522                p.add(new Chunk(po.getVendorContract().getVendorContractName(), cour_7_normal));
523            }
524            cell = new PdfPCell(p);
525            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
526            nestedInfoTable.addCell(cell);
527    
528            // Add the nestedInfoTable to the infoTable
529            cell = new PdfPCell(nestedInfoTable);
530            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
531            infoTable.addCell(cell);
532    
533            StringBuffer billToInfo = new StringBuffer();
534            billToInfo.append("\n");
535            billToInfo.append("     " + po.getBillingName() + "\n");
536            billToInfo.append("     " + po.getBillingLine1Address() + "\n");
537            if (po.getBillingLine2Address() != null) {
538                billToInfo.append("     " + po.getBillingLine2Address() + "\n");
539            }
540            billToInfo.append("     " + po.getBillingCityName() + ", " + po.getBillingStateCode() + " " + po.getBillingPostalCode() + "\n");
541            if (po.getBillingPhoneNumber() != null) {
542                billToInfo.append("     " + po.getBillingPhoneNumber());
543            }
544            p = new Paragraph();
545            p.add(new Chunk("  Billing Address", ver_5_normal));
546            p.add(new Chunk("     " + billToInfo.toString(), cour_7_normal));
547            p.add(new Chunk("\n Invoice status inquiry: " + statusInquiryUrl, ver_6_normal));
548            cell = new PdfPCell(p);
549            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
550            infoTable.addCell(cell);
551    
552            document.add(infoTable);
553    
554            PdfPTable notesStipulationsTable = new PdfPTable(1);
555            notesStipulationsTable.setWidthPercentage(100);
556            notesStipulationsTable.setSplitLate(false);
557    
558            p = new Paragraph();
559            p.add(new Chunk("  Vendor Note(s)\n", ver_5_normal));
560            if (po.getVendorNoteText() != null) {
561                p.add(new Chunk("     " + po.getVendorNoteText() + "\n", cour_7_normal));
562            }
563    
564            PdfPCell tableCell = new PdfPCell(p);
565            tableCell.setHorizontalAlignment(Element.ALIGN_LEFT);
566            tableCell.setVerticalAlignment(Element.ALIGN_TOP);
567    
568            notesStipulationsTable.addCell(tableCell);
569    
570            p = new Paragraph();
571            p.add(new Chunk("  Vendor Stipulations and Information\n", ver_5_normal));
572            if ((po.getPurchaseOrderBeginDate() != null) && (po.getPurchaseOrderEndDate() != null)) {
573                p.add(new Chunk("     Order in effect from " + sdf.format(po.getPurchaseOrderBeginDate()) + " to " + sdf.format(po.getPurchaseOrderEndDate()) + ".\n", cour_7_normal));
574    
575            }
576            Collection<PurchaseOrderVendorStipulation> vendorStipulationsList = po.getPurchaseOrderVendorStipulations();
577            if (vendorStipulationsList.size() > 0) {
578                StringBuffer vendorStipulations = new StringBuffer();
579                for (PurchaseOrderVendorStipulation povs : vendorStipulationsList) {
580                    vendorStipulations.append("     " + povs.getVendorStipulationDescription() + "\n");
581                }
582                p.add(new Chunk("     " + vendorStipulations.toString(), cour_7_normal));
583            }
584    
585            tableCell = new PdfPCell(p);
586            tableCell.setHorizontalAlignment(Element.ALIGN_LEFT);
587            tableCell.setVerticalAlignment(Element.ALIGN_TOP);
588            notesStipulationsTable.addCell(tableCell);
589    
590            document.add(notesStipulationsTable);
591    
592            // ***** Items table *****
593            LOG.debug("createPdf() items table started.");
594            
595            float[] itemsWidths = { 0.07f, 0.1f, 0.07f, 0.45f, 0.15f, 0.15f};
596            
597            if (!po.isUseTaxIndicator()){
598                itemsWidths = ArrayUtils.add(itemsWidths, 0.14f);    
599                itemsWidths = ArrayUtils.add(itemsWidths, 0.15f);
600            }
601    
602            PdfPTable itemsTable = new PdfPTable(itemsWidths.length);
603            
604            // itemsTable.setCellsFitPage(false); With this set to true a large cell will
605            // skip to the next page. The default Table behaviour seems to be what we want:
606            // start the large cell on the same page and continue it to the next.
607            itemsTable.setWidthPercentage(100);
608            itemsTable.setWidths(itemsWidths);
609            itemsTable.setSplitLate(false);
610    
611            tableCell = new PdfPCell(new Paragraph("Item\nNo.", ver_5_normal));
612            tableCell.setHorizontalAlignment(Element.ALIGN_CENTER);
613            itemsTable.addCell(tableCell);
614            tableCell = new PdfPCell(new Paragraph("Quantity", ver_5_normal));
615            tableCell.setHorizontalAlignment(Element.ALIGN_CENTER);
616            itemsTable.addCell(tableCell);
617            tableCell = new PdfPCell(new Paragraph("UOM", ver_5_normal));
618            tableCell.setHorizontalAlignment(Element.ALIGN_CENTER);
619            itemsTable.addCell(tableCell);
620            tableCell = new PdfPCell(new Paragraph("Description", ver_5_normal));
621            tableCell.setHorizontalAlignment(Element.ALIGN_CENTER);
622            itemsTable.addCell(tableCell);
623            tableCell = new PdfPCell(new Paragraph("Unit Cost", ver_5_normal));
624            tableCell.setHorizontalAlignment(Element.ALIGN_CENTER);
625            itemsTable.addCell(tableCell);
626            tableCell = new PdfPCell(new Paragraph("Extended Cost", ver_5_normal));
627            tableCell.setHorizontalAlignment(Element.ALIGN_CENTER);
628            itemsTable.addCell(tableCell);
629    
630            if (!po.isUseTaxIndicator()){
631                tableCell = new PdfPCell(new Paragraph("Tax Amount", ver_5_normal));
632                tableCell.setHorizontalAlignment(Element.ALIGN_CENTER);
633                itemsTable.addCell(tableCell);
634                
635                tableCell = new PdfPCell(new Paragraph("Total Amount", ver_5_normal));
636                tableCell.setHorizontalAlignment(Element.ALIGN_CENTER);
637                itemsTable.addCell(tableCell);
638            }
639            
640            Collection<PurchaseOrderItem> itemsList = new ArrayList();
641            if (isRetransmit) {
642                itemsList = retransmitItems;
643            }
644            else {
645                itemsList = po.getItems();
646            }
647            for (PurchaseOrderItem poi : itemsList) {
648                if ((poi.getItemType() != null) && (poi.getItemType().isLineItemIndicator() || poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_SHIP_AND_HAND_CODE) || poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_FREIGHT_CODE) || poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE) || poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE)) && lineItemDisplaysOnPdf(poi)) {
649    
650                    String description = (poi.getItemCatalogNumber() != null) ? poi.getItemCatalogNumber().trim() + " - " : "";
651                    description = description + ((poi.getItemDescription() != null) ? poi.getItemDescription().trim() : "");
652                    if (StringUtils.isNotBlank(description)) {
653                        if (poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE) || poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE) || poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_FREIGHT_CODE) || poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_SHIP_AND_HAND_CODE)) {
654                            // If this is a full order discount or trade-in item, we add the item type description to the description.
655                            description = poi.getItemType().getItemTypeDescription() + " - " + description;
656                        }
657                    }
658    
659                    // Above the line item types items display the line number; other types don't.
660                    if (poi.getItemType().isLineItemIndicator()) {
661                        tableCell = new PdfPCell(new Paragraph(poi.getItemLineNumber().toString(), cour_7_normal));
662                    }
663                    else {
664                        tableCell = new PdfPCell(new Paragraph(" ", cour_7_normal));
665                    }
666                    tableCell.setHorizontalAlignment(Element.ALIGN_CENTER);
667                    itemsTable.addCell(tableCell);
668                    String quantity = (poi.getItemQuantity() != null) ? poi.getItemQuantity().toString() : " ";
669                    tableCell = new PdfPCell(new Paragraph(quantity, cour_7_normal));
670                    tableCell.setHorizontalAlignment(Element.ALIGN_CENTER);
671                    tableCell.setNoWrap(true);
672                    itemsTable.addCell(tableCell);
673                    tableCell = new PdfPCell(new Paragraph(poi.getItemUnitOfMeasureCode(), cour_7_normal));
674                    tableCell.setHorizontalAlignment(Element.ALIGN_CENTER);
675                    itemsTable.addCell(tableCell);
676    
677                    tableCell = new PdfPCell(new Paragraph(" " + description, cour_7_normal));
678                    tableCell.setHorizontalAlignment(Element.ALIGN_LEFT);
679                    itemsTable.addCell(tableCell);
680                    String unitPrice = poi.getItemUnitPrice().setScale(4, BigDecimal.ROUND_HALF_UP).toString();
681                    tableCell = new PdfPCell(new Paragraph(unitPrice + " ", cour_7_normal));
682                    tableCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
683                    tableCell.setNoWrap(true);
684                    itemsTable.addCell(tableCell);
685                    tableCell = new PdfPCell(new Paragraph(numberFormat.format(poi.getExtendedPrice()) + " ", cour_7_normal));
686                    tableCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
687                    tableCell.setNoWrap(true);
688                    itemsTable.addCell(tableCell);
689                    
690                    if (!po.isUseTaxIndicator()){
691                        KualiDecimal taxAmount = poi.getItemTaxAmount();
692                        taxAmount = taxAmount == null ? KualiDecimal.ZERO : taxAmount;
693                        tableCell = new PdfPCell(new Paragraph(numberFormat.format(taxAmount) + " ", cour_7_normal));
694                        tableCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
695                        tableCell.setNoWrap(true);
696                        itemsTable.addCell(tableCell);
697                        
698                        tableCell = new PdfPCell(new Paragraph(numberFormat.format(poi.getTotalAmount()) + " ", cour_7_normal));
699                        tableCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
700                        tableCell.setNoWrap(true);
701                        itemsTable.addCell(tableCell);
702                    }
703                    
704                }
705            }
706            // Blank line before totals
707            itemsTable.addCell(" ");
708            itemsTable.addCell(" ");
709            itemsTable.addCell(" ");
710            itemsTable.addCell(" ");
711            itemsTable.addCell(" ");
712            itemsTable.addCell(" ");
713            
714            if (!po.isUseTaxIndicator()){
715                itemsTable.addCell(" ");
716                itemsTable.addCell(" ");
717            }
718            
719            //Next Line
720            if (!po.isUseTaxIndicator()){
721                
722                //Print Total Prior to Tax
723                itemsTable.addCell(" ");
724                itemsTable.addCell(" ");
725                itemsTable.addCell(" ");
726                itemsTable.addCell(" ");
727                itemsTable.addCell(" ");
728                
729                tableCell = new PdfPCell(new Paragraph("Total Prior to Tax: ", ver_10_normal));
730                tableCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
731                itemsTable.addCell(tableCell);
732                itemsTable.addCell(" ");
733                KualiDecimal totalDollarAmount = new KualiDecimal(BigDecimal.ZERO);
734                if (po instanceof PurchaseOrderRetransmitDocument) {
735                    totalDollarAmount = ((PurchaseOrderRetransmitDocument) po).getTotalPreTaxDollarAmountForRetransmit();
736                }
737                else {
738                    totalDollarAmount = po.getTotalPreTaxDollarAmount();
739                }
740                tableCell = new PdfPCell(new Paragraph(numberFormat.format(totalDollarAmount) + " ", cour_7_normal));
741                tableCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
742                tableCell.setNoWrap(true);
743                itemsTable.addCell(tableCell);
744                
745                //Print Total Tax
746                itemsTable.addCell(" ");
747                itemsTable.addCell(" ");
748                itemsTable.addCell(" ");
749                itemsTable.addCell(" ");
750                itemsTable.addCell(" ");
751    
752                tableCell = new PdfPCell(new Paragraph("Total Tax: ", ver_10_normal));
753                tableCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
754                itemsTable.addCell(tableCell);
755                itemsTable.addCell(" ");
756                totalDollarAmount = new KualiDecimal(BigDecimal.ZERO);
757                if (po instanceof PurchaseOrderRetransmitDocument) {
758                    totalDollarAmount = ((PurchaseOrderRetransmitDocument) po).getTotalTaxDollarAmountForRetransmit();
759                }
760                else {
761                    totalDollarAmount = po.getTotalTaxAmount();
762                }
763                tableCell = new PdfPCell(new Paragraph(numberFormat.format(totalDollarAmount) + " ", cour_7_normal));
764                tableCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
765                tableCell.setNoWrap(true);
766                itemsTable.addCell(tableCell);
767                
768            }
769            
770            // Totals line; first 3 cols empty
771            itemsTable.addCell(" ");
772            itemsTable.addCell(" ");
773            itemsTable.addCell(" ");
774            
775            if (!po.isUseTaxIndicator()){
776                itemsTable.addCell(" ");
777                itemsTable.addCell(" ");
778            }
779            
780            tableCell = new PdfPCell(new Paragraph("Total order amount: ", ver_10_normal));
781            tableCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
782            itemsTable.addCell(tableCell);
783            itemsTable.addCell(" ");
784            KualiDecimal totalDollarAmount = new KualiDecimal(BigDecimal.ZERO);
785            if (po instanceof PurchaseOrderRetransmitDocument) {
786                totalDollarAmount = ((PurchaseOrderRetransmitDocument) po).getTotalDollarAmountForRetransmit();
787            }
788            else {
789                totalDollarAmount = po.getTotalDollarAmount();
790            }
791            tableCell = new PdfPCell(new Paragraph(numberFormat.format(totalDollarAmount) + " ", cour_7_normal));
792            tableCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
793            tableCell.setNoWrap(true);
794            itemsTable.addCell(tableCell);
795            // Blank line after totals
796            itemsTable.addCell(" ");
797            itemsTable.addCell(" ");
798            itemsTable.addCell(" ");
799            itemsTable.addCell(" ");
800            itemsTable.addCell(" ");
801            itemsTable.addCell(" ");
802            
803            if (!po.isUseTaxIndicator()){
804                itemsTable.addCell(" ");
805                itemsTable.addCell(" ");
806            }
807            
808            document.add(itemsTable);
809    
810            // Contract language.
811            LOG.debug("createPdf() contract language started.");
812            document.add(new Paragraph(contractLanguage, ver_6_normal));
813            document.add(new Paragraph("\n", ver_6_normal));
814    
815            // ***** Signatures table *****
816            LOG.debug("createPdf() signatures table started.");
817            float[] signaturesWidths = { 0.30f, 0.70f };
818            PdfPTable signaturesTable = new PdfPTable(signaturesWidths);
819            signaturesTable.setWidthPercentage(100);
820            signaturesTable.setHorizontalAlignment(Element.ALIGN_CENTER);
821            signaturesTable.setSplitLate(false);
822    
823            // Director signature and "for more info" line; only on APOs
824            if (po.getPurchaseOrderAutomaticIndicator()) {
825                // Empty cell.
826                cell = new PdfPCell(new Paragraph(" ", cour_7_normal));
827                cell.setBorderWidth(0);
828                signaturesTable.addCell(cell);
829    
830                if (StringUtils.isBlank(po.getInstitutionContactName()) || StringUtils.isBlank(po.getInstitutionContactPhoneNumber())) {
831                    p = new Paragraph("For more information contact: " + po.getRequestorPersonName() + "  " + po.getRequestorPersonPhoneNumber(), cour_7_normal);
832                }
833                else {
834                    p = new Paragraph("For more information contact: " + po.getInstitutionContactName() + "  " + po.getInstitutionContactPhoneNumber(), cour_7_normal);
835                }
836                cell = new PdfPCell(p);
837                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
838                cell.setVerticalAlignment(Element.ALIGN_CENTER);
839                cell.setBorderWidth(0);
840                signaturesTable.addCell(cell);
841                
842                Image directorSignature = null;
843                if (StringUtils.isNotBlank(directorSignatureImage)) {
844                    try {
845                        directorSignature = Image.getInstance(directorSignatureImage);
846                    }
847                    catch (FileNotFoundException e) {
848                        LOG.info("The director signature image [" + directorSignatureImage + "] is not available.  Defaulting to the default image.");
849                    }
850                }
851                                    
852                if (directorSignature == null) {
853                    // an empty cell if the contract manager signature image is not available.
854                    cell = new PdfPCell();
855                }
856                else {
857                    directorSignature.scalePercent(30, 30);
858                    cell = new PdfPCell(directorSignature, false);
859                }
860                
861                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
862                cell.setVerticalAlignment(Element.ALIGN_BOTTOM);
863                cell.setBorderWidth(0);
864                signaturesTable.addCell(cell);
865    
866                // Empty cell.
867                cell = new PdfPCell(new Paragraph(" ", cour_7_normal));
868                cell.setBorderWidth(0);
869                signaturesTable.addCell(cell);
870            }
871    
872            // Director name and title; on every pdf.
873            p = new Paragraph();
874            LOG.debug("createPdf() directorName parameter: " + directorName);
875            if (po.getPurchaseOrderAutomaticIndicator()) { // The signature is on the pdf; use small font.
876                p.add(new Chunk(directorName, ver_6_normal));
877            }
878            else { // The signature isn't on the pdf; use larger font.
879                p.add(new Chunk(directorName, ver_10_normal));
880            }
881            p.add(new Chunk("\n" + directorTitle, ver_4_normal));
882            cell = new PdfPCell(p);
883            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
884            cell.setVerticalAlignment(Element.ALIGN_TOP);
885            cell.setBorderWidth(0);
886            signaturesTable.addCell(cell);
887    
888            // Contract manager signature, name and phone; only on non-APOs
889            if (!po.getPurchaseOrderAutomaticIndicator()) {
890                
891                Image contractManagerSignature = null;
892                if (StringUtils.isNotBlank(contractManagerSignatureImage)) {
893                    try {
894                        contractManagerSignature = Image.getInstance(contractManagerSignatureImage);
895                    } catch (FileNotFoundException e) {
896                        LOG.info("The contract manager image [" + contractManagerSignatureImage + "] is not available.  Defaulting to the default image.");
897                    }
898                }
899                
900                if (contractManagerSignature == null) {
901                    // an empty cell if the contract manager signature image is not available.
902                    cell = new PdfPCell();
903                }
904                else {
905                    contractManagerSignature.scalePercent(15, 15);
906                    cell = new PdfPCell(contractManagerSignature, false);
907                }
908                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
909                cell.setVerticalAlignment(Element.ALIGN_BOTTOM);
910                cell.setBorderWidth(0);
911                signaturesTable.addCell(cell);
912    
913                // Empty cell.
914                cell = new PdfPCell(new Paragraph(" ", ver_10_normal));
915                cell.setBorderWidth(0);
916                signaturesTable.addCell(cell);
917    
918                cell = new PdfPCell(new Paragraph(po.getContractManager().getContractManagerName() + "  " + po.getContractManager().getContractManagerPhoneNumber(), cour_7_normal));
919                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
920                cell.setVerticalAlignment(Element.ALIGN_TOP);
921                cell.setBorderWidth(0);
922                signaturesTable.addCell(cell);
923            }
924            else { // Empty cell.
925                cell = new PdfPCell(new Paragraph(" ", ver_10_normal));
926                cell.setBorderWidth(0);
927                signaturesTable.addCell(cell);
928            }
929            document.add(signaturesTable);
930    
931            document.close();
932            LOG.debug("createPdf()pdf document closed.");
933        } // End of createPdf()
934    
935        /**
936         * Determines whether the item should be displayed on the pdf.
937         * 
938         * @param poi  The PurchaseOrderItem to be determined whether it should be displayed on the pdf.
939         * @return     boolean true if it should be displayed on the pdf.
940         */
941        private boolean lineItemDisplaysOnPdf(PurchaseOrderItem poi) {
942            LOG.debug("lineItemDisplaysOnPdf() started");
943    
944            // Shipping, freight, full order discount and trade in items.
945            if ((poi.getItemType() != null) && (poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_SHIP_AND_HAND_CODE) || poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_FREIGHT_CODE) || poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE) || poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE))) {
946    
947                // If the unit price is not null and either the unit price > 0 or the item type is full order discount or trade in,
948                // we'll display this line item on pdf.
949                if ((poi.getItemUnitPrice() != null) && ((poi.getItemUnitPrice().compareTo(zero.bigDecimalValue()) == 1) || (poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) || (poi.getItemType().getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE)))) {
950                    LOG.debug("lineItemDisplaysOnPdf() Item type is " + poi.getItemType().getItemTypeCode() + ". Unit price is " + poi.getItemUnitPrice() + ". Display on pdf.");
951                    return true;
952                }
953                LOG.debug("lineItemDisplaysOnPdf() Item type is " + poi.getItemType().getItemTypeCode() + ". Unit price is " + poi.getItemUnitPrice() + ". Don't display on pdf.");
954                return false;
955            }
956            else if ((poi.getItemType() != null) && poi.getItemType().isLineItemIndicator()) {
957                if (poi.getItemQuantity() == null && poi.getItemUnitPrice() == null) {
958                    LOG.debug("lineItemDisplaysOnPdf() Item type is " + poi.getItemType().getItemTypeCode() + " OrderQuantity and unit price are both null. Display on pdf.");
959                    return true;
960                }
961                if ((poi.getItemType().isAmountBasedGeneralLedgerIndicator() && ((poi.getItemUnitPrice() != null) && (poi.getItemUnitPrice().compareTo(zero.bigDecimalValue()) >= 0))) || (((poi.getItemType().isQuantityBasedGeneralLedgerIndicator()) && (poi.getItemQuantity().isGreaterThan(zero))) && (poi.getItemUnitPrice() != null))) {
962                    LOG.debug("lineItemDisplaysOnPdf() Item type is " + poi.getItemType().getItemTypeCode() + " OrderQuantity is " + poi.getItemQuantity() + ". Unit price is " + poi.getItemUnitPrice() + ". Display on pdf.");
963                    return true;
964                }
965                else {
966                    LOG.debug("lineItemDisplaysOnPdf() Item type is " + poi.getItemType().getItemTypeCode() + " and item order quantity is " + poi.getItemQuantity() + " and item unit price is " + poi.getItemUnitPrice() + ". Don't display on pdf.");
967                }
968            }
969            return false;
970        }
971    
972    }