001/*
002 * Copyright 2007 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 */
016package org.kuali.ole.fp.batch.service.impl;
017
018import java.sql.Timestamp;
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.Date;
022import java.util.HashSet;
023import java.util.Iterator;
024import java.util.List;
025import java.util.Set;
026
027import org.apache.commons.lang.StringUtils;
028import org.apache.commons.lang.WordUtils;
029import org.kuali.ole.fp.batch.DvToPdpExtractStep;
030import org.kuali.ole.fp.batch.service.DisbursementVoucherExtractService;
031import org.kuali.ole.fp.businessobject.DisbursementVoucherPayeeDetail;
032import org.kuali.ole.fp.dataaccess.DisbursementVoucherDao;
033import org.kuali.ole.fp.document.DisbursementVoucherConstants;
034import org.kuali.ole.fp.document.DisbursementVoucherDocument;
035import org.kuali.ole.pdp.PdpConstants;
036import org.kuali.ole.pdp.PdpParameterConstants;
037import org.kuali.ole.pdp.businessobject.Batch;
038import org.kuali.ole.pdp.businessobject.CustomerProfile;
039import org.kuali.ole.pdp.businessobject.PaymentAccountDetail;
040import org.kuali.ole.pdp.businessobject.PaymentDetail;
041import org.kuali.ole.pdp.businessobject.PaymentGroup;
042import org.kuali.ole.pdp.businessobject.PaymentNoteText;
043import org.kuali.ole.pdp.service.CustomerProfileService;
044import org.kuali.ole.pdp.service.PaymentFileService;
045import org.kuali.ole.pdp.service.PaymentGroupService;
046import org.kuali.ole.pdp.service.PdpEmailService;
047import org.kuali.ole.select.document.OleDisbursementVoucherDocument;
048import org.kuali.ole.select.document.service.OleSelectDocumentService;
049import org.kuali.ole.sys.OLEConstants;
050import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry;
051import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
052import org.kuali.ole.sys.businessobject.SourceAccountingLine;
053import org.kuali.ole.sys.context.SpringContext;
054import org.kuali.ole.sys.document.service.FinancialSystemDocumentService;
055import org.kuali.ole.sys.document.validation.event.AccountingDocumentSaveWithNoLedgerEntryGenerationEvent;
056import org.kuali.ole.sys.service.GeneralLedgerPendingEntryService;
057import org.kuali.ole.sys.service.impl.OleParameterConstants;
058import org.kuali.ole.vnd.businessobject.VendorDetail;
059import org.kuali.ole.vnd.document.service.VendorService;
060import org.kuali.rice.core.api.datetime.DateTimeService;
061import org.kuali.rice.core.api.parameter.ParameterEvaluator;
062import org.kuali.rice.core.api.parameter.ParameterEvaluatorService;
063import org.kuali.rice.core.api.util.type.KualiDecimal;
064import org.kuali.rice.core.api.util.type.KualiInteger;
065import org.kuali.rice.coreservice.framework.parameter.ParameterService;
066import org.kuali.rice.kew.api.exception.WorkflowException;
067import org.kuali.rice.kim.api.identity.Person;
068import org.kuali.rice.kim.api.identity.PersonService;
069import org.kuali.rice.krad.service.BusinessObjectService;
070import org.kuali.rice.krad.service.DocumentService;
071import org.kuali.rice.krad.util.ObjectUtils;
072import org.springframework.transaction.annotation.Transactional;
073
074/**
075 * This is the default implementation of the DisbursementVoucherExtractService interface.
076 */
077@Transactional
078public class DisbursementVoucherExtractServiceImpl implements DisbursementVoucherExtractService {
079    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DisbursementVoucherExtractServiceImpl.class);
080
081    private PersonService personService;
082    private ParameterService parameterService;
083    private DisbursementVoucherDao disbursementVoucherDao;
084    private DateTimeService dateTimeService;
085    private CustomerProfileService customerProfileService;
086    private PaymentFileService paymentFileService;
087    private PaymentGroupService paymentGroupService;
088    private BusinessObjectService businessObjectService;
089    private PdpEmailService paymentFileEmailService;
090    private int maxNoteLines;
091    private OleSelectDocumentService oleSelectDocumentService;
092
093    // This should only be set to true when testing this system. Setting this to true will run the code but
094    // won't set the doc status to extracted
095    boolean testMode = false;
096
097    /**
098     * This method extracts all payments from a disbursement voucher with a status code of "A" and uploads them as a batch for
099     * 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}