1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  package org.kuali.ole.fp.document.service.impl;
18  
19  import java.io.ByteArrayOutputStream;
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.OutputStream;
23  
24  import org.apache.commons.lang.StringUtils;
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.kuali.ole.fp.businessobject.Check;
28  import org.kuali.ole.fp.document.CashReceiptDocument;
29  import org.kuali.ole.fp.document.service.CashReceiptCoverSheetService;
30  import org.kuali.rice.kew.api.WorkflowDocument;
31  import org.kuali.rice.kns.service.DataDictionaryService;
32  import org.kuali.rice.kns.service.DocumentHelperService;
33  
34  import com.lowagie.text.Document;
35  import com.lowagie.text.DocumentException;
36  import com.lowagie.text.Rectangle;
37  import com.lowagie.text.pdf.AcroFields;
38  import com.lowagie.text.pdf.BaseFont;
39  import com.lowagie.text.pdf.PdfContentByte;
40  import com.lowagie.text.pdf.PdfImportedPage;
41  import com.lowagie.text.pdf.PdfReader;
42  import com.lowagie.text.pdf.PdfStamper;
43  import com.lowagie.text.pdf.PdfWriter;
44  
45  
46  
47  
48  public class CashReceiptCoverSheetServiceImpl implements CashReceiptCoverSheetService {
49      private static Log LOG = LogFactory.getLog(CashReceiptCoverSheetService.class);
50      
51      private DataDictionaryService dataDictionaryService;
52      private DocumentHelperService documentHelperService;
53  
54      public static final String CR_COVERSHEET_TEMPLATE_NM = "CashReceiptCoverSheetTemplate.pdf";
55  
56      private static final float LEFT_MARGIN = 45;
57      private static final float TOP_MARGIN = 45;
58      private static final float TOP_FIRST_PAGE = 440;
59  
60      private static final String DOCUMENT_NUMBER_FIELD = "DocumentNumber";
61      private static final String INITIATOR_FIELD = "Initiator";
62      private static final String CREATED_DATE_FIELD = "CreatedDate";
63      private static final String AMOUNT_FIELD = "Amount";
64      private static final String ORG_DOC_NUMBER_FIELD = "OrgDocNumber";
65      private static final String CAMPUS_FIELD = "Campus";
66      private static final String DEPOSIT_DATE_FIELD = "DepositDate";
67      private static final String DESCRIPTION_FIELD = "Description";
68      private static final String EXPLANATION_FIELD = "Explanation";
69      private static final String CHECKS_FIELD = "Checks";
70      private static final String CURRENCY_FIELD = "Currency";
71      private static final String COIN_FIELD = "Coin";
72      private static final String CREDIT_CARD_FIELD = "CreditCard";
73      private static final String CHANGE_OUT_FIELD = "ChangeOut";
74      private static final String TOTAL_RECONCILIATION_FIELD = "ReconciliationTotal";
75  
76      private static final int FRONT_PAGE = 1;
77      private static final int CHECK_PAGE_NORMAL = 2;
78      private static final float CHECK_DETAIL_HEADING_HEIGHT = 45;
79      private static final float CHECK_LINE_SPACING = 12;
80      private static final float CHECK_FIELD_MARGIN = 12;
81      private static final float CHECK_NORMAL_FIELD_LENGTH = 100;
82      private static final float CHECK_FIELD_HEIGHT = 10;
83      private static final int MAX_CHECKS_FIRST_PAGE = 30;
84      private static final int MAX_CHECKS_NORMAL = 65;
85  
86      private static final float CHECK_HEADER_HEIGHT = 12;
87      private static final String CHECK_NUMBER_FIELD_PREFIX = "CheckNumber";
88      private static final float CHECK_NUMBER_FIELD_POSITION = LEFT_MARGIN;
89  
90      private static final String CHECK_DATE_FIELD_PREFIX = "CheckDate";
91      private static final float CHECK_DATE_FIELD_POSITION = CHECK_NUMBER_FIELD_POSITION + CHECK_NORMAL_FIELD_LENGTH + CHECK_FIELD_MARGIN;
92  
93      private static final String CHECK_DESCRIPTION_FIELD_PREFIX = "CheckDescription";
94      private static final float CHECK_DESCRIPTION_FIELD_POSITION = CHECK_DATE_FIELD_POSITION + CHECK_NORMAL_FIELD_LENGTH + CHECK_FIELD_MARGIN;
95      private static final float CHECK_DESCRIPTION_FIELD_LENGTH = 250;
96  
97      private static final String CHECK_AMOUNT_FIELD_PREFIX = "CheckAmount";
98      private static final float CHECK_AMOUNT_FIELD_POSITION = CHECK_DESCRIPTION_FIELD_POSITION + CHECK_DESCRIPTION_FIELD_LENGTH + CHECK_FIELD_MARGIN;
99  
100     private float _yPos;
101 
102 
103     
104 
105 
106 
107 
108 
109 
110 
111 
112 
113     public boolean isCoverSheetPrintingAllowed(CashReceiptDocument crDoc) {
114         WorkflowDocument workflowDocument = crDoc.getDocumentHeader().getWorkflowDocument();
115         return !(workflowDocument.isCanceled() || workflowDocument.isInitiated() || workflowDocument.isDisapproved() || workflowDocument.isException() || workflowDocument.isDisapproved() || workflowDocument.isSaved());
116     }
117     
118     
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130     public void generateCoverSheet(CashReceiptDocument document, String searchPath, OutputStream returnStream) throws Exception {
131 
132         if (isCoverSheetPrintingAllowed(document)) {
133             ByteArrayOutputStream stamperStream = new ByteArrayOutputStream();
134 
135             stampPdfFormValues(document, searchPath, stamperStream);
136             
137             PdfReader reader = new PdfReader(stamperStream.toByteArray());
138             Document pdfDoc = new Document(reader.getPageSize(FRONT_PAGE));
139             PdfWriter writer = PdfWriter.getInstance(pdfDoc, returnStream);
140 
141             pdfDoc.open();
142             populateCheckDetail(document, writer, reader);
143             pdfDoc.close();
144             writer.close();
145         }
146     }
147 
148     
149 
150 
151 
152 
153 
154 
155 
156     protected void stampPdfFormValues(CashReceiptDocument document, String searchPath, OutputStream returnStream) throws Exception {
157         String templateName = CR_COVERSHEET_TEMPLATE_NM;
158 
159         try {
160             
161             
162             
163             
164             final boolean isWebResourcePath = StringUtils.containsIgnoreCase(searchPath, "HTTP");
165             
166             
167             PdfStamper stamper = new PdfStamper(new PdfReader(searchPath + (isWebResourcePath? "" : File.separator) + templateName), returnStream);
168             AcroFields populatedCoverSheet = stamper.getAcroFields();
169             
170             populatedCoverSheet.setField(DOCUMENT_NUMBER_FIELD, document.getDocumentNumber());
171             populatedCoverSheet.setField(INITIATOR_FIELD, document.getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId());
172             populatedCoverSheet.setField(CREATED_DATE_FIELD, document.getDocumentHeader().getWorkflowDocument().getDateCreated().toString());
173             populatedCoverSheet.setField(AMOUNT_FIELD, document.getTotalDollarAmount().toString());
174             populatedCoverSheet.setField(ORG_DOC_NUMBER_FIELD, document.getDocumentHeader().getOrganizationDocumentNumber());
175             populatedCoverSheet.setField(CAMPUS_FIELD, document.getCampusLocationCode());
176             if (document.getDepositDate() != null) {
177                 
178                 
179                 
180                 
181                 
182                 
183                 
184                 
185                 
186                 populatedCoverSheet.setField(DEPOSIT_DATE_FIELD, document.getDepositDate().toString());
187             }
188             populatedCoverSheet.setField(DESCRIPTION_FIELD, document.getDocumentHeader().getDocumentDescription());
189             populatedCoverSheet.setField(EXPLANATION_FIELD, document.getDocumentHeader().getExplanation());
190             populatedCoverSheet.setField(CHECKS_FIELD, document.getTotalCheckAmount().toString());
191             populatedCoverSheet.setField(CURRENCY_FIELD, document.getTotalCashAmount().toString());
192             populatedCoverSheet.setField(COIN_FIELD, document.getTotalCoinAmount().toString());
193             populatedCoverSheet.setField(CHANGE_OUT_FIELD, document.getTotalChangeAmount().toString());
194             
195             populatedCoverSheet.setField(TOTAL_RECONCILIATION_FIELD, document.getTotalDollarAmount().toString());
196 
197             stamper.setFormFlattening(true);
198             stamper.close();
199         }
200         catch (Exception e) {
201             LOG.error("Error creating coversheet for: " + document.getDocumentNumber() + ". ::" + e);
202             throw e;
203         }
204     }
205 
206     
207 
208 
209 
210 
211 
212     protected void writeCheckNumber(PdfContentByte output, Check check) {
213         writeCheckField(output, CHECK_NUMBER_FIELD_POSITION, check.getCheckNumber().toString());
214     }
215 
216     
217 
218 
219 
220 
221 
222     protected void writeCheckDate(PdfContentByte output, Check check) {
223         writeCheckField(output, CHECK_DATE_FIELD_POSITION, check.getCheckDate().toString());
224     }
225 
226     
227 
228 
229 
230 
231 
232     protected void writeCheckDescription(PdfContentByte output, Check check) {
233         writeCheckField(output, CHECK_DESCRIPTION_FIELD_POSITION, check.getDescription());
234     }
235 
236     
237 
238 
239 
240 
241 
242     protected void writeCheckAmount(PdfContentByte output, Check check) {
243         writeCheckField(output, CHECK_AMOUNT_FIELD_POSITION, check.getAmount().toString());
244     }
245 
246     
247 
248 
249 
250 
251 
252 
253 
254     protected void writeCheckField(PdfContentByte output, float xPos, String fieldValue) {
255         output.beginText();
256         output.setTextMatrix(xPos, getCurrentRenderingYPosition());
257         output.newlineShowText(fieldValue);
258         output.endText();
259     }
260 
261     
262 
263 
264 
265 
266 
267     protected BaseFont getTextFont() throws DocumentException, IOException {
268         return BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
269     }
270 
271     
272 
273 
274 
275 
276     protected void setCurrentRenderingYPosition(float y) {
277         _yPos = y;
278     }
279 
280     
281 
282 
283 
284 
285     protected float getCurrentRenderingYPosition() {
286         return _yPos;
287     }
288 
289     
290 
291 
292 
293 
294 
295 
296     protected void populateCheckDetail(CashReceiptDocument crDoc, PdfWriter writer, PdfReader reader) throws Exception {
297         PdfContentByte content;
298         ModifiableInteger pageNumber;
299         int checkCount = 0;
300         int maxCheckCount = MAX_CHECKS_FIRST_PAGE;
301 
302         pageNumber = new ModifiableInteger(0);
303         content = startNewPage(writer, reader, pageNumber);
304 
305         for (Check current : crDoc.getChecks()) {
306             writeCheckNumber(content, current);
307             writeCheckDate(content, current);
308             writeCheckDescription(content, current);
309             writeCheckAmount(content, current);
310             setCurrentRenderingYPosition(getCurrentRenderingYPosition() - CHECK_FIELD_HEIGHT);
311 
312             checkCount++;
313 
314             if (checkCount > maxCheckCount) {
315                 checkCount = 0;
316                 maxCheckCount = MAX_CHECKS_NORMAL;
317                 content = startNewPage(writer, reader, pageNumber);
318             }
319         }
320     }
321 
322     
323 
324 
325 
326 
327 
328 
329 
330 
331 
332 
333 
334     protected PdfContentByte startNewPage(PdfWriter writer, PdfReader reader, ModifiableInteger pageNumber) throws DocumentException, IOException {
335         PdfContentByte retval;
336         PdfContentByte under;
337         Rectangle pageSize;
338         Document pdfDoc;
339         PdfImportedPage newPage;
340 
341         pageNumber.increment();
342         pageSize = reader.getPageSize(FRONT_PAGE);
343         retval = writer.getDirectContent();
344         
345 
346         if (pageNumber.getInt() > FRONT_PAGE) {
347             newPage = writer.getImportedPage(reader, CHECK_PAGE_NORMAL);
348             setCurrentRenderingYPosition(pageSize.top(TOP_MARGIN + CHECK_DETAIL_HEADING_HEIGHT));
349         }
350         else {
351             newPage = writer.getImportedPage(reader, FRONT_PAGE);
352             setCurrentRenderingYPosition(pageSize.top(TOP_FIRST_PAGE));
353         }
354 
355         pdfDoc = retval.getPdfDocument();
356         pdfDoc.newPage();
357         retval.addTemplate(newPage, 0, 0);
358         retval.setFontAndSize(getTextFont(), 8);
359 
360         return retval;
361     }
362 
363     
364 
365 
366 
367     public DataDictionaryService getDataDictionaryService() {
368         return dataDictionaryService;
369     }
370 
371     
372 
373 
374 
375     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
376         this.dataDictionaryService = dataDictionaryService;
377     }
378 
379     
380 
381 
382 
383     public DocumentHelperService getDocumentHelperService() {
384         return documentHelperService;
385     }
386 
387     
388 
389 
390 
391     public void setDocumentHelperService(DocumentHelperService documentHelperService) {
392         this.documentHelperService = documentHelperService;
393     }
394 
395 }
396 
397 
398 
399 
400 
401 
402 
403 class ModifiableInteger {
404     int _value;
405 
406     
407 
408 
409 
410 
411     public ModifiableInteger(Integer val) {
412         this(val.intValue());
413     }
414 
415     
416 
417 
418 
419 
420     public ModifiableInteger(int val) {
421         setInt(val);
422     }
423 
424     
425 
426 
427 
428 
429     public void setInt(int val) {
430         _value = val;
431     }
432 
433     
434 
435 
436 
437 
438     public int getInt() {
439         return _value;
440     }
441 
442     
443 
444 
445 
446 
447     public ModifiableInteger increment() {
448         _value++;
449         return this;
450     }
451 
452     
453 
454 
455 
456 
457 
458     public ModifiableInteger increment(int inc) {
459         _value += inc;
460         return this;
461     }
462 
463     
464 
465 
466 
467 
468     public ModifiableInteger decrement() {
469         _value--;
470         return this;
471     }
472 
473     
474 
475 
476 
477 
478 
479     public ModifiableInteger decrement(int dec) {
480         _value -= dec;
481         return this;
482     }
483 
484     
485 
486 
487 
488 
489     public Integer getInteger() {
490         return new Integer(_value);
491     }
492 
493     
494 
495 
496 
497 
498 
499     @Override
500     public String toString() {
501         return getInteger().toString();
502     }
503 }