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 }