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.gl.report;
017    
018    import java.io.FileNotFoundException;
019    import java.io.FileOutputStream;
020    import java.text.DecimalFormat;
021    import java.text.SimpleDateFormat;
022    import java.util.ArrayList;
023    import java.util.Collections;
024    import java.util.Date;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Map;
028    
029    import org.kuali.kfs.gl.businessobject.Transaction;
030    import org.kuali.kfs.sys.Message;
031    import org.kuali.kfs.sys.context.SpringContext;
032    import org.kuali.rice.kns.service.DateTimeService;
033    
034    import com.lowagie.text.Document;
035    import com.lowagie.text.DocumentException;
036    import com.lowagie.text.ExceptionConverter;
037    import com.lowagie.text.Font;
038    import com.lowagie.text.FontFactory;
039    import com.lowagie.text.PageSize;
040    import com.lowagie.text.Phrase;
041    import com.lowagie.text.Rectangle;
042    import com.lowagie.text.pdf.PdfPCell;
043    import com.lowagie.text.pdf.PdfPTable;
044    import com.lowagie.text.pdf.PdfPageEventHelper;
045    import com.lowagie.text.pdf.PdfWriter;
046    
047    /**
048     * This class represents the functionality related to the generating the Transaction Report. The transaction report
049     * shows the primary key from transactions and a list of messages for each one.
050     * 
051     */
052    public class TransactionReport {
053        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(TransactionReport.class);
054    
055        static public class PageHelper extends PdfPageEventHelper {
056            public Date runDate;
057            public Font headerFont;
058            public String title;
059    
060            /**
061             * Generates the end page for this transaction report
062             * 
063             * @see com.lowagie.text.pdf.PdfPageEventHelper#onEndPage(com.lowagie.text.pdf.PdfWriter, com.lowagie.text.Document)
064             */
065            public void onEndPage(PdfWriter writer, Document document) {
066                try {
067                    Rectangle page = document.getPageSize();
068                    PdfPTable head = new PdfPTable(3);
069                    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
070                    PdfPCell cell = new PdfPCell(new Phrase(sdf.format(runDate), headerFont));
071                    cell.setBorder(Rectangle.NO_BORDER);
072                    head.addCell(cell);
073    
074                    cell = new PdfPCell(new Phrase(title, headerFont));
075                    cell.setBorder(Rectangle.NO_BORDER);
076                    cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
077                    head.addCell(cell);
078    
079                    cell = new PdfPCell(new Phrase("Page: " + new Integer(writer.getPageNumber()), headerFont));
080                    cell.setBorder(Rectangle.NO_BORDER);
081                    cell.setHorizontalAlignment(PdfPCell.ALIGN_RIGHT);
082                    head.addCell(cell);
083    
084                    head.setTotalWidth(page.width() - document.leftMargin() - document.rightMargin());
085                    head.writeSelectedRows(0, -1, document.leftMargin(), page.height() - document.topMargin() + head.getTotalHeight(), writer.getDirectContent());
086                }
087                catch (Exception e) {
088                    throw new ExceptionConverter(e);
089                }
090            }
091        }
092    
093        public TransactionReport() {
094            super();
095        }
096    
097    
098        /**
099         * Generates transaction report
100         * 
101         * @param reportErrors map containing transactions and the errors associated with each transaction
102         * @param reportSummary list of summary objects
103         * @param runDate date report is run
104         * @param title title of report
105         * @param fileprefix file prefix of report file
106         * @param destinationDirectory destination of where report file will reside
107         */
108        public void generateReport(Map<Transaction, List<Message>> reportErrors, List<Summary> reportSummary, Date runDate, String title, String fileprefix, String destinationDirectory) {
109            LOG.debug("generateReport() started");
110    
111            List transactions = new ArrayList();
112            if (reportErrors != null) {
113                transactions.addAll(reportErrors.keySet());
114            }
115            generateReport(transactions, reportErrors, reportSummary, runDate, title, fileprefix, destinationDirectory);
116        }
117    
118        /**
119         * Generates transaction report
120         * 
121         * @param errorSortedList list of error'd transactions
122         * @param reportErrors map containing transactions and the errors associated with each transaction
123         * @param reportSummary list of summary objects
124         * @param runDate date report is run
125         * @param title title of report
126         * @param fileprefix file prefix of report file
127         * @param destinationDirectory destination of where report file will reside
128         */
129        public void generateReport(List<Transaction> errorSortedList, Map<Transaction, List<Message>> reportErrors, List<Summary> reportSummary, Date runDate, String title, String fileprefix, String destinationDirectory) {
130            LOG.debug("generateReport() started");
131    
132            Font headerFont = FontFactory.getFont(FontFactory.COURIER, 8, Font.BOLD);
133            Font textFont = FontFactory.getFont(FontFactory.COURIER, 8, Font.NORMAL);
134    
135            Document document = new Document(PageSize.A4.rotate());
136    
137            PageHelper helper = new PageHelper();
138            helper.runDate = runDate;
139            helper.headerFont = headerFont;
140            helper.title = title;
141    
142            try {
143                DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class);
144                
145                String filename = destinationDirectory + "/" + fileprefix + "_";
146                filename = filename + dateTimeService.toDateTimeStringForFilename(runDate);
147                filename = filename + ".pdf";
148                PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
149                writer.setPageEvent(helper);
150    
151                document.open();
152                appendReport(document, headerFont, textFont, errorSortedList, reportErrors, reportSummary, runDate);
153            }
154            catch (DocumentException de) {
155                LOG.error("generateReport() Error creating PDF report", de);
156                throw new RuntimeException("Report Generation Failed: " + de.getMessage());
157            }
158            catch (FileNotFoundException fnfe) {
159                LOG.error("generateReport() Error writing PDF report", fnfe);
160                throw new RuntimeException("Report Generation Failed: Error writing to file " + fnfe.getMessage());
161            }
162            finally {
163                if ((document != null) && document.isOpen()) {
164                    document.close();
165                }
166            }
167        }
168    
169        /**
170         * Appends the scrubber totals/statistics and error report to the given (iText) document object.
171         * 
172         * @param document the PDF document
173         * @param headerFont font for header
174         * @param textFont font for report text
175         * @param errorSortedList list of error'd transactions
176         * @param reportErrors map containing transactions and the errors associated with each transaction
177         * @param reportSummary list of summary objects
178         * @param runDate date report was run
179         * @throws DocumentException
180         */
181        public void appendReport(Document document, Font headerFont, Font textFont, List<Transaction> errorSortedList, Map<Transaction, List<Message>> reportErrors, List<Summary> reportSummary, Date runDate) throws DocumentException {
182            // Sort what we get
183            Collections.sort(reportSummary);
184    
185            float[] summaryWidths = { 80, 20 };
186            PdfPTable summary = new PdfPTable(summaryWidths);
187            summary.setWidthPercentage(40);
188            PdfPCell cell = new PdfPCell(new Phrase("S T A T I S T I C S", headerFont));
189            cell.setColspan(2);
190            cell.setBorder(Rectangle.NO_BORDER);
191            cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
192            summary.addCell(cell);
193    
194            for (Iterator iter = reportSummary.iterator(); iter.hasNext();) {
195                Summary s = (Summary) iter.next();
196    
197                cell = new PdfPCell(new Phrase(s.getDescription(), textFont));
198                cell.setBorder(Rectangle.NO_BORDER);
199                summary.addCell(cell);
200    
201                if ("".equals(s.getDescription())) {
202                    cell = new PdfPCell(new Phrase("", textFont));
203                    cell.setBorder(Rectangle.NO_BORDER);
204                    summary.addCell(cell);
205                }
206                else {
207                    DecimalFormat nf = new DecimalFormat("###,###,###,##0");
208                    cell = new PdfPCell(new Phrase(nf.format(s.getCount()), textFont));
209                    cell.setBorder(Rectangle.NO_BORDER);
210                    cell.setHorizontalAlignment(PdfPCell.ALIGN_RIGHT);
211                    summary.addCell(cell);
212                }
213            }
214            cell = new PdfPCell(new Phrase(""));
215            cell.setColspan(2);
216            cell.setBorder(Rectangle.NO_BORDER);
217            summary.addCell(cell);
218    
219            document.add(summary);
220    
221            if (reportErrors != null && reportErrors.size() > 0) {
222                float[] warningWidths = { 4, 3, 6, 5, 5, 4, 5, 5, 4, 5, 5, 9, 4, 36 };
223                PdfPTable warnings = new PdfPTable(warningWidths);
224                warnings.setHeaderRows(2);
225                warnings.setWidthPercentage(100);
226                cell = new PdfPCell(new Phrase("W A R N I N G S", headerFont));
227                cell.setColspan(14);
228                cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
229                warnings.addCell(cell);
230    
231                // Add headers
232                cell = new PdfPCell(new Phrase("Year", headerFont));
233                warnings.addCell(cell);
234                cell = new PdfPCell(new Phrase("COA", headerFont));
235                warnings.addCell(cell);
236                cell = new PdfPCell(new Phrase("Account", headerFont));
237                warnings.addCell(cell);
238                cell = new PdfPCell(new Phrase("Sacct", headerFont));
239                warnings.addCell(cell);
240                cell = new PdfPCell(new Phrase("Obj", headerFont));
241                warnings.addCell(cell);
242                cell = new PdfPCell(new Phrase("SObj", headerFont));
243                warnings.addCell(cell);
244                cell = new PdfPCell(new Phrase("BalTyp", headerFont));
245                warnings.addCell(cell);
246                cell = new PdfPCell(new Phrase("ObjTyp", headerFont));
247                warnings.addCell(cell);
248                cell = new PdfPCell(new Phrase("Prd", headerFont));
249                warnings.addCell(cell);
250                cell = new PdfPCell(new Phrase("DocType", headerFont));
251                warnings.addCell(cell);
252                cell = new PdfPCell(new Phrase("Origin", headerFont));
253                warnings.addCell(cell);
254                cell = new PdfPCell(new Phrase("DocNbr", headerFont));
255                warnings.addCell(cell);
256                cell = new PdfPCell(new Phrase("Seq", headerFont));
257                warnings.addCell(cell);
258                cell = new PdfPCell(new Phrase("Warning", headerFont));
259                warnings.addCell(cell);
260    
261                for (Iterator errorIter = errorSortedList.iterator(); errorIter.hasNext();) {
262                    Transaction tran = (Transaction) errorIter.next();
263                    boolean first = true;
264    
265                    List errors = (List) reportErrors.get(tran);
266                    for (Iterator listIter = errors.iterator(); listIter.hasNext();) {
267                        String msg = null;
268                        Object m = listIter.next();
269                        if (m instanceof Message) {
270                            Message mm = (Message) m;
271                            msg = mm.getMessage();
272                        }
273                        else {
274                            if (m == null) {
275                                msg = "";
276                            }
277                            else {
278                                msg = m.toString();
279                            }
280                        }
281    
282                        if (first) {
283                            first = false;
284    
285                            if (tran.getUniversityFiscalYear() == null) {
286                                cell = new PdfPCell(new Phrase("NULL", textFont));
287                            }
288                            else {
289                                cell = new PdfPCell(new Phrase(tran.getUniversityFiscalYear().toString(), textFont));
290                            }
291                            warnings.addCell(cell);
292                            cell = new PdfPCell(new Phrase(tran.getChartOfAccountsCode(), textFont));
293                            warnings.addCell(cell);
294                            cell = new PdfPCell(new Phrase(tran.getAccountNumber(), textFont));
295                            warnings.addCell(cell);
296                            cell = new PdfPCell(new Phrase(tran.getSubAccountNumber(), textFont));
297                            warnings.addCell(cell);
298                            cell = new PdfPCell(new Phrase(tran.getFinancialObjectCode(), textFont));
299                            warnings.addCell(cell);
300                            cell = new PdfPCell(new Phrase(tran.getFinancialSubObjectCode(), textFont));
301                            warnings.addCell(cell);
302                            cell = new PdfPCell(new Phrase(tran.getFinancialBalanceTypeCode(), textFont));
303                            warnings.addCell(cell);
304                            cell = new PdfPCell(new Phrase(tran.getFinancialObjectTypeCode(), textFont));
305                            warnings.addCell(cell);
306                            cell = new PdfPCell(new Phrase(tran.getUniversityFiscalPeriodCode(), textFont));
307                            warnings.addCell(cell);
308                            cell = new PdfPCell(new Phrase(tran.getFinancialDocumentTypeCode(), textFont));
309                            warnings.addCell(cell);
310                            cell = new PdfPCell(new Phrase(tran.getFinancialSystemOriginationCode(), textFont));
311                            warnings.addCell(cell);
312                            cell = new PdfPCell(new Phrase(tran.getDocumentNumber(), textFont));
313                            warnings.addCell(cell);
314                            if (tran.getTransactionLedgerEntrySequenceNumber() == null) {
315                                cell = new PdfPCell(new Phrase("NULL", textFont));
316                            }
317                            else {
318                                cell = new PdfPCell(new Phrase(tran.getTransactionLedgerEntrySequenceNumber().toString(), textFont));
319                            }
320                            warnings.addCell(cell);
321                        }
322                        else {
323                            cell = new PdfPCell(new Phrase("", textFont));
324                            cell.setColspan(13);
325                            warnings.addCell(cell);
326                        }
327                        cell = new PdfPCell(new Phrase(msg, textFont));
328                        warnings.addCell(cell);
329                    }
330                }
331                document.add(warnings);
332            }
333        }
334    }