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.text.NumberFormat;
022    import java.text.ParseException;
023    import java.text.SimpleDateFormat;
024    import java.util.ArrayList;
025    import java.util.Collection;
026    import java.util.HashMap;
027    import java.util.List;
028    import java.util.Locale;
029    import java.util.Map;
030    
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.PurapPropertyConstants;
036    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderItem;
037    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderQuoteLanguage;
038    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderVendorQuote;
039    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderVendorStipulation;
040    import org.kuali.kfs.module.purap.document.PurchaseOrderDocument;
041    import org.kuali.kfs.module.purap.exception.PurError;
042    import org.kuali.kfs.module.purap.util.PurApDateFormatUtils;
043    import org.kuali.kfs.sys.KFSConstants;
044    import org.kuali.kfs.sys.KFSPropertyConstants;
045    import org.kuali.kfs.sys.context.SpringContext;
046    import org.kuali.kfs.vnd.businessobject.CampusParameter;
047    import org.kuali.kfs.vnd.businessobject.ContractManager;
048    import org.kuali.rice.kns.service.BusinessObjectService;
049    import org.kuali.rice.kns.util.ObjectUtils;
050    
051    import com.lowagie.text.Chunk;
052    import com.lowagie.text.Document;
053    import com.lowagie.text.DocumentException;
054    import com.lowagie.text.Element;
055    import com.lowagie.text.ExceptionConverter;
056    import com.lowagie.text.Font;
057    import com.lowagie.text.Image;
058    import com.lowagie.text.Paragraph;
059    import com.lowagie.text.Phrase;
060    import com.lowagie.text.pdf.BaseFont;
061    import com.lowagie.text.pdf.PdfPCell;
062    import com.lowagie.text.pdf.PdfPTable;
063    import com.lowagie.text.pdf.PdfWriter;
064    
065    /**
066     * 
067     * 
068     */
069    public class PurchaseOrderQuotePdf extends PurapPdf {
070        private static Log LOG = LogFactory.getLog(PurchaseOrderQuotePdf.class);
071    
072        public PurchaseOrderQuotePdf() {
073            super();
074        }
075    
076        /**
077         * Overrides the method in PdfPageEventHelper from itext to create and set the headerTable with relevant contents 
078         * and set its logo image if there is a logoImage to be used.
079         * 
080         * @param writer    The PdfWriter for this document.
081         * @param document  The document.
082         * @see com.lowagie.text.pdf.PdfPageEventHelper#onOpenDocument(com.lowagie.text.pdf.PdfWriter, com.lowagie.text.Document)
083         */
084        public void onOpenDocument(PdfWriter writer, Document document) {
085            LOG.debug("onOpenDocument() started.");
086            try {
087                float[] headerWidths = { 0.20f, 0.60f, 0.20f };
088                headerTable = new PdfPTable(headerWidths);
089                headerTable.setWidthPercentage(100);
090                headerTable.setHorizontalAlignment(Element.ALIGN_CENTER);
091    
092                headerTable.getDefaultCell().setBorderWidth(0);
093                headerTable.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
094                headerTable.getDefaultCell().setVerticalAlignment(Element.ALIGN_CENTER);
095    
096                if (StringUtils.isNotBlank(logoImage)) {
097                    logo = Image.getInstance(logoImage);
098                    logo.scalePercent(3, 3);
099                    headerTable.addCell(new Phrase(new Chunk(logo, 0, 0)));
100                }
101                else {
102                    // if we don't use images
103                    headerTable.addCell(new Phrase(new Chunk("")));
104                }
105                PdfPCell cell;
106                cell = new PdfPCell(new Paragraph("REQUEST FOR QUOTATION\nTHIS IS NOT AN ORDER", ver_17_normal));
107                cell.setBorderWidth(0);
108                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
109                headerTable.addCell(cell);
110    
111                Paragraph p = new Paragraph();
112                p.add(new Chunk("\n     R.Q. Number: ", ver_8_bold));
113                p.add(new Chunk(po.getPurapDocumentIdentifier() + "\n", cour_10_normal));
114                cell = new PdfPCell(p);
115                cell.setBorderWidth(0);
116                headerTable.addCell(cell);
117    
118                // initialization of the template
119                tpl = writer.getDirectContent().createTemplate(100, 100);
120                // initialization of the font
121                helv = BaseFont.createFont("Helvetica", BaseFont.WINANSI, false);
122            }
123            catch (Exception e) {
124                throw new ExceptionConverter(e);
125            }
126        }
127    
128        /**
129         * Gets a PageEvents object.
130         * 
131         * @return a new PageEvents object
132         */
133        public PurchaseOrderQuotePdf getPageEvents() {
134            LOG.debug("getPageEvents() started.");
135            return new PurchaseOrderQuotePdf();
136        }
137    
138        /**
139         * Generates the purchase order quote pdf document based on the data in the given input parameters,
140         * creates a pdf writer using the given byteArrayOutputStream then write the pdf document into the writer.
141         * 
142         * @param po                         The PurchaseOrderDocument to be used to generate the pdf.
143         * @param poqv                       The PurchaseOrderVendorQuote to be used to generate the pdf.
144         * @param campusName                 The campus name to be used to generate the pdf.
145         * @param contractManagerCampusCode  The contract manager campus code to be used to generate the pdf.
146         * @param logoImage                  The logo image file name to be used to generate the pdf.
147         * @param byteArrayOutputStream      The ByteArrayOutputStream to print the pdf to.
148         * @param environment                The current environment used (e.g. DEV if it is a development environment).
149         */
150        public void generatePOQuotePDF(PurchaseOrderDocument po, PurchaseOrderVendorQuote poqv, String campusName, String contractManagerCampusCode, String logoImage, ByteArrayOutputStream byteArrayOutputStream, String environment) {
151            LOG.debug("generatePOQuotePDF() started for po number " + po.getPurapDocumentIdentifier());
152    
153            Collection errors = new ArrayList();
154    
155            try {
156                Document doc = getDocument(9, 9, 70, 36);
157                PdfWriter writer = PdfWriter.getInstance(doc, byteArrayOutputStream);
158                this.createPOQuotePdf(po, poqv, campusName, contractManagerCampusCode, logoImage, doc, writer, environment);
159            }
160            catch (DocumentException de) {
161                LOG.error(de.getMessage(), de);
162                throw new PurError("Document Exception when trying to save a Purchase Order Quote PDF", de);
163            }
164        }
165    
166        /**
167         * Invokes the createPOQuotePDF method to create a purchase order quote pdf document and saves it into a file 
168         * which name and location are specified in the pdfParameters.
169         * 
170         * @param po                         The PurchaseOrderDocument to be used to generate the pdf.
171         * @param poqv                       The PurchaseOrderVendorQuote to be used to generate the pdf.
172         * @param pdfFileLocation            The location to save the pdf file.
173         * @param pdfFilename                The name for the pdf file.
174         * @param campusName                 The campus name to be used to generate the pdf.
175         * @param contractManagerCampusCode  The contract manager campus code to be used to generate the pdf.
176         * @param logoImage                  The logo image file name to be used to generate the pdf.
177         * @param environment                The current environment used (e.g. DEV if it is a development environment).
178         */
179        public void savePOQuotePDF(PurchaseOrderDocument po, PurchaseOrderVendorQuote poqv,PurchaseOrderParameters transmitParameters , String environment) {
180            LOG.debug("savePOQuotePDF() started for po number " + po.getPurapDocumentIdentifier());
181    
182            try {
183                PurchaseOrderTransmitParameters orderTransmitParameters = (PurchaseOrderTransmitParameters)transmitParameters;
184                CampusParameter deliveryCampus = orderTransmitParameters.getCampusParameter();
185                    if (deliveryCampus == null) {
186                        throw new RuntimeException(" delivery campus is null");
187                    }
188                    String campusName = deliveryCampus.getCampus().getCampusName();
189                    if (campusName == null) {
190                       
191                        throw new RuntimeException("Campus Information is missing - campusName: " + campusName);
192                    }
193                Document doc = this.getDocument(9, 9, 70, 36);
194                PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(orderTransmitParameters.getPdfFileLocation() + orderTransmitParameters.getPdfFileName()));
195                this.createPOQuotePdf(po, poqv,campusName, orderTransmitParameters.getContractManagerCampusCode(), orderTransmitParameters.getLogoImage(), doc, writer, environment);
196            }
197            catch (DocumentException de) {
198                LOG.error(de.getMessage(), de);
199                throw new PurError("Document Exception when trying to save a Purchase Order Quote PDF", de);
200            }
201            catch (FileNotFoundException f) {
202                LOG.error(f.getMessage(), f);
203                throw new PurError("FileNotFound Exception when trying to save a Purchase Order Quote PDF", f);
204            }
205        }
206    
207        /**
208         * Create a PDF using the given input parameters.
209         * 
210         * @param po                         The PurchaseOrderDocument to be used to create the pdf.
211         * @param poqv                       The PurchaseOrderVendorQuote to be used to generate the pdf.
212         * @param campusName                 The campus name to be used to generate the pdf.
213         * @param contractManagerCampusCode  The contract manager campus code to be used to generate the pdf.
214         * @param logoImage                  The logo image file name to be used to generate the pdf.
215         * @param document                   The pdf document whose margins have already been set.
216         * @param writer                     The PdfWriter to write the pdf document into.
217         * @param environment                The current environment used (e.g. DEV if it is a development environment).
218         * @throws DocumentException
219         */
220        private void createPOQuotePdf(PurchaseOrderDocument po, PurchaseOrderVendorQuote poqv, String campusName, String contractManagerCampusCode, String logoImage, Document document, PdfWriter writer, String environment) throws DocumentException {
221            LOG.debug("createQuotePdf() started for po number " + po.getPurapDocumentIdentifier());
222            
223            // These have to be set because they are used by the onOpenDocument() and onStartPage() methods.
224            this.campusName = campusName;
225            this.po = po;
226            this.logoImage = logoImage;
227            this.environment = environment;
228    
229            NumberFormat numberFormat = NumberFormat.getCurrencyInstance(Locale.US);
230            // Date format pattern: MM-dd-yyyy
231            SimpleDateFormat sdf = PurApDateFormatUtils.getSimpleDateFormat(PurapConstants.NamedDateFormats.KUALI_SIMPLE_DATE_FORMAT_2);
232    
233            CampusParameter campusParameter = getCampusParameter(contractManagerCampusCode);
234            String purchasingAddressFull = getPurchasingAddressFull(campusParameter);
235    
236            // Turn on the page events that handle the header and page numbers.
237            PurchaseOrderQuotePdf events = new PurchaseOrderQuotePdf().getPageEvents();
238            writer.setPageEvent(this); // Passing in "this" lets it know about the po, campusName, etc.
239    
240            document.open();
241    
242            PdfPCell cell;
243            Paragraph p = new Paragraph();
244    
245            // ***** Info table (address, vendor, other info) *****
246            LOG.debug("createQuotePdf() info table started.");
247            float[] infoWidths = { 0.45f, 0.55f };
248            PdfPTable infoTable = new PdfPTable(infoWidths);
249            infoTable.setWidthPercentage(100);
250            infoTable.setHorizontalAlignment(Element.ALIGN_CENTER);
251            infoTable.setSplitLate(false);
252    
253            p = new Paragraph();
254            ContractManager contractManager = po.getContractManager();
255            p.add(new Chunk("\n Return this form to:\n", ver_8_bold));
256            p.add(new Chunk(purchasingAddressFull + "\n", cour_10_normal));
257            p.add(new Chunk("\n", cour_10_normal));
258            p.add(new Chunk(" Fax #: ", ver_6_normal));
259            p.add(new Chunk(contractManager.getContractManagerFaxNumber() + "\n", cour_10_normal));
260            p.add(new Chunk(" Contract Manager: ", ver_6_normal));
261            p.add(new Chunk(contractManager.getContractManagerName() + " " + contractManager.getContractManagerPhoneNumber() + "\n", cour_10_normal));
262            p.add(new Chunk("\n", cour_10_normal));
263            p.add(new Chunk(" To:\n", ver_6_normal));
264            StringBuffer vendorInfo = new StringBuffer();
265            if (StringUtils.isNotBlank(poqv.getVendorAttentionName())) {
266                vendorInfo.append("     ATTN: " + poqv.getVendorAttentionName().trim() + "\n");
267            }
268            vendorInfo.append("     " + poqv.getVendorName() + "\n");
269            if (StringUtils.isNotBlank(poqv.getVendorLine1Address())) {
270                vendorInfo.append("     " + poqv.getVendorLine1Address() + "\n");
271            }
272            if (StringUtils.isNotBlank(poqv.getVendorLine2Address())) {
273                vendorInfo.append("     " + poqv.getVendorLine2Address() + "\n");
274            }
275            if (StringUtils.isNotBlank(poqv.getVendorCityName())) {
276                vendorInfo.append("     " + poqv.getVendorCityName());
277            }
278            if ((StringUtils.isNotBlank(poqv.getVendorStateCode())) && (!poqv.getVendorStateCode().equals("--"))) {
279                vendorInfo.append(", " + poqv.getVendorStateCode());
280            }
281            if (StringUtils.isNotBlank(poqv.getVendorAddressInternationalProvinceName())) {
282                vendorInfo.append(", " + poqv.getVendorAddressInternationalProvinceName());
283            }
284            if (StringUtils.isNotBlank(poqv.getVendorPostalCode())) {
285                vendorInfo.append(" " + poqv.getVendorPostalCode() + "\n");
286            }
287            else {
288                vendorInfo.append("\n");
289            }
290    
291            if (!KFSConstants.COUNTRY_CODE_UNITED_STATES.equalsIgnoreCase(poqv.getVendorCountryCode()) && poqv.getVendorCountryCode() != null) {
292                vendorInfo.append("     " + poqv.getVendorCountry().getPostalCountryName() + "\n\n");
293            }
294            else {
295                vendorInfo.append("     \n\n");
296            }
297    
298            p.add(new Chunk(vendorInfo.toString(), cour_10_normal));
299            cell = new PdfPCell(p);
300            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
301            infoTable.addCell(cell);
302    
303            p = new Paragraph();
304            p.add(new Chunk("\n     R.Q. Number: ", ver_8_bold));
305            p.add(new Chunk(po.getPurapDocumentIdentifier() + "\n", cour_10_normal));
306            java.sql.Date requestDate = getDateTimeService().getCurrentSqlDate();
307            if (poqv.getPurchaseOrderQuoteTransmitTimestamp() != null) {
308                try {
309                    requestDate = getDateTimeService().convertToSqlDate(poqv.getPurchaseOrderQuoteTransmitTimestamp());
310                }
311                catch (ParseException e) {
312                    throw new RuntimeException("ParseException thrown when trying to convert from Timestamp to SqlDate.", e);
313                }
314            }
315            p.add(new Chunk("     R.Q. Date: ", ver_8_bold));
316            p.add(new Chunk(sdf.format(requestDate) + "\n", cour_10_normal));
317            p.add(new Chunk("     RESPONSE MUST BE RECEIVED BY: ", ver_8_bold));
318            if (po.getPurchaseOrderQuoteDueDate() != null) {
319                p.add(new Chunk(sdf.format(po.getPurchaseOrderQuoteDueDate()) + "\n\n", cour_10_normal));
320            }
321            else {
322                p.add(new Chunk("N/A\n\n", cour_10_normal));
323            }
324    
325            // retrieve the quote stipulations
326            StringBuffer quoteStipulations = getPoQuoteLanguage();
327    
328            p.add(new Chunk(quoteStipulations.toString(), ver_6_normal));
329            p.add(new Chunk("\n ALL QUOTES MUST BE TOTALED", ver_12_normal));
330            cell = new PdfPCell(p);
331            infoTable.addCell(cell);
332    
333            document.add(infoTable);
334    
335            // ***** Notes and Stipulations table *****
336            // The notes and stipulations table is type Table instead of PdfPTable
337            // because Table has the method setCellsFitPage and I can't find an equivalent
338            // in PdfPTable. Long notes or stipulations would break to the next page, leaving
339            // a large white space on the previous page.
340            PdfPTable notesStipulationsTable = new PdfPTable(1);
341            notesStipulationsTable.setWidthPercentage(100);
342            notesStipulationsTable.setSplitLate(false);
343    
344            p = new Paragraph();
345            p.add(new Chunk("  Vendor Stipulations and Information\n\n", ver_6_normal));
346            if ((po.getPurchaseOrderBeginDate() != null) && (po.getPurchaseOrderEndDate() != null)) {
347                p.add(new Chunk("     Order in effect from " + sdf.format(po.getPurchaseOrderBeginDate()) + " to " + sdf.format(po.getPurchaseOrderEndDate()) + ".\n", cour_10_normal));
348            }
349            Collection<PurchaseOrderVendorStipulation> vendorStipulationsList = po.getPurchaseOrderVendorStipulations();
350            if (vendorStipulationsList.size() > 0) {
351                StringBuffer vendorStipulations = new StringBuffer();
352                for (PurchaseOrderVendorStipulation povs : vendorStipulationsList) {
353                    vendorStipulations.append("     " + povs.getVendorStipulationDescription() + "\n");
354                }
355                p.add(new Chunk("     " + vendorStipulations.toString(), cour_10_normal));
356            }
357    
358            PdfPCell tableCell = new PdfPCell(p);
359            tableCell.setHorizontalAlignment(Element.ALIGN_LEFT);
360            tableCell.setVerticalAlignment(Element.ALIGN_TOP);
361            notesStipulationsTable.addCell(tableCell);
362            document.add(notesStipulationsTable);
363    
364            // ***** Items table *****
365            LOG.debug("createQuotePdf() items table started.");
366            float[] itemsWidths = { 0.07f, 0.1f, 0.07f, 0.50f, 0.13f, 0.13f };
367            PdfPTable itemsTable = new PdfPTable(6);
368            // itemsTable.setCellsFitPage(false); With this set to true a large cell will
369            // skip to the next page. The default Table behaviour seems to be what we want:
370            // start the large cell on the same page and continue it to the next.
371            itemsTable.setWidthPercentage(100);
372            itemsTable.setWidths(itemsWidths);
373            itemsTable.setSplitLate(false);
374    
375            tableCell = createCell("Item\nNo.", false, false, false, false, Element.ALIGN_CENTER, ver_6_normal);
376            itemsTable.addCell(tableCell);
377            tableCell = createCell("Quantity", false, false, false, false, Element.ALIGN_CENTER, ver_6_normal);
378            itemsTable.addCell(tableCell);
379            tableCell = createCell("UOM", false, false, false, false, Element.ALIGN_CENTER, ver_6_normal);
380            itemsTable.addCell(tableCell);
381            tableCell = createCell("Description", false, false, false, false, Element.ALIGN_CENTER, ver_6_normal);
382            itemsTable.addCell(tableCell);
383            tableCell = createCell("Unit Cost\n(Required)", false, false, false, false, Element.ALIGN_CENTER, ver_6_normal);
384            itemsTable.addCell(tableCell);
385            tableCell = createCell("Extended Cost\n(Required)", false, false, false, false, Element.ALIGN_CENTER, ver_6_normal);
386            itemsTable.addCell(tableCell);
387    
388            if (StringUtils.isNotBlank(po.getPurchaseOrderQuoteVendorNoteText())) {
389                // Vendor notes line.
390                itemsTable.addCell(" ");
391                itemsTable.addCell(" ");
392                itemsTable.addCell(" ");
393                tableCell = createCell(po.getPurchaseOrderQuoteVendorNoteText(), false, false, false, false, Element.ALIGN_LEFT, cour_10_normal);
394                itemsTable.addCell(tableCell);
395                itemsTable.addCell(" ");
396                itemsTable.addCell(" ");
397            }
398    
399            for (PurchaseOrderItem poi : (List<PurchaseOrderItem>) po.getItems()) {
400                if ((poi.getItemType() != null) && (StringUtils.isNotBlank(poi.getItemDescription())) && (poi.getItemType().isLineItemIndicator() || poi.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_SHIP_AND_HAND_CODE) || poi.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_FREIGHT_CODE) || poi.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE) || poi.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE))) {
401                    // "ITEM"s display the line number; other types don't.
402                    String description = "";
403                    description = (StringUtils.isNotBlank(poi.getItemCatalogNumber())) ? poi.getItemCatalogNumber().trim() + " - " : "";
404                    description = description + ((StringUtils.isNotBlank(poi.getItemDescription())) ? poi.getItemDescription().trim() : "");
405    
406                    // If this is a full order discount item or trade in item, we add the
407                    // itemType description and a dash to the purchase order item description.
408                    if (StringUtils.isNotBlank(poi.getItemDescription())) {
409                        if (poi.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE) || poi.getItemTypeCode().equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE)) {
410                            description = poi.getItemType().getItemTypeDescription() + " - " + description;
411                        }
412                    }
413    
414                    // We can do the normal table now because description is not too long.
415                    String itemLineNumber = new String();
416                    if (poi.getItemType().isLineItemIndicator()) {
417                        itemLineNumber = poi.getItemLineNumber().toString();
418                    }
419                    else {
420                        itemLineNumber = "";
421                    }
422                    tableCell = createCell(itemLineNumber, false, false, false, false, Element.ALIGN_CENTER, cour_10_normal);
423                    itemsTable.addCell(tableCell);
424                    String quantity = (poi.getItemQuantity() != null) ? poi.getItemQuantity().toString() : " ";
425                    tableCell = createCell(quantity, false, false, false, false, Element.ALIGN_CENTER, cour_10_normal);
426                    itemsTable.addCell(tableCell);
427                    tableCell = createCell(poi.getItemUnitOfMeasureCode(), false, false, false, false, Element.ALIGN_CENTER, cour_10_normal);
428                    itemsTable.addCell(tableCell);
429    
430                    tableCell = createCell(description, false, false, false, false, Element.ALIGN_LEFT, cour_10_normal);
431                    itemsTable.addCell(tableCell);
432                    itemsTable.addCell(" ");
433                    itemsTable.addCell(" ");
434    
435                }
436            }
437    
438            // Blank line before totals
439            createBlankRowInItemsTable(itemsTable);
440    
441            // Totals line.
442            itemsTable.addCell(" ");
443            itemsTable.addCell(" ");
444            itemsTable.addCell(" ");
445            tableCell = createCell("Total: ", false, false, false, false, Element.ALIGN_RIGHT, ver_10_normal);
446            itemsTable.addCell(tableCell);
447            itemsTable.addCell(" ");
448            itemsTable.addCell(" ");
449            // Blank line after totals
450            createBlankRowInItemsTable(itemsTable);
451    
452            document.add(itemsTable);
453    
454            LOG.debug("createQuotePdf() vendorFillsIn table started.");
455            float[] vendorFillsInWidths = { 0.50f, 0.50f };
456            PdfPTable vendorFillsInTable = new PdfPTable(vendorFillsInWidths);
457            vendorFillsInTable.setWidthPercentage(100);
458            vendorFillsInTable.setHorizontalAlignment(Element.ALIGN_CENTER);
459            vendorFillsInTable.setSplitLate(false);
460            vendorFillsInTable.getDefaultCell().setBorderWidth(0);
461            vendorFillsInTable.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
462            vendorFillsInTable.getDefaultCell().setVerticalAlignment(Element.ALIGN_CENTER);
463    
464            // New row
465            String important = new String("\nIMPORTANT: The information and signature below MUST BE COMPLETED or your offer may be rejected.\n");
466            cell = createCell(important, true, false, false, false, Element.ALIGN_LEFT, ver_8_normal);
467            cell.setColspan(2);
468            vendorFillsInTable.addCell(cell);
469            // New row
470            String cashDiscount = new String("Terms of Payment:  Cash discount_________%_________Days-Net________Days\n");
471            cell = createCell(cashDiscount, true, false, false, false, Element.ALIGN_LEFT, ver_8_normal);
472            cell.setColspan(2);
473            vendorFillsInTable.addCell(cell);
474            // New row
475            String fob = new String(" FOB: __ Destination (Title)\n");
476            cell = createCell(fob, true, false, false, false, Element.ALIGN_LEFT, ver_8_normal);
477            vendorFillsInTable.addCell(cell);
478            String freightVendor = new String(" __ Freight Vendor Paid (Allowed)\n");
479            cell = createCell(freightVendor, true, false, false, false, Element.ALIGN_LEFT, ver_8_normal);
480            vendorFillsInTable.addCell(cell);
481            // New row
482            String shipping = new String("          __ Shipping Point (Title)\n");
483            cell = createCell(shipping, true, false, false, false, Element.ALIGN_LEFT, ver_8_normal);
484            vendorFillsInTable.addCell(cell);
485            String freightPrepaid = new String(" __ Freight Prepaid & Added Amount $_________\n");
486            cell = createCell(freightPrepaid, true, false, false, false, Element.ALIGN_LEFT, ver_8_normal);
487            vendorFillsInTable.addCell(cell);
488            // New row
489            String commonCarrier = new String("      If material will ship common carrier, please provide the following:\n");
490            cell = createCell(commonCarrier, true, false, false, false, Element.ALIGN_LEFT, ver_8_bold);
491            cell.setColspan(2);
492            vendorFillsInTable.addCell(cell);
493            // New row
494            String origin = new String("      Point of origin and zip code: ______________________ Weight: _________ Class: _________\n");
495            cell = createCell(origin, true, false, false, false, Element.ALIGN_LEFT, ver_8_bold);
496            cell.setColspan(2);
497            vendorFillsInTable.addCell(cell);
498            // New row
499            p = new Paragraph();
500            p.add(new Chunk(" Unless otherwise stated, all material to be shipped to ", ver_8_normal));
501            String purchasingAddressPartial;
502            if (po.getAddressToVendorIndicator())  // use receiving address
503                purchasingAddressPartial = po.getReceivingCityName() + ", " + po.getReceivingStateCode() + " " + po.getReceivingPostalCode();
504            else  // use final delivery address
505                purchasingAddressPartial = po.getDeliveryCityName() + ", " + po.getDeliveryStateCode() + " " + po.getDeliveryPostalCode();
506            p.add(new Chunk(purchasingAddressPartial + "\n", cour_10_normal));
507            cell = new PdfPCell(p);
508            cell.setColspan(2);
509            cell.setHorizontalAlignment(Element.ALIGN_LEFT);
510            cell.setBorderWidth(0);
511            vendorFillsInTable.addCell(cell);
512            // New row
513            String offerEffective = new String(" Offer effective until (Date):_____________\n");
514            cell = createCell(offerEffective, true, false, false, false, Element.ALIGN_LEFT, ver_8_normal);
515            vendorFillsInTable.addCell(cell);
516            String deliverBy = new String(" Delivery can be made by (Date):_____________\n");
517            cell = createCell(deliverBy, true, false, false, false, Element.ALIGN_LEFT, ver_8_normal);
518            vendorFillsInTable.addCell(cell);
519            // New row
520            String sign = new String(" SIGN HERE:____________________________\n");
521            cell = createCell(sign, true, false, false, false, Element.ALIGN_RIGHT, ver_10_bold);
522            vendorFillsInTable.addCell(cell);
523            String date = new String(" DATE:____________________________\n");
524            cell = createCell(date, true, false, false, false, Element.ALIGN_RIGHT, ver_10_bold);
525            vendorFillsInTable.addCell(cell);
526            // New row
527            String name = new String(" PRINT NAME:____________________________\n");
528            cell = createCell(name, true, false, false, false, Element.ALIGN_RIGHT, ver_10_bold);
529            vendorFillsInTable.addCell(cell);
530            String phone = new String(" PHONE:____________________________\n");
531            cell = createCell(phone, true, false, false, false, Element.ALIGN_RIGHT, ver_10_bold);
532            vendorFillsInTable.addCell(cell);
533            // New row
534            String company = new String(" COMPANY:____________________________\n");
535            cell = createCell(company, true, false, false, false, Element.ALIGN_RIGHT, ver_10_bold);
536            vendorFillsInTable.addCell(cell);
537            String fax = new String(" FAX:____________________________\n");
538            cell = createCell(fax, true, false, false, false, Element.ALIGN_RIGHT, ver_10_bold);
539            vendorFillsInTable.addCell(cell);
540    
541            document.add(vendorFillsInTable);
542            document.close();
543            LOG.debug("createQuotePdf()pdf document closed.");
544        } // End of createQuotePdf()
545    
546    
547        /**
548         * Creates and returns a string buffer of the quote language descriptions from the database, ordered by the quote language
549         * identifier and appended with carriage returns after each line.
550         * 
551         * @return  The StringBuffer of the purchase order quote language.
552         */
553        private StringBuffer getPoQuoteLanguage() {
554    
555            StringBuffer quoteLanguage = new StringBuffer();
556            Map<String, Object> criteria = new HashMap<String, Object>();
557    
558            // retrieve list of purchase order quote language objects sorted by PO Quote Language Identifier
559            Collection<PurchaseOrderQuoteLanguage> poqlList = SpringContext.getBean(BusinessObjectService.class).findMatchingOrderBy(PurchaseOrderQuoteLanguage.class, criteria, PurapPropertyConstants.PURCHASE_ORDER_QUOTE_LANGUAGE_ID, true);
560    
561            // append in string buffer
562            for (PurchaseOrderQuoteLanguage poql : poqlList) {
563                quoteLanguage.append(poql.getPurchaseOrderQuoteLanguageDescription());
564                quoteLanguage.append("\n");
565            }
566    
567            return quoteLanguage;
568    
569        }
570    
571        /**
572         * A helper method to create a blank row of 6 cells in the items table.
573         * 
574         * @param itemsTable
575         */
576        private void createBlankRowInItemsTable(PdfPTable itemsTable) {
577            // We're adding 6 cells because each row in the items table
578            // contains 6 columns.
579            for (int i = 0; i < 6; i++) {
580                itemsTable.addCell(" ");
581            }
582        }
583    
584        /**
585         * A helper method to create a PdfPCell. We can specify the content, font, horizontal alignment, border (borderless, no
586         * bottom border, no right border, no top border, etc.
587         * 
588         * @param content              The text content to be displayed in the cell.
589         * @param borderless           boolean true if the cell should be borderless.
590         * @param noBottom             boolean true if the cell should have borderWidthBottom = 0.
591         * @param noRight              boolean true if the cell should have borderWidthRight = 0.
592         * @param noTop                boolean true if the cell should have borderWidthTop = 0.
593         * @param horizontalAlignment  The desired horizontal alignment for the cell.
594         * @param font                 The font type to be used in the cell.
595         * @return                     An instance of PdfPCell which content and attributes were set by the input parameters.
596         */
597        private PdfPCell createCell(String content, boolean borderless, boolean noBottom, boolean noRight, boolean noTop, int horizontalAlignment, Font font) {
598            PdfPCell tableCell = new PdfPCell(new Paragraph(content, font));
599            if (borderless) {
600                tableCell.setBorder(0);
601            }
602            if (noBottom) {
603                tableCell.setBorderWidthBottom(0);
604            }
605            if (noTop) {
606                tableCell.setBorderWidthTop(0);
607            }
608            if (noRight) {
609                tableCell.setBorderWidthRight(0);
610            }
611            tableCell.setHorizontalAlignment(horizontalAlignment);
612            return tableCell;
613        }
614    
615        /**
616         * Obtains the CampusParameter based on the delivery campus code of the purchase order.
617         * 
618         * @param contractManagerCampusCode  This is not used anymore. 
619         * @return                           The CampusParameter whose delivery campus code matches with the 
620         *                                   purchase order's delivery campus code.
621         */
622        private CampusParameter getCampusParameter(String contractManagerCampusCode) {
623            Map<String, Object> criteria = new HashMap<String, Object>();
624            criteria.put(KFSPropertyConstants.CAMPUS_CODE, po.getDeliveryCampusCode());
625            CampusParameter campusParameter = (CampusParameter) ((List) SpringContext.getBean(BusinessObjectService.class).findMatching(CampusParameter.class, criteria)).get(0);
626    
627            return campusParameter;
628        }
629    
630        /**
631         * Creates and returns the full purchasing address given the campus parameter.
632         * 
633         * @param campusParameter  The CampusParameter object to be used to create the full purchasing address.
634         * @return                 The String containing the full purchasing address.
635         */
636        private String getPurchasingAddressFull(CampusParameter campusParameter) {
637            String indent = "     ";
638            StringBuffer addressBuffer = new StringBuffer();
639            addressBuffer.append(indent + campusParameter.getPurchasingInstitutionName() + "\n");
640            addressBuffer.append(indent + campusParameter.getPurchasingDepartmentName() + "\n");
641            addressBuffer.append(indent + campusParameter.getPurchasingDepartmentLine1Address() + "\n");
642            if (ObjectUtils.isNotNull(campusParameter.getPurchasingDepartmentLine2Address()))
643                addressBuffer.append(indent + campusParameter.getPurchasingDepartmentLine2Address() + "\n");
644            addressBuffer.append(indent + campusParameter.getPurchasingDepartmentCityName() + ", ");
645            addressBuffer.append(campusParameter.getPurchasingDepartmentStateCode() + " ");
646            addressBuffer.append(campusParameter.getPurchasingDepartmentZipCode() + " ");
647            addressBuffer.append((ObjectUtils.isNotNull(campusParameter.getPurchasingDepartmentCountryCode()) ? campusParameter.getPurchasingDepartmentCountryCode() : ""));
648    
649            return addressBuffer.toString();
650        }
651    
652        /**
653         * Creates and returns the partial purchasing address given the campus parameter.
654         * 
655         * @param campusParameter  The CampusParameter object to be used to create the partial purchasing address.
656         * @return                 The String containing the partial purchasing address.
657         */
658        private String getPurchasingAddressPartial(CampusParameter campusParameter) {
659            StringBuffer purchasingAddressPartial = new StringBuffer();
660    
661            purchasingAddressPartial.append(campusParameter.getPurchasingInstitutionName() + ", ");
662            purchasingAddressPartial.append(campusParameter.getPurchasingDepartmentCityName() + ", ");
663            purchasingAddressPartial.append(campusParameter.getPurchasingDepartmentStateCode() + " ");
664            purchasingAddressPartial.append(campusParameter.getPurchasingDepartmentZipCode());
665    
666            return purchasingAddressPartial.toString();
667        }
668    }