View Javadoc
1   /*
2    * Copyright 2007 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.fp.batch.service.impl;
17  
18  import java.sql.Timestamp;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.Date;
22  import java.util.HashSet;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Set;
26  
27  import org.apache.commons.lang.StringUtils;
28  import org.apache.commons.lang.WordUtils;
29  import org.kuali.ole.fp.batch.DvToPdpExtractStep;
30  import org.kuali.ole.fp.batch.service.DisbursementVoucherExtractService;
31  import org.kuali.ole.fp.businessobject.DisbursementVoucherPayeeDetail;
32  import org.kuali.ole.fp.dataaccess.DisbursementVoucherDao;
33  import org.kuali.ole.fp.document.DisbursementVoucherConstants;
34  import org.kuali.ole.fp.document.DisbursementVoucherDocument;
35  import org.kuali.ole.pdp.PdpConstants;
36  import org.kuali.ole.pdp.PdpParameterConstants;
37  import org.kuali.ole.pdp.businessobject.Batch;
38  import org.kuali.ole.pdp.businessobject.CustomerProfile;
39  import org.kuali.ole.pdp.businessobject.PaymentAccountDetail;
40  import org.kuali.ole.pdp.businessobject.PaymentDetail;
41  import org.kuali.ole.pdp.businessobject.PaymentGroup;
42  import org.kuali.ole.pdp.businessobject.PaymentNoteText;
43  import org.kuali.ole.pdp.service.CustomerProfileService;
44  import org.kuali.ole.pdp.service.PaymentFileService;
45  import org.kuali.ole.pdp.service.PaymentGroupService;
46  import org.kuali.ole.pdp.service.PdpEmailService;
47  import org.kuali.ole.select.document.OleDisbursementVoucherDocument;
48  import org.kuali.ole.select.document.service.OleSelectDocumentService;
49  import org.kuali.ole.sys.OLEConstants;
50  import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry;
51  import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
52  import org.kuali.ole.sys.businessobject.SourceAccountingLine;
53  import org.kuali.ole.sys.context.SpringContext;
54  import org.kuali.ole.sys.document.service.FinancialSystemDocumentService;
55  import org.kuali.ole.sys.document.validation.event.AccountingDocumentSaveWithNoLedgerEntryGenerationEvent;
56  import org.kuali.ole.sys.service.GeneralLedgerPendingEntryService;
57  import org.kuali.ole.sys.service.impl.OleParameterConstants;
58  import org.kuali.ole.vnd.businessobject.VendorDetail;
59  import org.kuali.ole.vnd.document.service.VendorService;
60  import org.kuali.rice.core.api.datetime.DateTimeService;
61  import org.kuali.rice.core.api.parameter.ParameterEvaluator;
62  import org.kuali.rice.core.api.parameter.ParameterEvaluatorService;
63  import org.kuali.rice.core.api.util.type.KualiDecimal;
64  import org.kuali.rice.core.api.util.type.KualiInteger;
65  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
66  import org.kuali.rice.kew.api.exception.WorkflowException;
67  import org.kuali.rice.kim.api.identity.Person;
68  import org.kuali.rice.kim.api.identity.PersonService;
69  import org.kuali.rice.krad.service.BusinessObjectService;
70  import org.kuali.rice.krad.service.DocumentService;
71  import org.kuali.rice.krad.util.ObjectUtils;
72  import org.springframework.transaction.annotation.Transactional;
73  
74  /**
75   * This is the default implementation of the DisbursementVoucherExtractService interface.
76   */
77  @Transactional
78  public class DisbursementVoucherExtractServiceImpl implements DisbursementVoucherExtractService {
79      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DisbursementVoucherExtractServiceImpl.class);
80  
81      private PersonService personService;
82      private ParameterService parameterService;
83      private DisbursementVoucherDao disbursementVoucherDao;
84      private DateTimeService dateTimeService;
85      private CustomerProfileService customerProfileService;
86      private PaymentFileService paymentFileService;
87      private PaymentGroupService paymentGroupService;
88      private BusinessObjectService businessObjectService;
89      private PdpEmailService paymentFileEmailService;
90      private int maxNoteLines;
91      private OleSelectDocumentService oleSelectDocumentService;
92  
93      // This should only be set to true when testing this system. Setting this to true will run the code but
94      // won't set the doc status to extracted
95      boolean testMode = false;
96  
97      /**
98       * This method extracts all payments from a disbursement voucher with a status code of "A" and uploads them as a batch for
99       * processing.
100      *
101      * @return Always returns true if the method completes.
102      * @see org.kuali.ole.fp.batch.service.DisbursementVoucherExtractService#extractPayments()
103      */
104     @Override
105     public boolean extractPayments() {
106         LOG.debug("extractPayments() started");
107 
108         Date processRunDate = dateTimeService.getCurrentDate();
109 
110         String noteLines = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.MAX_NOTE_LINES);
111 
112         try {
113             maxNoteLines = Integer.parseInt(noteLines);
114         }
115         catch (NumberFormatException nfe) {
116             throw new IllegalArgumentException("Invalid Max Notes Lines parameter");
117         }
118 
119         Person uuser = getPersonService().getPersonByPrincipalName(getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER));
120         if (uuser == null) {
121             if (LOG.isDebugEnabled()) {
122                 LOG.debug("extractPayments() Unable to find user " + getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER));
123             }
124             throw new IllegalArgumentException("Unable to find user " + getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER));
125         }
126 
127         // Get a list of campuses that have documents with an 'A' (approved) status.
128         Set<String> campusList = getCampusListByDocumentStatusCode(DisbursementVoucherConstants.DocumentStatusCodes.APPROVED);
129 
130         // Process each campus one at a time
131         for (String campusCode : campusList) {
132             extractPaymentsForCampus(campusCode, uuser, processRunDate);
133         }
134 
135         return true;
136     }
137 
138     /**
139      * Pulls all disbursement vouchers with status of "A" and marked for immediate payment from the database and builds payment records for them
140      * @see org.kuali.ole.fp.batch.service.DisbursementVoucherExtractService#extractImmediatePayments()
141      */
142     @Override
143     public void extractImmediatePayments() {
144         LOG.debug("extractImmediatePayments() started");
145 
146         Date processRunDate = dateTimeService.getCurrentDate();
147 
148         String noteLines = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.MAX_NOTE_LINES);
149 
150         try {
151             maxNoteLines = Integer.parseInt(noteLines);
152         }
153         catch (NumberFormatException nfe) {
154             throw new IllegalArgumentException("Invalid Max Notes Lines parameter");
155         }
156 
157         Person uuser = getPersonService().getPersonByPrincipalName(getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER));
158         if (uuser == null) {
159             LOG.debug("extractPayments() Unable to find user " + getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER));
160             throw new IllegalArgumentException("Unable to find user " + getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER));
161         }
162 
163         // Get a list of campuses that have documents with an 'A' (approved) status.
164         Set<String> campusList = getImmediatesCampusListByDocumentStatusCode(DisbursementVoucherConstants.DocumentStatusCodes.APPROVED);
165 
166         // Process each campus one at a time
167         for (String campusCode : campusList) {
168             extractImmediatePaymentsForCampus(campusCode, uuser, processRunDate);
169         }
170     }
171 
172     /**
173      * This method extracts all outstanding payments from all the disbursement vouchers in approved status for a given campus and
174      * adds these payments to a batch file that is uploaded for processing.
175      *
176      * @param campusCode The id code of the campus the payments will be retrieved for.
177      * @param user The user object used when creating the batch file to upload with outstanding payments.
178      * @param processRunDate This is the date that the batch file is created, often this value will be today's date.
179      */
180     protected void extractPaymentsForCampus(String campusCode, Person user, Date processRunDate) {
181         if (LOG.isDebugEnabled()) {
182             LOG.debug("extractPaymentsForCampus() started for campus: " + campusCode);
183         }
184 
185         Batch batch = createBatch(campusCode, user, processRunDate);
186         Integer count = 0;
187         KualiDecimal totalAmount = KualiDecimal.ZERO;
188 
189         Collection<DisbursementVoucherDocument> dvd = getListByDocumentStatusCodeCampus(DisbursementVoucherConstants.DocumentStatusCodes.APPROVED, campusCode, false);
190         for (DisbursementVoucherDocument document : dvd) {
191             addPayment(document, batch, processRunDate, false);
192             count++;
193             totalAmount = totalAmount.add(document.getDisbVchrCheckTotalAmount());
194         }
195 
196         batch.setPaymentCount(new KualiInteger(count));
197         batch.setPaymentTotalAmount(totalAmount);
198 
199         businessObjectService.save(batch);
200         paymentFileEmailService.sendLoadEmail(batch);
201     }
202 
203     /**
204      * Builds payment batch for Disbursement Vouchers marked as immediate
205      * @param campusCode the campus code the disbursement vouchers should be associated with
206      * @param user the user responsible building the payment batch (typically the System User, kfs)
207      * @param processRunDate the time that the job to build immediate payments is run
208      */
209     protected void extractImmediatePaymentsForCampus(String campusCode, Person user, Date processRunDate) {
210         LOG.debug("extractImmediatesPaymentsForCampus() started for campus: " + campusCode);
211 
212         Batch batch = createBatch(campusCode, user, processRunDate);
213         Integer count = 0;
214         KualiDecimal totalAmount = KualiDecimal.ZERO;
215 
216         Collection<DisbursementVoucherDocument> dvd = getListByDocumentStatusCodeCampus(DisbursementVoucherConstants.DocumentStatusCodes.APPROVED, campusCode, true);
217         for (DisbursementVoucherDocument document : dvd) {
218             addPayment(document, batch, processRunDate, false);
219             count++;
220             totalAmount = totalAmount.add(document.getDisbVchrCheckTotalAmount());
221         }
222 
223         batch.setPaymentCount(new KualiInteger(count));
224         batch.setPaymentTotalAmount(totalAmount);
225 
226         businessObjectService.save(batch);
227         paymentFileEmailService.sendLoadEmail(batch);
228     }
229 
230     /**
231      * This method creates a payment group from the disbursement voucher and batch provided and persists that group to the database.
232      *
233      * @param document The document used to build a payment group detail.
234      * @param batch The batch file used to build a payment group and detail.
235      * @param processRunDate The date the batch file is to post.
236      */
237     protected void addPayment(DisbursementVoucherDocument document, Batch batch, Date processRunDate, boolean immediate) {
238         LOG.debug("addPayment() started");
239 
240         PaymentGroup pg = buildPaymentGroup(document, batch);
241         if (immediate) {
242             pg.setProcessImmediate(Boolean.TRUE);
243         }
244         PaymentDetail pd = buildPaymentDetail(document, batch, processRunDate);
245 
246         pd.setPaymentGroup(pg);
247         pg.addPaymentDetails(pd);
248         this.businessObjectService.save(pg);
249 
250         if (!testMode) {
251             try {
252                 document.getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(DisbursementVoucherConstants.DocumentStatusCodes.EXTRACTED);
253                 document.setExtractDate(new java.sql.Date(processRunDate.getTime()));
254                 SpringContext.getBean(DocumentService.class).saveDocument(document, AccountingDocumentSaveWithNoLedgerEntryGenerationEvent.class);
255             }
256             catch (WorkflowException we) {
257                 LOG.error("Could not save disbursement voucher document #" + document.getDocumentNumber() + ": " + we);
258                 throw new RuntimeException(we);
259             }
260         }
261     }
262 
263     /**
264      * This method creates a PaymentGroup from the disbursement voucher and batch provided. The values provided by the disbursement
265      * voucher are used to assign appropriate attributes to the payment group, including address and vendor detail information. The
266      * information added to the payment group includes tax encoding to identify if taxes should be taken out of the payment. The tax
267      * rules vary depending on the type of individual or entity being paid
268      *
269      * @param document The document to be used for retrieving the information about the vendor being paid.
270      * @param batch The batch that the payment group will be associated with.
271      * @return A PaymentGroup object fully populated with all the values necessary to make a payment.
272      */
273     protected PaymentGroup buildPaymentGroup(DisbursementVoucherDocument document, Batch batch) {
274         LOG.debug("buildPaymentGroup() started");
275 
276         PaymentGroup pg = new PaymentGroup();
277         pg.setBatch(batch);
278         pg.setCombineGroups(Boolean.TRUE);
279         pg.setCampusAddress(Boolean.FALSE);
280 
281         DisbursementVoucherPayeeDetail pd = document.getDvPayeeDetail();
282         String rc = pd.getDisbVchrPaymentReasonCode();
283 
284         // If the payee is an employee, set these flags accordingly
285         if ((document.getDvPayeeDetail().isVendor() && SpringContext.getBean(VendorService.class).isVendorInstitutionEmployee(pd.getDisbVchrVendorHeaderIdNumberAsInteger())) || document.getDvPayeeDetail().isEmployee()) {
286             pg.setEmployeeIndicator(Boolean.TRUE);
287             pg.setPayeeIdTypeCd(PdpConstants.PayeeIdTypeCodes.EMPLOYEE);
288             //Commented for the jira issue OLE-3415
289 //            pg.setTaxablePayment(
290 //                    !/*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(DisbursementVoucherDocument.class, DisbursementVoucherConstants.RESEARCH_PAYMENT_REASONS_PARM_NM, rc).evaluationSucceeds()
291 //                        && !parameterService.getParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.PAYMENT_REASON_CODE_RENTAL_PAYMENT_PARM_NM).equals(rc)
292 //                        && !parameterService.getParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.PAYMENT_REASON_CODE_ROYALTIES_PARM_NM).equals(rc));
293         }
294         // Payee is not an employee
295         else {
296 
297             // These are taxable
298             VendorDetail vendDetail = SpringContext.getBean(VendorService.class).getVendorDetail(pd.getDisbVchrVendorHeaderIdNumberAsInteger(), pd.getDisbVchrVendorDetailAssignedIdNumberAsInteger());
299             String vendorOwnerCode = vendDetail.getVendorHeader().getVendorOwnershipCode();
300             String vendorOwnerCategoryCode = vendDetail.getVendorHeader().getVendorOwnershipCategoryCode();
301             String payReasonCode = pd.getDisbVchrPaymentReasonCode();
302 
303             pg.setPayeeIdTypeCd(PdpConstants.PayeeIdTypeCodes.VENDOR_ID);
304 
305             // Assume it is not taxable until proven otherwise
306             pg.setTaxablePayment(Boolean.FALSE);
307             pg.setPayeeOwnerCd(vendorOwnerCode);
308 
309             ParameterEvaluator parameterEvaluator1 = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(DvToPdpExtractStep.class, PdpParameterConstants.TAXABLE_PAYMENT_REASON_CODES_BY_OWNERSHIP_CODES_PARAMETER_NAME, PdpParameterConstants.NON_TAXABLE_PAYMENT_REASON_CODES_BY_OWNERSHIP_CODES_PARAMETER_NAME, vendorOwnerCode, payReasonCode);
310             ParameterEvaluator parameterEvaluator2 = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(DvToPdpExtractStep.class, PdpParameterConstants.TAXABLE_PAYMENT_REASON_CODES_BY_CORPORATION_OWNERSHIP_TYPE_CATEGORY_PARAMETER_NAME, PdpParameterConstants.NON_TAXABLE_PAYMENT_REASON_CODES_BY_CORPORATION_OWNERSHIP_TYPE_CATEGORY_PARAMETER_NAME, vendorOwnerCategoryCode, payReasonCode);
311 
312             if ( parameterEvaluator1.evaluationSucceeds() ) {
313                 pg.setTaxablePayment(Boolean.TRUE);
314             }
315             else if (this.parameterService.getParameterValueAsString(DvToPdpExtractStep.class, PdpParameterConstants.CORPORATION_OWNERSHIP_TYPE_PARAMETER_NAME).equals("CP") &&
316                       StringUtils.isEmpty(vendorOwnerCategoryCode) &&
317                       /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(DvToPdpExtractStep.class, PdpParameterConstants.TAXABLE_PAYMENT_REASON_CODES_FOR_BLANK_CORPORATION_OWNERSHIP_TYPE_CATEGORIES_PARAMETER_NAME, payReasonCode).evaluationSucceeds()) {
318                 pg.setTaxablePayment(Boolean.TRUE);
319             }
320             else if (this.parameterService.getParameterValueAsString(DvToPdpExtractStep.class, PdpParameterConstants.CORPORATION_OWNERSHIP_TYPE_PARAMETER_NAME).equals("CP")
321                         && !StringUtils.isEmpty(vendorOwnerCategoryCode)
322                         && parameterEvaluator2.evaluationSucceeds() ) {
323                 pg.setTaxablePayment(Boolean.TRUE);
324             }
325         }
326 
327         pg.setCity(pd.getDisbVchrPayeeCityName());
328         pg.setCountry(pd.getDisbVchrPayeeCountryCode());
329         pg.setLine1Address(pd.getDisbVchrPayeeLine1Addr());
330         pg.setLine2Address(pd.getDisbVchrPayeeLine2Addr());
331         pg.setPayeeName(pd.getDisbVchrPayeePersonName());
332         pg.setPayeeId(pd.getDisbVchrPayeeIdNumber());
333         pg.setState(pd.getDisbVchrPayeeStateCode());
334         pg.setZipCd(pd.getDisbVchrPayeeZipCode());
335         pg.setPaymentDate(document.getDisbursementVoucherDueDate());
336 
337         // It doesn't look like the DV has a way to do immediate processes
338         pg.setProcessImmediate(Boolean.FALSE);
339         pg.setPymtAttachment(document.isDisbVchrAttachmentCode());
340         pg.setPymtSpecialHandling(document.isDisbVchrSpecialHandlingCode());
341         pg.setNraPayment(pd.isDisbVchrAlienPaymentCode());
342 
343         pg.setBankCode(document.getDisbVchrBankCode());
344         pg.setPaymentStatusCode(OLEConstants.PdpConstants.PAYMENT_OPEN_STATUS_CODE);
345 
346         return pg;
347     }
348 
349     /**
350      * This method builds a payment detail object from the disbursement voucher document provided and links that detail file to the
351      * batch and process run date given.
352      *
353      * @param document The disbursement voucher document to retrieve payment information from to populate the PaymentDetail.
354      * @param batch The batch file associated with the payment.
355      * @param processRunDate The date of the payment detail invoice.
356      * @return A fully populated PaymentDetail instance.
357      */
358     protected PaymentDetail buildPaymentDetail(DisbursementVoucherDocument document, Batch batch, Date processRunDate) {
359         LOG.debug("buildPaymentDetail() started");
360 
361         PaymentDetail pd = new PaymentDetail();
362         if (StringUtils.isNotEmpty(document.getDocumentHeader().getOrganizationDocumentNumber())) {
363             pd.setOrganizationDocNbr(document.getDocumentHeader().getOrganizationDocumentNumber());
364         }
365         if(((OleDisbursementVoucherDocument) document).getInvoiceNumber() != null) {
366             pd.setInvoiceNbr(((OleDisbursementVoucherDocument) document).getInvoiceNumber());
367         }
368         pd.setCustPaymentDocNbr(document.getDocumentNumber());
369         pd.setInvoiceDate(new java.sql.Date(processRunDate.getTime()));
370         pd.setOrigInvoiceAmount(document.getDisbVchrCheckTotalAmount());
371         pd.setInvTotDiscountAmount(KualiDecimal.ZERO);
372         pd.setInvTotOtherCreditAmount(KualiDecimal.ZERO);
373         pd.setInvTotOtherDebitAmount(KualiDecimal.ZERO);
374         pd.setInvTotShipAmount(KualiDecimal.ZERO);
375         pd.setNetPaymentAmount(document.getDisbVchrCheckTotalAmount());
376         pd.setPrimaryCancelledPayment(Boolean.FALSE);
377         pd.setFinancialDocumentTypeCode(DisbursementVoucherConstants.DOCUMENT_TYPE_CHECKACH);
378         pd.setFinancialSystemOriginCode(OLEConstants.ORIGIN_CODE_KUALI);
379 
380         if(document.getDisbVchrPaymentMethodCode().equalsIgnoreCase(DisbursementVoucherConstants.PAYMENT_METHOD_CHECK)) {
381             pd.setPaymentMethodCode("Check");
382         }
383         else if(document.getDisbVchrPaymentMethodCode().equalsIgnoreCase(DisbursementVoucherConstants.PAYMENT_METHOD_WIRE)) {
384             pd.setPaymentMethodCode("Wire");
385         }
386         else if(document.getDisbVchrPaymentMethodCode().equalsIgnoreCase(DisbursementVoucherConstants.PAYMENT_METHOD_DRAFT)) {
387             pd.setPaymentMethodCode("Draft");
388         }
389 
390         // Handle accounts
391         for (Iterator iter = document.getSourceAccountingLines().iterator(); iter.hasNext();) {
392             SourceAccountingLine sal = (SourceAccountingLine) iter.next();
393 
394             PaymentAccountDetail pad = new PaymentAccountDetail();
395             pad.setFinChartCode(sal.getChartOfAccountsCode());
396             pad.setAccountNbr(sal.getAccountNumber());
397             if (StringUtils.isNotEmpty(sal.getSubAccountNumber())) {
398                 pad.setSubAccountNbr(sal.getSubAccountNumber());
399             }
400             else {
401                 pad.setSubAccountNbr(OLEConstants.getDashSubAccountNumber());
402             }
403             pad.setFinObjectCode(sal.getFinancialObjectCode());
404             if (StringUtils.isNotEmpty(sal.getFinancialSubObjectCode())) {
405                 pad.setFinSubObjectCode(sal.getFinancialSubObjectCode());
406             }
407             else {
408                 pad.setFinSubObjectCode(OLEConstants.getDashFinancialSubObjectCode());
409             }
410             if (StringUtils.isNotEmpty(sal.getOrganizationReferenceId())) {
411                 pad.setOrgReferenceId(sal.getOrganizationReferenceId());
412             }
413             if (StringUtils.isNotEmpty(sal.getProjectCode())) {
414                 pad.setProjectCode(sal.getProjectCode());
415             }
416             else {
417                 pad.setProjectCode(OLEConstants.getDashProjectCode());
418             }
419             pad.setAccountNetAmount(sal.getAmount());
420             pd.addAccountDetail(pad);
421         }
422 
423         // Handle notes
424         DisbursementVoucherPayeeDetail dvpd = document.getDvPayeeDetail();
425 
426         int line = 0;
427         PaymentNoteText pnt = new PaymentNoteText();
428         pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
429         pnt.setCustomerNoteText("Info: " + document.getDisbVchrContactPersonName() + " " + document.getDisbVchrContactPhoneNumber());
430         pd.addNote(pnt);
431 
432         String dvSpecialHandlingPersonName = null;
433         String dvSpecialHandlingLine1Address = null;
434         String dvSpecialHandlingLine2Address = null;
435         String dvSpecialHandlingCity = null;
436         String dvSpecialHandlingState = null;
437         String dvSpecialHandlingZip = null;
438 
439         dvSpecialHandlingPersonName = dvpd.getDisbVchrSpecialHandlingPersonName();
440         dvSpecialHandlingLine1Address = dvpd.getDisbVchrSpecialHandlingLine1Addr();
441         dvSpecialHandlingLine2Address = dvpd.getDisbVchrSpecialHandlingLine2Addr();
442         dvSpecialHandlingCity = dvpd.getDisbVchrSpecialHandlingCityName();
443         dvSpecialHandlingState = dvpd.getDisbVchrSpecialHandlingStateCode();
444         dvSpecialHandlingZip = dvpd.getDisbVchrSpecialHandlingZipCode();
445 
446         if (StringUtils.isNotEmpty(dvSpecialHandlingPersonName)) {
447             pnt = new PaymentNoteText();
448             pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
449             pnt.setCustomerNoteText("Send Check To: " + dvSpecialHandlingPersonName);
450             if (LOG.isDebugEnabled()) {
451                 LOG.debug("Creating special handling person name note: "+pnt.getCustomerNoteText());
452             }
453             pd.addNote(pnt);
454         }
455         if (StringUtils.isNotEmpty(dvSpecialHandlingLine1Address)) {
456             pnt = new PaymentNoteText();
457             pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
458             pnt.setCustomerNoteText(dvSpecialHandlingLine1Address);
459             if (LOG.isDebugEnabled()) {
460                 LOG.debug("Creating special handling address 1 note: "+pnt.getCustomerNoteText());
461             }
462             pd.addNote(pnt);
463         }
464         if (StringUtils.isNotEmpty(dvSpecialHandlingLine2Address)) {
465             pnt = new PaymentNoteText();
466             pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
467             pnt.setCustomerNoteText(dvSpecialHandlingLine2Address);
468             if (LOG.isDebugEnabled()) {
469                 LOG.debug("Creating special handling address 2 note: "+pnt.getCustomerNoteText());
470             }
471             pd.addNote(pnt);
472         }
473         if (StringUtils.isNotEmpty(dvSpecialHandlingCity)) {
474             pnt = new PaymentNoteText();
475             pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
476             pnt.setCustomerNoteText(dvSpecialHandlingCity + ", " + dvSpecialHandlingState + " " + dvSpecialHandlingZip);
477             if (LOG.isDebugEnabled()) {
478                 LOG.debug("Creating special handling city note: "+pnt.getCustomerNoteText());
479             }
480             pd.addNote(pnt);
481         }
482         if (document.isDisbVchrAttachmentCode()) {
483             pnt = new PaymentNoteText();
484             pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
485             pnt.setCustomerNoteText("Attachment Included");
486             if (LOG.isDebugEnabled()) {
487                 LOG.debug("create attachment note: "+pnt.getCustomerNoteText());
488             }
489             pd.addNote(pnt);
490         }
491 
492         String paymentReasonCode = dvpd.getDisbVchrPaymentReasonCode();
493         //Commented for the jira issue OLE-3415
494         /*if (SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(DisbursementVoucherDocument.class, DisbursementVoucherConstants.NONEMPLOYEE_TRAVEL_PAY_REASONS_PARM_NM, paymentReasonCode).evaluationSucceeds()) {
495             DisbursementVoucherNonEmployeeTravel dvnet = document.getDvNonEmployeeTravel();
496 
497             pnt = new PaymentNoteText();
498             pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
499             pnt.setCustomerNoteText("Reimbursement associated with " + dvnet.getDisbVchrServicePerformedDesc());
500             if (LOG.isDebugEnabled()) {
501                 LOG.debug("Creating non employee travel notes: "+pnt.getCustomerNoteText());
502             }
503             pd.addNote(pnt);
504 
505             pnt = new PaymentNoteText();
506             pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
507             pnt.setCustomerNoteText("The total per diem amount for your daily expenses is " + dvnet.getDisbVchrPerdiemCalculatedAmt());
508             if (LOG.isDebugEnabled()) {
509                 LOG.debug("Creating non employee travel notes: "+pnt.getCustomerNoteText());
510             }
511             pd.addNote(pnt);
512 
513             if (dvnet.getDisbVchrPersonalCarAmount() != null && dvnet.getDisbVchrPersonalCarAmount().compareTo(KualiDecimal.ZERO) != 0) {
514                 pnt = new PaymentNoteText();
515                 pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
516                 pnt.setCustomerNoteText("The total dollar amount for your vehicle mileage is " + dvnet.getDisbVchrPersonalCarAmount());
517                 if (LOG.isDebugEnabled()) {
518                     LOG.debug("Creating non employee travel vehicle note: "+pnt.getCustomerNoteText());
519                 }
520                 pd.addNote(pnt);
521 
522                 for (Iterator iter = dvnet.getDvNonEmployeeExpenses().iterator(); iter.hasNext();) {
523                     DisbursementVoucherNonEmployeeExpense exp = (DisbursementVoucherNonEmployeeExpense) iter.next();
524 
525                     if (line < (maxNoteLines - 8)) {
526                         pnt = new PaymentNoteText();
527                         pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
528                         pnt.setCustomerNoteText(exp.getDisbVchrExpenseCompanyName() + " " + exp.getDisbVchrExpenseAmount());
529                         if (LOG.isDebugEnabled()) {
530                             LOG.debug("Creating non employee travel expense note: "+pnt.getCustomerNoteText());
531                         }
532                         pd.addNote(pnt);
533                     }
534                 }
535             }
536         }
537          else if (SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(DisbursementVoucherDocument.class, DisbursementVoucherConstants.PREPAID_TRAVEL_PAYMENT_REASONS_PARM_NM, paymentReasonCode).evaluationSucceeds()) {
538             pnt = new PaymentNoteText();
539             pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
540             pnt.setCustomerNoteText("Payment is for the following individuals/charges:");
541             pd.addNote(pnt);
542             if (LOG.isDebugEnabled()) {
543                 LOG.info("Creating prepaid travel note note: "+pnt.getCustomerNoteText());
544             }
545 
546             DisbursementVoucherPreConferenceDetail dvpcd = document.getDvPreConferenceDetail();
547 
548             for (Iterator iter = dvpcd.getDvPreConferenceRegistrants().iterator(); iter.hasNext();) {
549                 DisbursementVoucherPreConferenceRegistrant dvpcr = (DisbursementVoucherPreConferenceRegistrant) iter.next();
550 
551                 if (line < (maxNoteLines - 8)) {
552                     pnt = new PaymentNoteText();
553                     pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
554                     pnt.setCustomerNoteText(dvpcr.getDvConferenceRegistrantName() + " " + dvpcr.getDisbVchrExpenseAmount());
555                     if (LOG.isDebugEnabled()) {
556                         LOG.debug("Creating pre-paid conference registrants note: "+pnt.getCustomerNoteText());
557                     }
558                     pd.addNote(pnt);
559                 }
560             }
561         }*/
562 
563         // Get the original, raw form, note text from the DV document.
564         String text = document.getDisbVchrCheckStubText();
565         if (text != null && text.length() > 0) {
566 
567             // The WordUtils should be sufficient for the majority of cases.  This method will
568             // word wrap the whole string based on the MAX_NOTE_LINE_SIZE, separating each wrapped
569             // word by a newline character.  The 'wrap' method adds line feeds to the end causing
570             // the character length to exceed the max length by 1, hence the need for the replace
571             // method before splitting.
572             String   wrappedText = WordUtils.wrap(text, DisbursementVoucherConstants.MAX_NOTE_LINE_SIZE);
573             String[] noteLines   = wrappedText.replaceAll("[\r]", "").split("\\n");
574 
575             // Loop through all the note lines.
576             for (String noteLine : noteLines) {
577                 if (line < (maxNoteLines - 3) && !StringUtils.isEmpty(noteLine)) {
578 
579                     // This should only happen if we encounter a word that is greater than the max length.
580                     // The only concern I have for this occurring is with URLs/email addresses.
581                     if (noteLine.length() > DisbursementVoucherConstants.MAX_NOTE_LINE_SIZE) {
582                         for (String choppedWord : chopWord(noteLine, DisbursementVoucherConstants.MAX_NOTE_LINE_SIZE)) {
583 
584                             // Make sure we're still under the maximum number of note lines.
585                             if (line < (maxNoteLines - 3) && !StringUtils.isEmpty(choppedWord)) {
586                                 pnt = new PaymentNoteText();
587                                 pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
588                                 pnt.setCustomerNoteText(choppedWord.replaceAll("\\n", "").trim());
589                             }
590                             // We can't add any additional note lines, or we'll exceed the maximum, therefore
591                             // just break out of the loop early - there's nothing left to do.
592                             else {
593                                 break;
594                             }
595                         }
596                     }
597                     // This should be the most common case.  Simply create a new PaymentNoteText,
598                     // add the line at the correct line location.
599                     else {
600                         pnt = new PaymentNoteText();
601                         pnt.setCustomerNoteLineNbr(new KualiInteger(line++));
602                         pnt.setCustomerNoteText(noteLine.replaceAll("\\n", "").trim());
603                     }
604 
605                     // Logging...
606                     if (LOG.isDebugEnabled()) {
607                         LOG.debug("Creating check stub text note: " + pnt.getCustomerNoteText());
608                     }
609                     pd.addNote(pnt);
610                 }
611             }
612         }
613 
614         return pd;
615     }
616 
617     /**
618      * This method will take a word and simply chop into smaller
619      * text segments that satisfy the limit requirements.  All words
620      * brute force chopped, with no regard to preserving whole words.
621      *
622      * For example:
623      *
624      *      "Java is a fun programming language!"
625      *
626      * Might be chopped into:
627      *
628      *      "Java is a fun prog"
629      *      "ramming language!"
630      *
631      * @param word The word that needs chopping
632      * @param limit Number of character that should represent a chopped word
633      * @return String [] of chopped words
634      */
635     private String [] chopWord(String word, int limit)
636     {
637         StringBuilder builder = new StringBuilder();
638         if (word != null && word.trim().length() > 0) {
639 
640             char[] chars = word.toCharArray();
641             int index = 0;
642 
643             // First process all the words that fit into the limit.
644             for (int i = 0; i < chars.length/limit; i++) {
645                 builder.append(String.copyValueOf(chars, index, limit));
646                 builder.append("\n");
647 
648                 index += limit;
649             }
650 
651             // Not all words will fit perfectly into the limit amount, so
652             // calculate the modulus value to determine any remaining characters.
653             int modValue =  chars.length%limit;
654             if (modValue > 0) {
655                 builder.append(String.copyValueOf(chars, index, modValue));
656             }
657 
658         }
659 
660         // Split the chopped words into individual segments.
661         return builder.toString().split("\\n");
662     }
663 
664     /**
665      * This method creates a Batch instance and populates it with the information provided.
666      *
667      * @param campusCode The campus code used to retrieve a customer profile to be set on the batch.
668      * @param user The user who submitted the batch.
669      * @param processRunDate The date the batch was submitted and the date the customer profile was generated.
670      * @return A fully populated batch instance.
671      */
672     protected Batch createBatch(String campusCode, Person user, Date processRunDate) {
673         String orgCode = parameterService.getParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.DvPdpExtractGroup.DV_PDP_ORG_CODE);
674         String subUnitCode = parameterService.getParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.DvPdpExtractGroup.DV_PDP_SBUNT_CODE);
675         CustomerProfile customer = customerProfileService.get(campusCode, orgCode, subUnitCode);
676         if (customer == null) {
677             throw new IllegalArgumentException("Unable to find customer profile for " + campusCode + "/" + orgCode + "/" + subUnitCode);
678         }
679 
680         // Create the group for this campus
681         Batch batch = new Batch();
682         batch.setCustomerProfile(customer);
683         batch.setCustomerFileCreateTimestamp(new Timestamp(processRunDate.getTime()));
684         batch.setFileProcessTimestamp(new Timestamp(processRunDate.getTime()));
685         batch.setPaymentFileName(OLEConstants.DISBURSEMENT_VOUCHER_PDP_EXTRACT_FILE_NAME);
686         batch.setSubmiterUserId(user.getPrincipalId());
687 
688         // Set these for now, we will update them later
689         batch.setPaymentCount(KualiInteger.ZERO);
690         batch.setPaymentTotalAmount(KualiDecimal.ZERO);
691 
692         businessObjectService.save(batch);
693 
694         return batch;
695     }
696 
697     /**
698      * This method retrieves a collection of campus instances representing all the campuses which currently have disbursement
699      * vouchers with the status code provided.
700      *
701      * @param statusCode The status code to retrieve disbursement vouchers by.
702      * @return A collection of campus codes of all the campuses with disbursement vouchers in the status given.
703      */
704     protected Set<String> getCampusListByDocumentStatusCode(String statusCode) {
705         LOG.debug("getCampusListByDocumentStatusCode() started");
706 
707         Set<String> campusSet = new HashSet<String>();
708 
709         Collection<DisbursementVoucherDocument> docs = disbursementVoucherDao.getDocumentsByHeaderStatus(statusCode, false);
710         for (DisbursementVoucherDocument element : docs) {
711             String dvdCampusCode = element.getCampusCode();
712             campusSet.add(dvdCampusCode);
713         }
714 
715         return campusSet;
716     }
717 
718     /**
719      * Retrieves a list of campuses which have Disbursement Vouchers ready to be process which are marked for immediate processing
720      * @param statusCode the status code of the documents to retrieve
721      * @return the Set of campuses which have DV which are up for immediate disbursement
722      */
723     protected Set<String> getImmediatesCampusListByDocumentStatusCode(String statusCode) {
724         LOG.debug("getCampusListByDocumentStatusCode() started");
725 
726         Set<String> campusSet = new HashSet<String>();
727 
728         Collection<DisbursementVoucherDocument> docs = disbursementVoucherDao.getDocumentsByHeaderStatus(statusCode, true);
729         for (DisbursementVoucherDocument element : docs) {
730 
731             final String dvdCampusCode = element.getCampusCode();
732             campusSet.add(dvdCampusCode);
733         }
734 
735         return campusSet;
736     }
737 
738     /**
739      * This method retrieves a list of disbursement voucher documents that are in the status provided for the campus code given.
740      *
741      * @param statusCode The status of the disbursement vouchers to be retrieved.
742      * @param campusCode The campus code that the disbursement vouchers will be associated with.
743      * @param immediatesOnly only retrieve Disbursement Vouchers marked for immediate payment
744      * @return A collection of disbursement voucher objects that meet the search criteria given.
745      */
746     protected Collection<DisbursementVoucherDocument> getListByDocumentStatusCodeCampus(String statusCode, String campusCode, boolean immediatesOnly) {
747         LOG.debug("getListByDocumentStatusCodeCampus() started");
748 
749         Collection<DisbursementVoucherDocument> list = new ArrayList<DisbursementVoucherDocument>();
750 
751         try {
752             Collection<DisbursementVoucherDocument> docs = SpringContext.getBean(FinancialSystemDocumentService.class).findByDocumentHeaderStatusCode(DisbursementVoucherDocument.class, statusCode);
753             for (DisbursementVoucherDocument element : docs) {
754                 String dvdCampusCode = element.getCampusCode();
755 
756                 if (dvdCampusCode.equals(campusCode) && DisbursementVoucherConstants.PAYMENT_METHOD_CHECK.equals(element.getDisbVchrPaymentMethodCode())) {
757                     if ((immediatesOnly && element.isImmediatePaymentIndicator()) || !immediatesOnly) {
758                     list.add(element);
759                 }
760             }
761         }
762         }
763         catch (WorkflowException we) {
764             LOG.error("Could not load Disbursement Voucher Documents with status code = " + statusCode + ": " + we);
765             throw new RuntimeException(we);
766         }
767 
768         return list;
769     }
770 
771     /**
772      * This cancels the disbursement voucher
773      *
774      * @param dv the disbursement voucher document to cancel
775      * @param processDate the date of the cancelation
776      * @see org.kuali.ole.fp.batch.service.DisbursementVoucherExtractService#cancelExtractedDisbursementVoucher(org.kuali.ole.fp.document.DisbursementVoucherDocument, java.sql.Date)
777      */
778     @Override
779     public void cancelExtractedDisbursementVoucher(DisbursementVoucherDocument dv, java.sql.Date processDate) {
780         if (dv.getCancelDate() == null) {
781             try {
782                 BusinessObjectService boService = SpringContext.getBean(BusinessObjectService.class);
783                 // set the canceled date
784                 dv.setCancelDate(processDate);
785                 dv.refreshReferenceObject("generalLedgerPendingEntries");
786                 if (ObjectUtils.isNull(dv.getGeneralLedgerPendingEntries()) || dv.getGeneralLedgerPendingEntries().size() == 0) {
787                     // generate all the pending entries for the document
788                     SpringContext.getBean(GeneralLedgerPendingEntryService.class).generateGeneralLedgerPendingEntries(dv);
789                     // for each pending entry, opposite-ify it and reattach it to the document
790                     GeneralLedgerPendingEntrySequenceHelper glpeSeqHelper = new GeneralLedgerPendingEntrySequenceHelper();
791                     for (GeneralLedgerPendingEntry glpe : dv.getGeneralLedgerPendingEntries()) {
792                         oppositifyEntry(glpe, boService, glpeSeqHelper);
793                     }
794                 }
795                 else {
796                     List<GeneralLedgerPendingEntry> newGLPEs = new ArrayList<GeneralLedgerPendingEntry>();
797                     GeneralLedgerPendingEntrySequenceHelper glpeSeqHelper = new GeneralLedgerPendingEntrySequenceHelper(dv.getGeneralLedgerPendingEntries().size() + 1);
798                     for (GeneralLedgerPendingEntry glpe : dv.getGeneralLedgerPendingEntries()) {
799                         glpe.refresh();
800                         if (glpe.getFinancialDocumentApprovedCode().equals(OLEConstants.PENDING_ENTRY_APPROVED_STATUS_CODE.PROCESSED)) {
801                             // damn! it got processed! well, make a copy, oppositify, and save
802                             GeneralLedgerPendingEntry undoer = new GeneralLedgerPendingEntry(glpe);
803                             oppositifyEntry(undoer, boService, glpeSeqHelper);
804                             newGLPEs.add(undoer);
805                         }
806                         else {
807                             // just delete the GLPE before anything happens to it
808                             boService.delete(glpe);
809                         }
810                     }
811                     dv.setGeneralLedgerPendingEntries(newGLPEs);
812                 }
813                 // set the financial document status to canceled
814                 dv.getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(OLEConstants.DocumentStatusCodes.CANCELLED);
815                 // save the document
816                 SpringContext.getBean(DocumentService.class).saveDocument(dv, AccountingDocumentSaveWithNoLedgerEntryGenerationEvent.class);
817             }
818             catch (WorkflowException we) {
819                 LOG.error("encountered workflow exception while attempting to save Disbursement Voucher: " + dv.getDocumentNumber() + " " + we);
820                 throw new RuntimeException(we);
821             }
822         }
823     }
824 
825     /**
826      * Updates the given general ledger pending entry so that it will have the opposite effect of what it was created to do; this,
827      * in effect, undoes the entries that were already posted for this document
828      *
829      * @param glpe the general ledger pending entry to undo
830      */
831     protected void oppositifyEntry(GeneralLedgerPendingEntry glpe, BusinessObjectService boService, GeneralLedgerPendingEntrySequenceHelper glpeSeqHelper) {
832         if (glpe.getTransactionDebitCreditCode().equals(OLEConstants.GL_CREDIT_CODE)) {
833             glpe.setTransactionDebitCreditCode(OLEConstants.GL_DEBIT_CODE);
834         }
835         else if (glpe.getTransactionDebitCreditCode().equals(OLEConstants.GL_DEBIT_CODE)) {
836             glpe.setTransactionDebitCreditCode(OLEConstants.GL_CREDIT_CODE);
837         }
838         glpe.setTransactionLedgerEntrySequenceNumber(glpeSeqHelper.getSequenceCounter());
839         glpeSeqHelper.increment();
840         glpe.setFinancialDocumentApprovedCode(OLEConstants.PENDING_ENTRY_APPROVED_STATUS_CODE.APPROVED);
841         boService.save(glpe);
842     }
843 
844     /**
845      * This updates the disbursement voucher so that when it is re-extracted, information about it will be accurate
846      *
847      * @param dv the disbursement voucher document to reset
848      * @param processDate the date of the reseting
849      * @see org.kuali.ole.fp.batch.service.DisbursementVoucherExtractService#resetExtractedDisbursementVoucher(org.kuali.ole.fp.document.DisbursementVoucherDocument, java.sql.Date)
850      */
851     @Override
852     public void resetExtractedDisbursementVoucher(DisbursementVoucherDocument dv, java.sql.Date processDate) {
853         try {
854             // 1. reset the extracted date
855             dv.setExtractDate(null);
856             dv.setPaidDate(null);
857             // 2. save the doc
858             SpringContext.getBean(DocumentService.class).saveDocument(dv, AccountingDocumentSaveWithNoLedgerEntryGenerationEvent.class);
859         }
860         catch (WorkflowException we) {
861             LOG.error("encountered workflow exception while attempting to save Disbursement Voucher: " + dv.getDocumentNumber() + " " + we);
862             throw new RuntimeException(we);
863         }
864     }
865 
866     /**
867      * Looks up the document using document service, and deals with any nasty WorkflowException or ClassCastExceptions that pop up
868      *
869      * @param documentNumber the number of the document to look up
870      * @return the dv doc if found, or null otherwise
871      * @see org.kuali.ole.fp.batch.service.DisbursementVoucherExtractService#getDocumentById(java.lang.String)
872      */
873     @Override
874     public DisbursementVoucherDocument getDocumentById(String documentNumber) {
875         DisbursementVoucherDocument dv = null;
876         try {
877             dv = (DisbursementVoucherDocument) SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(documentNumber);
878         }
879         catch (WorkflowException we) {
880             LOG.error("encountered workflow exception while attempting to retrieve Disbursement Voucher: " + dv.getDocumentNumber() + " " + we);
881             throw new RuntimeException(we);
882         }
883         return dv;
884     }
885 
886     /**
887      * Marks the disbursement voucher as paid by setting its paid date
888      *
889      * @param dv the dv document to mark as paid
890      * @param processDate the date when the dv was paid
891      * @see org.kuali.ole.fp.batch.service.DisbursementVoucherExtractService#markDisbursementVoucherAsPaid(org.kuali.ole.fp.document.DisbursementVoucherDocument, java.sql.Date)
892      */
893     @Override
894     public void markDisbursementVoucherAsPaid(DisbursementVoucherDocument dv, java.sql.Date processDate) {
895         try {
896             dv.setPaidDate(processDate);
897             SpringContext.getBean(DocumentService.class).saveDocument(dv, AccountingDocumentSaveWithNoLedgerEntryGenerationEvent.class);
898         }
899         catch (WorkflowException we) {
900             LOG.error("encountered workflow exception while attempting to save Disbursement Voucher: " + dv.getDocumentNumber() + " " + we);
901             throw new RuntimeException(we);
902         }
903     }
904 
905 
906 
907     /**
908      * Extracts a single DisbursementVoucherDocument
909      * @see org.kuali.ole.fp.batch.service.DisbursementVoucherExtractService#extractImmediatePayment(org.kuali.ole.fp.document.DisbursementVoucherDocument)
910      */
911     @Override
912     public void extractImmediatePayment(DisbursementVoucherDocument disbursementVoucher) {
913         if (LOG.isDebugEnabled()) {
914             LOG.debug("extractImmediatePayment(DisbursementVoucherDocument) started");
915         }
916         Date processRunDate = dateTimeService.getCurrentDate();
917         String noteLines = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.MAX_NOTE_LINES);
918         try {
919             maxNoteLines = Integer.parseInt(noteLines);
920         }
921         catch (NumberFormatException nfe) {
922             throw new IllegalArgumentException("Invalid Max Notes Lines parameter");
923         }
924         Person user = getPersonService().getPersonByPrincipalName(getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER));
925         if (user == null) {
926             LOG.debug("extractPayments() Unable to find user " + getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER));
927             throw new IllegalArgumentException("Unable to find user " + getOleSelectDocumentService().getSelectParameterValue(OLEConstants.SYSTEM_USER));
928         }
929 
930         Batch batch = createBatch(disbursementVoucher.getCampusCode(), user, processRunDate);
931         KualiDecimal totalAmount = KualiDecimal.ZERO;
932 
933         addPayment(disbursementVoucher, batch, processRunDate, true);
934         totalAmount = totalAmount.add(disbursementVoucher.getDisbVchrCheckTotalAmount());
935 
936         batch.setPaymentCount(new KualiInteger(1));
937         batch.setPaymentTotalAmount(totalAmount);
938 
939         businessObjectService.save(batch);
940         paymentFileEmailService.sendDisbursementVoucherImmediateExtractEmail(disbursementVoucher, user);
941     }
942 
943     /**
944      * This method sets the disbursementVoucherDao instance.
945      *
946      * @param disbursementVoucherDao The DisbursementVoucherDao to be set.
947      */
948     public void setDisbursementVoucherDao(DisbursementVoucherDao disbursementVoucherDao) {
949         this.disbursementVoucherDao = disbursementVoucherDao;
950     }
951 
952     /**
953      * This method sets the ParameterService instance.
954      *
955      * @param parameterService The ParameterService to be set.
956      */
957     public void setParameterService(ParameterService parameterService) {
958         this.parameterService = parameterService;
959     }
960 
961     /**
962      * This method sets the dateTimeService instance.
963      *
964      * @param dateTimeService The DateTimeService to be set.
965      */
966     public void setDateTimeService(DateTimeService dateTimeService) {
967         this.dateTimeService = dateTimeService;
968     }
969 
970     /**
971      * This method sets the customerProfileService instance.
972      *
973      * @param customerProfileService The CustomerProfileService to be set.
974      */
975     public void setCustomerProfileService(CustomerProfileService customerProfileService) {
976         this.customerProfileService = customerProfileService;
977     }
978 
979     /**
980      * This method sets the paymentFileService instance.
981      *
982      * @param paymentFileService The PaymentFileService to be set.
983      */
984     public void setPaymentFileService(PaymentFileService paymentFileService) {
985         this.paymentFileService = paymentFileService;
986     }
987 
988     /**
989      * This method sets the paymentGroupService instance.
990      *
991      * @param paymentGroupService The PaymentGroupService to be set.
992      */
993     public void setPaymentGroupService(PaymentGroupService paymentGroupService) {
994         this.paymentGroupService = paymentGroupService;
995     }
996 
997     /**
998      * Sets the businessObjectService attribute value.
999      *
1000      * @param businessObjectService The businessObjectService to set.
1001      */
1002     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
1003         this.businessObjectService = businessObjectService;
1004     }
1005 
1006     /**
1007      * Sets the paymentFileEmailService attribute value.
1008      *
1009      * @param paymentFileEmailService The paymentFileEmailService to set.
1010      */
1011     public void setPaymentFileEmailService(PdpEmailService paymentFileEmailService) {
1012         this.paymentFileEmailService = paymentFileEmailService;
1013     }
1014 
1015     /**
1016      * @return Returns the personService.
1017      */
1018     protected PersonService getPersonService() {
1019         if(personService==null) {
1020             personService = SpringContext.getBean(PersonService.class);
1021         }
1022         return personService;
1023     }
1024 
1025     public OleSelectDocumentService getOleSelectDocumentService() {
1026         if(oleSelectDocumentService == null){
1027             oleSelectDocumentService = SpringContext.getBean(OleSelectDocumentService.class);
1028         }
1029         return oleSelectDocumentService;
1030     }
1031 
1032     public void setOleSelectDocumentService(OleSelectDocumentService oleSelectDocumentService) {
1033         this.oleSelectDocumentService = oleSelectDocumentService;
1034     }
1035 
1036 }