001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.module.purap.service.impl;
017    
018    import java.sql.Timestamp;
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.Date;
022    import java.util.HashMap;
023    import java.util.Iterator;
024    import java.util.List;
025    import java.util.Map;
026    import java.util.Set;
027    
028    import org.apache.commons.lang.StringUtils;
029    import org.apache.commons.lang.builder.EqualsBuilder;
030    import org.apache.commons.lang.builder.HashCodeBuilder;
031    import org.kuali.kfs.module.purap.PurapConstants;
032    import org.kuali.kfs.module.purap.batch.service.PurapRunDateService;
033    import org.kuali.kfs.module.purap.businessobject.CreditMemoItem;
034    import org.kuali.kfs.module.purap.businessobject.PaymentRequestItem;
035    import org.kuali.kfs.module.purap.document.AccountsPayableDocument;
036    import org.kuali.kfs.module.purap.document.PaymentRequestDocument;
037    import org.kuali.kfs.module.purap.document.VendorCreditMemoDocument;
038    import org.kuali.kfs.module.purap.document.service.CreditMemoService;
039    import org.kuali.kfs.module.purap.document.service.PaymentRequestService;
040    import org.kuali.kfs.module.purap.document.service.PurapService;
041    import org.kuali.kfs.module.purap.service.PdpExtractService;
042    import org.kuali.kfs.module.purap.util.VendorGroupingHelper;
043    import org.kuali.kfs.pdp.PdpConstants;
044    import org.kuali.kfs.pdp.PdpParameterConstants;
045    import org.kuali.kfs.pdp.businessobject.Batch;
046    import org.kuali.kfs.pdp.businessobject.CustomerProfile;
047    import org.kuali.kfs.pdp.businessobject.PaymentAccountDetail;
048    import org.kuali.kfs.pdp.businessobject.PaymentDetail;
049    import org.kuali.kfs.pdp.businessobject.PaymentGroup;
050    import org.kuali.kfs.pdp.businessobject.PaymentNoteText;
051    import org.kuali.kfs.pdp.service.CustomerProfileService;
052    import org.kuali.kfs.pdp.service.PaymentDetailService;
053    import org.kuali.kfs.pdp.service.PaymentFileService;
054    import org.kuali.kfs.pdp.service.PaymentGroupService;
055    import org.kuali.kfs.pdp.service.PdpEmailService;
056    import org.kuali.kfs.sys.KFSConstants;
057    import org.kuali.kfs.sys.KFSParameterKeyConstants;
058    import org.kuali.kfs.sys.businessobject.SourceAccountingLine;
059    import org.kuali.kfs.sys.context.SpringContext;
060    import org.kuali.kfs.sys.service.BankService;
061    import org.kuali.kfs.sys.service.impl.KfsParameterConstants;
062    import org.kuali.kfs.vnd.VendorConstants;
063    import org.kuali.rice.kew.exception.WorkflowException;
064    import org.kuali.rice.kim.bo.Person;
065    import org.kuali.rice.kim.service.PersonService;
066    import org.kuali.rice.kns.service.BusinessObjectService;
067    import org.kuali.rice.kns.service.DataDictionaryService;
068    import org.kuali.rice.kns.service.DateTimeService;
069    import org.kuali.rice.kns.service.DocumentService;
070    import org.kuali.rice.kns.service.ParameterService;
071    import org.kuali.rice.kns.util.DateUtils;
072    import org.kuali.rice.kns.util.KualiDecimal;
073    import org.kuali.rice.kns.util.KualiInteger;
074    import org.springframework.transaction.annotation.Transactional;
075    
076    /**
077     * Implementation of PdpExtractService
078     */
079    @Transactional
080    public class PdpExtractServiceImpl implements PdpExtractService {
081        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PdpExtractServiceImpl.class);
082    
083        private PaymentRequestService paymentRequestService;
084        private BusinessObjectService businessObjectService;
085        private PaymentFileService paymentFileService;
086        private ParameterService parameterService;
087        private CustomerProfileService customerProfileService;
088        private DateTimeService dateTimeService;
089        private PersonService<Person> personService;
090        private PaymentGroupService paymentGroupService;
091        private PaymentDetailService paymentDetailService;
092        private CreditMemoService creditMemoService;
093        private DocumentService documentService;
094        private PurapRunDateService purapRunDateService;
095        private PdpEmailService paymentFileEmailService;
096        private BankService bankService;
097        private DataDictionaryService dataDictionaryService;
098        private PurapAccountingServiceImpl purapAccountingService;
099    
100        /**
101         * @see org.kuali.kfs.module.purap.service.PdpExtractService#extractImmediatePaymentsOnly()
102         */
103        public void extractImmediatePaymentsOnly() {
104            LOG.debug("extractImmediatePaymentsOnly() started");
105    
106            Date processRunDate = dateTimeService.getCurrentDate();
107            extractPayments(true, processRunDate);
108        }
109    
110        /**
111         * @see org.kuali.kfs.module.purap.service.PdpExtractService#extractPayments(Date)
112         */
113        public void extractPayments(Date runDate) {
114            LOG.debug("extractPayments() started");
115    
116            extractPayments(false, runDate);
117        }
118    
119        /**
120         * Extracts payments from the database
121         * 
122         * @param immediateOnly whether to pick up immediate payments only
123         * @param processRunDate time/date to use to put on the {@link Batch} that's created; and when immediateOnly is false, is also
124         *        used as the maximum allowed PREQ pay date when searching PREQ documents eligible to have payments extracted
125         */
126        protected void extractPayments(boolean immediateOnly, Date processRunDate) {
127            LOG.debug("extractPayments() started");
128    
129            Person uuser = getPersonService().getPersonByPrincipalName(KFSConstants.SYSTEM_USER);
130            if (uuser == null) {
131                LOG.error("extractPayments() Unable to find user " + KFSConstants.SYSTEM_USER);
132                throw new IllegalArgumentException("Unable to find user " + KFSConstants.SYSTEM_USER);
133            }
134    
135            List<String> campusesToProcess = getChartCodes(immediateOnly, processRunDate);
136            for (String campus : campusesToProcess) {
137                extractPaymentsForCampus(campus, uuser, processRunDate, immediateOnly);
138            }
139        }
140    
141        /**
142         * Handle a single campus
143         * 
144         * @param campusCode
145         * @param puser
146         * @param processRunDate
147         */
148        protected void extractPaymentsForCampus(String campusCode, Person puser, Date processRunDate, boolean immediateOnly) {
149            LOG.debug("extractPaymentsForCampus() started for campus: " + campusCode);
150    
151            Batch batch = createBatch(campusCode, puser, processRunDate);
152    
153            Integer count = 0;
154            KualiDecimal totalAmount = KualiDecimal.ZERO;
155    
156            // Do all the special ones
157            Totals totals = extractSpecialPaymentsForChart(campusCode, puser, processRunDate, batch, immediateOnly);
158            count = count + totals.count;
159            totalAmount = totalAmount.add(totals.totalAmount);
160    
161            if (!immediateOnly) {
162                // Do all the regular ones (including credit memos)
163                totals = extractRegularPaymentsForChart(campusCode, puser, processRunDate, batch);
164                count = count + totals.count;
165                totalAmount = totalAmount.add(totals.totalAmount);
166            }
167    
168            batch.setPaymentCount(new KualiInteger(count));
169            batch.setPaymentTotalAmount(totalAmount);
170    
171            businessObjectService.save(batch);
172            paymentFileEmailService.sendLoadEmail(batch);
173        }
174    
175        /**
176         * Get all the payments that could be combined with credit memos
177         * 
178         * @param campusCode
179         * @param puser
180         * @param processRunDate
181         * @param batch
182         * @return Totals
183         */
184        protected Totals extractRegularPaymentsForChart(String campusCode, Person puser, Date processRunDate, Batch batch) {
185            LOG.debug("START - extractRegularPaymentsForChart()");
186    
187            Totals totals = new Totals();
188    
189            java.sql.Date onOrBeforePaymentRequestPayDate = DateUtils.convertToSqlDate(purapRunDateService.calculateRunDate(processRunDate));
190    
191            List<String> preqsWithOutstandingCreditMemos = new ArrayList<String>();
192    
193            Set<VendorGroupingHelper> vendors = creditMemoService.getVendorsOnCreditMemosToExtract(campusCode);
194            for (VendorGroupingHelper vendor : vendors) {
195                if (LOG.isDebugEnabled()) {
196                    LOG.debug("Processing Vendor: " + vendor);
197                }
198    
199                Map<String, List<PaymentRequestDocument>> bankCodePaymentRequests = new HashMap<String, List<PaymentRequestDocument>>();
200                Map<String, List<VendorCreditMemoDocument>> bankCodeCreditMemos = new HashMap<String, List<VendorCreditMemoDocument>>();
201    
202                // Get all the matching credit memos
203                Collection<VendorCreditMemoDocument> vendorMemos = creditMemoService.getCreditMemosToExtractByVendor(campusCode, vendor);
204                for (VendorCreditMemoDocument cmd : vendorMemos) {
205                    List<VendorCreditMemoDocument> bankMemos = new ArrayList<VendorCreditMemoDocument>();
206                    if (bankCodeCreditMemos.containsKey(cmd.getBankCode())) {
207                        bankMemos = (List<VendorCreditMemoDocument>) bankCodeCreditMemos.get(cmd.getBankCode());
208                    }
209    
210                    bankMemos.add(cmd);
211                    bankCodeCreditMemos.put(cmd.getBankCode(), bankMemos);
212                }
213    
214                // get all matching payment requests
215                Collection<PaymentRequestDocument> vendorPreqs = paymentRequestService.getPaymentRequestsToExtractByVendor(campusCode, vendor, onOrBeforePaymentRequestPayDate);
216                for (PaymentRequestDocument prd : vendorPreqs) {
217                    List<PaymentRequestDocument> bankPreqs = new ArrayList<PaymentRequestDocument>();
218                    if (bankCodePaymentRequests.containsKey(prd.getBankCode())) {
219                        bankPreqs = (List<PaymentRequestDocument>) bankCodePaymentRequests.get(prd.getBankCode());
220                    }
221    
222                    bankPreqs.add(prd);
223                    bankCodePaymentRequests.put(prd.getBankCode(), bankPreqs);
224                }
225    
226                // if bank functionality enabled, create bundles by bank, else just by vendor
227                if (bankService.isBankSpecificationEnabled()) {
228                    for (String bankCode : bankCodePaymentRequests.keySet()) {
229                        // if we have credit memos with bank code, process together, else let the preq go and will get picked up below
230                        // and processed as a single payment group
231                        if (bankCodeCreditMemos.containsKey(bankCode)) {
232                            processPaymentBundle(bankCodePaymentRequests.get(bankCode), bankCodeCreditMemos.get(bankCode), totals, preqsWithOutstandingCreditMemos, puser, processRunDate, batch);
233                        }
234                    }
235                }
236                else {
237                    if (vendorMemos.isEmpty()) {
238                        processPaymentBundle((List<PaymentRequestDocument>) vendorPreqs, (List<VendorCreditMemoDocument>) vendorMemos, totals, preqsWithOutstandingCreditMemos, puser, processRunDate, batch);
239                    }
240                }
241            }
242    
243            LOG.debug("processing PREQs without CMs");
244    
245            // Get all the payment requests to process that do not have credit memos
246            Collection<PaymentRequestDocument> paymentRequests = paymentRequestService.getPaymentRequestToExtractByChart(campusCode, onOrBeforePaymentRequestPayDate);
247            for (PaymentRequestDocument prd : paymentRequests) {
248                // if in the list created above, don't create the payment group
249                if (!preqsWithOutstandingCreditMemos.contains(prd.getDocumentNumber())) {
250                    PaymentGroup paymentGroup = processSinglePaymentRequestDocument(prd, batch, puser, processRunDate);
251    
252                    totals.count = totals.count + paymentGroup.getPaymentDetails().size();
253                    totals.totalAmount = totals.totalAmount.add(paymentGroup.getNetPaymentAmount());
254                }
255            }
256    
257            LOG.debug("END - extractRegularPaymentsForChart()");
258            return totals;
259        }
260    
261        /**
262         * Processes the list of payment requests and credit memos as a payment group pending
263         * 
264         * @param paymentRequests
265         * @param creditMemos
266         * @param totals
267         * @param preqsWithOutstandingCreditMemos
268         * @param puser
269         * @param processRunDate
270         * @param batch
271         */
272        protected void processPaymentBundle(List<PaymentRequestDocument> paymentRequests, List<VendorCreditMemoDocument> creditMemos, Totals totals, List<String> preqsWithOutstandingCreditMemos, Person puser, Date processRunDate, Batch batch) {
273            KualiDecimal paymentRequestAmount = KualiDecimal.ZERO;
274            for (PaymentRequestDocument paymentRequestDocument : paymentRequests) {
275                paymentRequestAmount = paymentRequestAmount.add(paymentRequestDocument.getGrandTotal());
276            }
277    
278            KualiDecimal creditMemoAmount = KualiDecimal.ZERO;
279            for (VendorCreditMemoDocument creditMemoDocument : creditMemos) {
280                creditMemoAmount = creditMemoAmount.add(creditMemoDocument.getCreditMemoAmount());
281            }
282    
283            // if payment amount greater than credit, create bundle
284            boolean bundleCreated = false;
285            if (paymentRequestAmount.compareTo(creditMemoAmount) >= 0) {
286                PaymentGroup paymentGroup = buildPaymentGroup(paymentRequests, creditMemos, batch);
287    
288                if (validatePaymentGroup(paymentGroup)) {
289                    this.businessObjectService.save(paymentGroup);
290                    if (LOG.isDebugEnabled()) {
291                        LOG.debug("Created PaymentGroup: " + paymentGroup.getId());
292                    }
293    
294                    totals.count++;
295                    totals.totalAmount = totals.totalAmount.add(paymentGroup.getNetPaymentAmount());
296    
297                    // mark the CMs and PREQs as processed
298                    for (VendorCreditMemoDocument cm : creditMemos) {
299                        updateCreditMemo(cm, puser, processRunDate);
300                    }
301    
302                    for (PaymentRequestDocument pr : paymentRequests) {
303                        updatePaymentRequest(pr, puser, processRunDate);
304                    }
305    
306                    bundleCreated = true;
307                }
308            }
309    
310            if (!bundleCreated) {
311                // add payment request doc numbers to list so they don't get picked up later
312                for (PaymentRequestDocument doc : paymentRequests) {
313                    preqsWithOutstandingCreditMemos.add(doc.getDocumentNumber());
314                }
315            }
316        }
317    
318        /**
319         * Handle a single payment request with no credit memos
320         * 
321         * @param paymentRequestDocument
322         * @param batch
323         * @param puser
324         * @param processRunDate
325         * @return PaymentGroup
326         */
327        protected PaymentGroup processSinglePaymentRequestDocument(PaymentRequestDocument paymentRequestDocument, Batch batch, Person puser, Date processRunDate) {
328            List<PaymentRequestDocument> prds = new ArrayList<PaymentRequestDocument>();
329            List<VendorCreditMemoDocument> cmds = new ArrayList<VendorCreditMemoDocument>();
330            prds.add(paymentRequestDocument);
331    
332            PaymentGroup paymentGroup = buildPaymentGroup(prds, cmds, batch);
333            if (validatePaymentGroup(paymentGroup)) {
334                this.businessObjectService.save(paymentGroup);
335                updatePaymentRequest(paymentRequestDocument, puser, processRunDate);
336            }
337    
338            return paymentGroup;
339        }
340    
341        /**
342         * Get all the special payments for a campus and process them
343         * 
344         * @param campusCode
345         * @param puser
346         * @param processRunDate
347         * @param batch
348         * @return Totals
349         */
350        protected Totals extractSpecialPaymentsForChart(String campusCode, Person puser, Date processRunDate, Batch batch, boolean immediatesOnly) {
351            Totals totals = new Totals();
352    
353            Collection<PaymentRequestDocument> paymentRequests = null;
354            if (immediatesOnly) {
355                paymentRequests = paymentRequestService.getImmediatePaymentRequestsToExtract(campusCode);
356            }
357            else {
358                java.sql.Date onOrBeforePaymentRequestPayDate = DateUtils.convertToSqlDate(purapRunDateService.calculateRunDate(processRunDate));
359                paymentRequests = paymentRequestService.getPaymentRequestsToExtractSpecialPayments(campusCode, onOrBeforePaymentRequestPayDate);
360            }
361    
362            for (PaymentRequestDocument prd : paymentRequests) {
363                PaymentGroup pg = processSinglePaymentRequestDocument(prd, batch, puser, processRunDate);
364    
365                totals.count = totals.count + pg.getPaymentDetails().size();
366                totals.totalAmount = totals.totalAmount.add(pg.getNetPaymentAmount());
367            }
368    
369            return totals;
370        }
371    
372        /**
373         * Mark a credit memo as extracted
374         * 
375         * @param creditMemoDocument
376         * @param puser
377         * @param processRunDate
378         */
379        protected void updateCreditMemo(VendorCreditMemoDocument creditMemoDocument, Person puser, Date processRunDate) {
380            try {
381                VendorCreditMemoDocument doc = (VendorCreditMemoDocument) documentService.getByDocumentHeaderId(creditMemoDocument.getDocumentNumber());
382                doc.setExtractedTimestamp(new Timestamp(processRunDate.getTime()));
383                SpringContext.getBean(PurapService.class).saveDocumentNoValidation(doc);
384            }
385            catch (WorkflowException e) {
386                throw new IllegalArgumentException("Unable to retrieve credit memo: " + creditMemoDocument.getDocumentNumber());
387            }
388        }
389    
390        /**
391         * Mark a payment request as extracted
392         * 
393         * @param prd
394         * @param puser
395         * @param processRunDate
396         */
397        protected void updatePaymentRequest(PaymentRequestDocument paymentRequestDocument, Person puser, Date processRunDate) {
398            try {
399                PaymentRequestDocument doc = (PaymentRequestDocument) documentService.getByDocumentHeaderId(paymentRequestDocument.getDocumentNumber());
400                doc.setExtractedTimestamp(new Timestamp(processRunDate.getTime()));
401                SpringContext.getBean(PurapService.class).saveDocumentNoValidation(doc);
402            }
403            catch (WorkflowException e) {
404                throw new IllegalArgumentException("Unable to retrieve payment request: " + paymentRequestDocument.getDocumentNumber());
405            }
406        }
407    
408        /**
409         * Create the PDP payment group from a list of payment requests & credit memos
410         * 
411         * @param paymentRequests
412         * @param creditMemos
413         * @param batch
414         * @return PaymentGroup
415         */
416        protected PaymentGroup buildPaymentGroup(List<PaymentRequestDocument> paymentRequests, List<VendorCreditMemoDocument> creditMemos, Batch batch) {
417            // There should always be at least one Payment Request Document in the list.
418            PaymentGroup paymentGroup = null;
419            if (creditMemos.size() > 0) {
420                VendorCreditMemoDocument firstCmd = creditMemos.get(0);
421                paymentGroup = populatePaymentGroup(firstCmd, batch);
422            }
423            else {
424                PaymentRequestDocument firstPrd = paymentRequests.get(0);
425                paymentGroup = populatePaymentGroup(firstPrd, batch);
426            }
427    
428            for (PaymentRequestDocument pr : paymentRequests) {
429                PaymentDetail pd = populatePaymentDetail(pr, batch);
430                paymentGroup.addPaymentDetails(pd);
431            }
432            for (VendorCreditMemoDocument cm : creditMemos) {
433                PaymentDetail pd = populatePaymentDetail(cm, batch);
434                paymentGroup.addPaymentDetails(pd);
435            }
436    
437            return paymentGroup;
438        }
439    
440        /**
441         * Checks payment group note lines does not exceed the maximum allowed
442         * 
443         * @param paymentGroup group to validate
444         * @return true if group is valid, false otherwise
445         */
446        protected boolean validatePaymentGroup(PaymentGroup paymentGroup) {
447            // Check to see if the payment group has too many note lines to be printed on a check
448            List<PaymentDetail> payDetails = paymentGroup.getPaymentDetails();
449    
450            int noteLines = 0;
451            for (PaymentDetail paymentDetail : payDetails) {
452                noteLines++; // Add one for each payment detail; summary of each detail is included on check and counts as a line
453                noteLines += paymentDetail.getNotes().size(); // get all the possible notes for a given detail
454            }
455    
456            int maxNoteLines = getMaxNoteLines();
457            if (noteLines > maxNoteLines) {
458                // compile list of all doc numbers that make up payment group
459                List<String> preqDocIds = new ArrayList<String>();
460                List<String> cmDocIds = new ArrayList<String>();
461    
462                List<PaymentDetail> pds = paymentGroup.getPaymentDetails();
463                for (PaymentDetail payDetail : pds) {
464                    if (KFSConstants.FinancialDocumentTypeCodes.VENDOR_CREDIT_MEMO.equals(payDetail.getFinancialDocumentTypeCode())) {
465                        cmDocIds.add(payDetail.getCustPaymentDocNbr());
466                    }
467                    else {
468                        preqDocIds.add(payDetail.getCustPaymentDocNbr());
469                    }
470                }
471    
472                // send warning email and prevent group from being processed by returning false
473                paymentFileEmailService.sendExceedsMaxNotesWarningEmail(cmDocIds, preqDocIds, noteLines, maxNoteLines);
474                
475                return false;
476            }
477    
478            return true;
479        }
480    
481        /**
482         * @return configured maximum number of note lines allowed
483         */
484        protected int getMaxNoteLines() {
485            String maxLines = parameterService.getParameterValue(KfsParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.MAX_NOTE_LINES);
486            if (StringUtils.isBlank(maxLines)) {
487                throw new RuntimeException("System parameter for max note lines is blank");
488            }
489    
490            return Integer.parseInt(maxLines);
491        }
492    
493        /**
494         * Create a PDP payment detail record from a Credit Memo document
495         * 
496         * @param creditMemoDocument Credit Memo to use for payment detail
497         * @param batch current PDP batch object
498         * @return populated PaymentDetail line
499         */
500        protected PaymentDetail populatePaymentDetail(VendorCreditMemoDocument creditMemoDocument, Batch batch) {
501            PaymentDetail paymentDetail = new PaymentDetail();
502    
503            String invoiceNumber = creditMemoDocument.getCreditMemoNumber();
504            if (invoiceNumber.length() > 25) {
505                invoiceNumber = invoiceNumber.substring(0, 25);
506            }
507            paymentDetail.setInvoiceNbr(invoiceNumber);
508            paymentDetail.setCustPaymentDocNbr(creditMemoDocument.getDocumentNumber());
509    
510            if (creditMemoDocument.getPurapDocumentIdentifier() != null) {
511                paymentDetail.setPurchaseOrderNbr(creditMemoDocument.getPurapDocumentIdentifier().toString());
512            }
513    
514            if (creditMemoDocument.getPurchaseOrderDocument() != null) {
515                if (creditMemoDocument.getPurchaseOrderDocument().getRequisitionIdentifier() != null) {
516                    paymentDetail.setRequisitionNbr(creditMemoDocument.getPurchaseOrderDocument().getRequisitionIdentifier().toString());
517                }
518    
519                if (creditMemoDocument.getDocumentHeader().getOrganizationDocumentNumber() != null) {
520                    paymentDetail.setOrganizationDocNbr(creditMemoDocument.getDocumentHeader().getOrganizationDocumentNumber());
521                }
522            }
523    
524            final String creditMemoDocType = getDataDictionaryService().getDocumentTypeNameByClass(creditMemoDocument.getClass());
525            paymentDetail.setFinancialDocumentTypeCode(creditMemoDocType);
526            paymentDetail.setFinancialSystemOriginCode(KFSConstants.ORIGIN_CODE_KUALI);
527    
528            paymentDetail.setInvoiceDate(creditMemoDocument.getCreditMemoDate());
529            paymentDetail.setOrigInvoiceAmount(creditMemoDocument.getCreditMemoAmount().negated());
530            paymentDetail.setNetPaymentAmount(creditMemoDocument.getDocumentHeader().getFinancialDocumentTotalAmount().negated());
531    
532            KualiDecimal shippingAmount = KualiDecimal.ZERO;
533            KualiDecimal discountAmount = KualiDecimal.ZERO;
534            KualiDecimal creditAmount = KualiDecimal.ZERO;
535            KualiDecimal debitAmount = KualiDecimal.ZERO;
536    
537            for (Iterator iter = creditMemoDocument.getItems().iterator(); iter.hasNext();) {
538                CreditMemoItem item = (CreditMemoItem) iter.next();
539    
540                KualiDecimal itemAmount = KualiDecimal.ZERO;
541                if (item.getExtendedPrice() != null) {
542                    itemAmount = item.getExtendedPrice();
543                }
544                if (PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE.equals(item.getItemTypeCode())) {
545                    discountAmount = discountAmount.subtract(itemAmount);
546                }
547                else if (PurapConstants.ItemTypeCodes.ITEM_TYPE_SHIP_AND_HAND_CODE.equals(item.getItemTypeCode())) {
548                    shippingAmount = shippingAmount.subtract(itemAmount);
549                }
550                else if (PurapConstants.ItemTypeCodes.ITEM_TYPE_FREIGHT_CODE.equals(item.getItemTypeCode())) {
551                    shippingAmount = shippingAmount.add(itemAmount);
552                }
553                else if (PurapConstants.ItemTypeCodes.ITEM_TYPE_MIN_ORDER_CODE.equals(item.getItemTypeCode())) {
554                    debitAmount = debitAmount.subtract(itemAmount);
555                }
556                else if (PurapConstants.ItemTypeCodes.ITEM_TYPE_MISC_CODE.equals(item.getItemTypeCode())) {
557                    if (itemAmount.isNegative()) {
558                        creditAmount = creditAmount.subtract(itemAmount);
559                    }
560                    else {
561                        debitAmount = debitAmount.subtract(itemAmount);
562                    }
563                }
564            }
565    
566            paymentDetail.setInvTotDiscountAmount(discountAmount);
567            paymentDetail.setInvTotShipAmount(shippingAmount);
568            paymentDetail.setInvTotOtherCreditAmount(creditAmount);
569            paymentDetail.setInvTotOtherDebitAmount(debitAmount);
570    
571            paymentDetail.setPrimaryCancelledPayment(Boolean.FALSE);
572    
573            addAccounts(creditMemoDocument, paymentDetail, creditMemoDocType);
574            addNotes(creditMemoDocument, paymentDetail);
575    
576            return paymentDetail;
577        }
578    
579        /**
580         * Create a PDP Payment Detail record from a Payment Request document
581         * 
582         * @param paymentRequestDocument Payment Request to use for Payment Detail
583         * @param batch current PDP batch object
584         * @return populated PaymentDetail line
585         */
586        protected PaymentDetail populatePaymentDetail(PaymentRequestDocument paymentRequestDocument, Batch batch) {
587            PaymentDetail paymentDetail = new PaymentDetail();
588    
589            paymentDetail.setCustPaymentDocNbr(paymentRequestDocument.getDocumentNumber());
590    
591            String invoiceNumber = paymentRequestDocument.getInvoiceNumber();
592            if (invoiceNumber.length() > 25) {
593                invoiceNumber = invoiceNumber.substring(0, 25);
594            }
595            paymentDetail.setInvoiceNbr(invoiceNumber);
596    
597            if (paymentRequestDocument.getPurapDocumentIdentifier() != null) {
598                paymentDetail.setPurchaseOrderNbr(paymentRequestDocument.getPurchaseOrderIdentifier().toString());
599            }
600    
601            if (paymentRequestDocument.getPurchaseOrderDocument().getRequisitionIdentifier() != null) {
602                paymentDetail.setRequisitionNbr(paymentRequestDocument.getPurchaseOrderDocument().getRequisitionIdentifier().toString());
603            }
604    
605            if (paymentRequestDocument.getDocumentHeader().getOrganizationDocumentNumber() != null) {
606                paymentDetail.setOrganizationDocNbr(paymentRequestDocument.getDocumentHeader().getOrganizationDocumentNumber());
607            }
608    
609            final String paymentRequestDocType = getDataDictionaryService().getDocumentTypeNameByClass(paymentRequestDocument.getClass());
610            paymentDetail.setFinancialDocumentTypeCode(paymentRequestDocType);
611            paymentDetail.setFinancialSystemOriginCode(KFSConstants.ORIGIN_CODE_KUALI);
612            
613            paymentDetail.setInvoiceDate(paymentRequestDocument.getInvoiceDate());
614            paymentDetail.setOrigInvoiceAmount(paymentRequestDocument.getVendorInvoiceAmount());
615            if (paymentRequestDocument.isUseTaxIndicator()) {
616                paymentDetail.setNetPaymentAmount(paymentRequestDocument.getGrandPreTaxTotal()); // including discounts
617            } else {
618                paymentDetail.setNetPaymentAmount(paymentRequestDocument.getGrandTotal()); // including discounts
619            }
620            
621            KualiDecimal shippingAmount = KualiDecimal.ZERO;
622            KualiDecimal discountAmount = KualiDecimal.ZERO;
623            KualiDecimal creditAmount = KualiDecimal.ZERO;
624            KualiDecimal debitAmount = KualiDecimal.ZERO;
625    
626            for (Iterator iter = paymentRequestDocument.getItems().iterator(); iter.hasNext();) {
627                PaymentRequestItem item = (PaymentRequestItem) iter.next();
628    
629                KualiDecimal itemAmount = KualiDecimal.ZERO;
630                if (item.getTotalRemitAmount() != null) {
631                    itemAmount = item.getTotalRemitAmount();
632                }
633                if (PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE.equals(item.getItemTypeCode())) {
634                    discountAmount = discountAmount.add(itemAmount);
635                }
636                else if (PurapConstants.ItemTypeCodes.ITEM_TYPE_SHIP_AND_HAND_CODE.equals(item.getItemTypeCode())) {
637                    shippingAmount = shippingAmount.add(itemAmount);
638                }
639                else if (PurapConstants.ItemTypeCodes.ITEM_TYPE_FREIGHT_CODE.equals(item.getItemTypeCode())) {
640                    shippingAmount = shippingAmount.add(itemAmount);
641                }
642                else if (PurapConstants.ItemTypeCodes.ITEM_TYPE_MIN_ORDER_CODE.equals(item.getItemTypeCode())) {
643                    debitAmount = debitAmount.add(itemAmount);
644                }
645                else if (PurapConstants.ItemTypeCodes.ITEM_TYPE_MISC_CODE.equals(item.getItemTypeCode())) {
646                    if (itemAmount.isNegative()) {
647                        creditAmount = creditAmount.add(itemAmount);
648                    }
649                    else {
650                        debitAmount = debitAmount.add(itemAmount);
651                    }
652                }
653            }
654    
655            paymentDetail.setInvTotDiscountAmount(discountAmount);
656            paymentDetail.setInvTotShipAmount(shippingAmount);
657            paymentDetail.setInvTotOtherCreditAmount(creditAmount);
658            paymentDetail.setInvTotOtherDebitAmount(debitAmount);
659    
660            paymentDetail.setPrimaryCancelledPayment(Boolean.FALSE);
661    
662            addAccounts(paymentRequestDocument, paymentDetail, paymentRequestDocType);
663            addNotes(paymentRequestDocument, paymentDetail);
664    
665            return paymentDetail;
666        }
667    
668        /**
669         * Add accounts to a PDP Payment Detail
670         * 
671         * @param accountsPayableDocument
672         * @param paymentDetail
673         * @param documentType
674         */
675        protected void addAccounts(AccountsPayableDocument accountsPayableDocument, PaymentDetail paymentDetail, String documentType) {
676            String creditMemoDocType = getDataDictionaryService().getDocumentTypeNameByClass(VendorCreditMemoDocument.class);
677            List<SourceAccountingLine> sourceAccountingLines = purapAccountingService.generateSourceAccountsForVendorRemit(accountsPayableDocument);
678            for (SourceAccountingLine sourceAccountingLine : sourceAccountingLines) {
679              KualiDecimal lineAmount = sourceAccountingLine.getAmount();  
680              PaymentAccountDetail paymentAccountDetail = new PaymentAccountDetail();
681              paymentAccountDetail.setAccountNbr(sourceAccountingLine.getAccountNumber());
682    
683              if (creditMemoDocType.equals(documentType)) {
684                 lineAmount = lineAmount.negated();
685              }
686    
687              paymentAccountDetail.setAccountNetAmount(sourceAccountingLine.getAmount());
688              paymentAccountDetail.setFinChartCode(sourceAccountingLine.getChartOfAccountsCode());
689              paymentAccountDetail.setFinObjectCode(sourceAccountingLine.getFinancialObjectCode());
690              
691              paymentAccountDetail.setFinSubObjectCode(StringUtils.defaultIfEmpty(sourceAccountingLine.getFinancialSubObjectCode(),KFSConstants.getDashFinancialSubObjectCode()));
692              paymentAccountDetail.setOrgReferenceId(sourceAccountingLine.getOrganizationReferenceId());
693              paymentAccountDetail.setProjectCode(StringUtils.defaultIfEmpty(sourceAccountingLine.getProjectCode(),KFSConstants.getDashProjectCode()));
694              paymentAccountDetail.setSubAccountNbr(StringUtils.defaultIfEmpty(sourceAccountingLine.getSubAccountNumber(),KFSConstants.getDashSubAccountNumber()));
695              paymentDetail.addAccountDetail(paymentAccountDetail);
696            }
697        }
698    
699        /**
700         * Add Notes to a PDP Payment Detail
701         * 
702         * @param accountsPayableDocument
703         * @param paymentDetail
704         */
705        protected void addNotes(AccountsPayableDocument accountsPayableDocument, PaymentDetail paymentDetail) {
706            int count = 1;
707    
708            if (accountsPayableDocument instanceof PaymentRequestDocument) {
709                PaymentRequestDocument prd = (PaymentRequestDocument) accountsPayableDocument;
710    
711                if (prd.getSpecialHandlingInstructionLine1Text() != null) {
712                    PaymentNoteText pnt = new PaymentNoteText();
713                    pnt.setCustomerNoteLineNbr(new KualiInteger(count++));
714                    pnt.setCustomerNoteText(prd.getSpecialHandlingInstructionLine1Text());
715                    paymentDetail.addNote(pnt);
716                }
717    
718                if (prd.getSpecialHandlingInstructionLine2Text() != null) {
719                    PaymentNoteText pnt = new PaymentNoteText();
720                    pnt.setCustomerNoteLineNbr(new KualiInteger(count++));
721                    pnt.setCustomerNoteText(prd.getSpecialHandlingInstructionLine2Text());
722                    paymentDetail.addNote(pnt);
723                }
724    
725                if (prd.getSpecialHandlingInstructionLine3Text() != null) {
726                    PaymentNoteText pnt = new PaymentNoteText();
727                    pnt.setCustomerNoteLineNbr(new KualiInteger(count++));
728                    pnt.setCustomerNoteText(prd.getSpecialHandlingInstructionLine3Text());
729                    paymentDetail.addNote(pnt);
730                }
731            }
732    
733            if (accountsPayableDocument.getNoteLine1Text() != null) {
734                PaymentNoteText pnt = new PaymentNoteText();
735                pnt.setCustomerNoteLineNbr(new KualiInteger(count++));
736                pnt.setCustomerNoteText(accountsPayableDocument.getNoteLine1Text());
737                paymentDetail.addNote(pnt);
738            }
739    
740            if (accountsPayableDocument.getNoteLine2Text() != null) {
741                PaymentNoteText pnt = new PaymentNoteText();
742                pnt.setCustomerNoteLineNbr(new KualiInteger(count++));
743                pnt.setCustomerNoteText(accountsPayableDocument.getNoteLine2Text());
744                paymentDetail.addNote(pnt);
745            }
746    
747            if (accountsPayableDocument.getNoteLine3Text() != null) {
748                PaymentNoteText pnt = new PaymentNoteText();
749                pnt.setCustomerNoteLineNbr(new KualiInteger(count++));
750                pnt.setCustomerNoteText(accountsPayableDocument.getNoteLine3Text());
751                paymentDetail.addNote(pnt);
752            }
753            
754            PaymentNoteText pnt = new PaymentNoteText();
755            pnt.setCustomerNoteLineNbr(new KualiInteger(count++));
756            pnt.setCustomerNoteText("Sales Tax: " + accountsPayableDocument.getTotalRemitTax());
757        }
758    
759        /**
760         * Populate the PDP Payment Group from fields on a payment request
761         * 
762         * @param paymentRequestDocument
763         * @param batch
764         * @return PaymentGroup
765         */
766        protected PaymentGroup populatePaymentGroup(PaymentRequestDocument paymentRequestDocument, Batch batch) {
767            LOG.debug("populatePaymentGroup() payment request documentNumber: " + paymentRequestDocument.getDocumentNumber());
768    
769            PaymentGroup paymentGroup = new PaymentGroup();
770    
771            paymentGroup.setBatchId(batch.getId());
772            paymentGroup.setPaymentStatusCode(KFSConstants.PdpConstants.PAYMENT_OPEN_STATUS_CODE);
773            paymentGroup.setBankCode(paymentRequestDocument.getBankCode());
774    
775            String postalCode = paymentRequestDocument.getVendorPostalCode();
776            if (KFSConstants.COUNTRY_CODE_UNITED_STATES.equals(paymentRequestDocument.getVendorCountry())) {
777                // Add a dash in the zip code if necessary
778                if (postalCode.length() > 5) {
779                    postalCode = postalCode.substring(0, 5) + "-" + postalCode.substring(5);
780                }
781            }
782    
783            paymentGroup.setPayeeName(paymentRequestDocument.getVendorName());
784            paymentGroup.setPayeeId(paymentRequestDocument.getVendorHeaderGeneratedIdentifier() + "-" + paymentRequestDocument.getVendorDetailAssignedIdentifier());
785            paymentGroup.setPayeeIdTypeCd(PdpConstants.PayeeIdTypeCodes.VENDOR_ID);
786    
787            if (paymentRequestDocument.getVendorDetail().getVendorHeader().getVendorOwnershipCategoryCode() != null) {
788                paymentGroup.setPayeeOwnerCd(paymentRequestDocument.getVendorDetail().getVendorHeader().getVendorOwnershipCategoryCode());
789            }
790    
791            if (paymentRequestDocument.getVendorCustomerNumber() != null) {
792                paymentGroup.setCustomerInstitutionNumber(paymentRequestDocument.getVendorCustomerNumber());
793            }
794    
795            paymentGroup.setLine1Address(paymentRequestDocument.getVendorLine1Address());
796            paymentGroup.setLine2Address(paymentRequestDocument.getVendorLine2Address());
797            paymentGroup.setLine3Address("");
798            paymentGroup.setLine4Address("");
799    
800            paymentGroup.setCity(paymentRequestDocument.getVendorCityName());
801            paymentGroup.setState(paymentRequestDocument.getVendorStateCode());
802            paymentGroup.setZipCd(postalCode);
803            paymentGroup.setCountry(paymentRequestDocument.getVendorCountryCode());
804            paymentGroup.setCampusAddress(Boolean.FALSE);
805    
806            if (paymentRequestDocument.getPaymentRequestPayDate() != null) {
807                paymentGroup.setPaymentDate(paymentRequestDocument.getPaymentRequestPayDate());
808            }
809    
810            paymentGroup.setPymtAttachment(paymentRequestDocument.getPaymentAttachmentIndicator());
811            paymentGroup.setProcessImmediate(paymentRequestDocument.getImmediatePaymentIndicator());
812            paymentGroup.setPymtSpecialHandling(StringUtils.isNotBlank(paymentRequestDocument.getSpecialHandlingInstructionLine1Text()) || StringUtils.isNotBlank(paymentRequestDocument.getSpecialHandlingInstructionLine2Text()) || StringUtils.isNotBlank(paymentRequestDocument.getSpecialHandlingInstructionLine3Text()));
813            paymentGroup.setTaxablePayment(Boolean.FALSE);
814            paymentGroup.setNraPayment(VendorConstants.OwnerTypes.NR.equals(paymentRequestDocument.getVendorDetail().getVendorHeader().getVendorOwnershipCode()));
815            paymentGroup.setCombineGroups(Boolean.TRUE);
816    
817            return paymentGroup;
818        }
819    
820        /**
821         * Populates a PaymentGroup record from a Credit Memo document
822         * 
823         * @param creditMemoDocument
824         * @param batch
825         * @return PaymentGroup
826         */
827        protected PaymentGroup populatePaymentGroup(VendorCreditMemoDocument creditMemoDocument, Batch batch) {
828            LOG.debug("populatePaymentGroup() credit memo documentNumber: " + creditMemoDocument.getDocumentNumber());
829    
830            PaymentGroup paymentGroup = new PaymentGroup();
831            paymentGroup.setBatchId(batch.getId());
832            paymentGroup.setPaymentStatusCode(KFSConstants.PdpConstants.PAYMENT_OPEN_STATUS_CODE);
833            paymentGroup.setBankCode(creditMemoDocument.getBankCode());
834    
835            String postalCode = creditMemoDocument.getVendorPostalCode();
836            if (KFSConstants.COUNTRY_CODE_UNITED_STATES.equals(creditMemoDocument.getVendorCountry())) {
837                // Add a dash in the zip code if necessary
838                if (postalCode.length() > 5) {
839                    postalCode = postalCode.substring(0, 5) + "-" + postalCode.substring(5);
840                }
841            }
842    
843            paymentGroup.setPayeeName(creditMemoDocument.getVendorName());
844            paymentGroup.setPayeeId(creditMemoDocument.getVendorHeaderGeneratedIdentifier() + "-" + creditMemoDocument.getVendorDetailAssignedIdentifier());
845            paymentGroup.setPayeeIdTypeCd(PdpConstants.PayeeIdTypeCodes.VENDOR_ID);
846    
847            if (creditMemoDocument.getVendorDetail().getVendorHeader().getVendorOwnershipCategoryCode() != null) {
848                paymentGroup.setPayeeOwnerCd(creditMemoDocument.getVendorDetail().getVendorHeader().getVendorOwnershipCategoryCode());
849            }
850    
851            if (creditMemoDocument.getVendorCustomerNumber() != null) {
852                paymentGroup.setCustomerInstitutionNumber(creditMemoDocument.getVendorCustomerNumber());
853            }
854    
855            paymentGroup.setLine1Address(creditMemoDocument.getVendorLine1Address());
856            paymentGroup.setLine2Address(creditMemoDocument.getVendorLine2Address());
857            paymentGroup.setLine3Address("");
858            paymentGroup.setLine4Address("");
859    
860            paymentGroup.setCity(creditMemoDocument.getVendorCityName());
861            paymentGroup.setState(creditMemoDocument.getVendorStateCode());
862            paymentGroup.setZipCd(postalCode);
863            paymentGroup.setCountry(creditMemoDocument.getVendorCountryCode());
864            paymentGroup.setCampusAddress(Boolean.FALSE);
865    
866            if (creditMemoDocument.getCreditMemoDate() != null) {
867                paymentGroup.setPaymentDate(creditMemoDocument.getCreditMemoDate());
868            }
869    
870            paymentGroup.setPymtAttachment(Boolean.FALSE);
871            paymentGroup.setProcessImmediate(Boolean.FALSE);
872            paymentGroup.setPymtSpecialHandling(Boolean.FALSE);
873            paymentGroup.setTaxablePayment(Boolean.FALSE);
874            paymentGroup.setNraPayment(VendorConstants.OwnerTypes.NR.equals(creditMemoDocument.getVendorDetail().getVendorHeader().getVendorOwnershipCode()));
875            paymentGroup.setCombineGroups(Boolean.TRUE);
876    
877            return paymentGroup;
878        }
879    
880        /**
881         * Create a new PDP batch
882         * 
883         * @param campusCode
884         * @param puser
885         * @param processRunDate
886         * @return Batch
887         */
888        protected Batch createBatch(String campusCode, Person puser, Date processRunDate) {
889            String orgCode = parameterService.getParameterValue(KfsParameterConstants.PURCHASING_BATCH.class, KFSParameterKeyConstants.PurapPdpParameterConstants.PURAP_PDP_ORG_CODE);
890            String subUnitCode = parameterService.getParameterValue(KfsParameterConstants.PURCHASING_BATCH.class, KFSParameterKeyConstants.PurapPdpParameterConstants.PURAP_PDP_SUB_UNIT_CODE);
891            CustomerProfile customer = customerProfileService.get(campusCode, orgCode, subUnitCode);
892            if (customer == null) {
893                throw new IllegalArgumentException("Unable to find customer profile for " + campusCode + "/" + orgCode + "/" + subUnitCode);
894            }
895    
896            // Create the group for this campus
897            Batch batch = new Batch();
898            batch.setCustomerProfile(customer);
899            batch.setCustomerFileCreateTimestamp(new Timestamp(processRunDate.getTime()));
900            batch.setFileProcessTimestamp(new Timestamp(processRunDate.getTime()));
901            batch.setPaymentFileName(PurapConstants.PDP_PURAP_EXTRACT_FILE_NAME);
902            batch.setSubmiterUserId(puser.getPrincipalId());
903    
904            // Set these for now, we will update them later
905            batch.setPaymentCount(KualiInteger.ZERO);
906            batch.setPaymentTotalAmount(KualiDecimal.ZERO);
907    
908            businessObjectService.save(batch);
909    
910            return batch;
911        }
912    
913        /**
914         * Find all the campuses that have payments to process
915         * 
916         * @return List<String>
917         */
918        protected List<String> getChartCodes(boolean immediatesOnly, Date processRunDate) {
919            List<String> output = new ArrayList<String>();
920    
921            Collection<PaymentRequestDocument> paymentRequests = null;
922            if (immediatesOnly) {
923                paymentRequests = paymentRequestService.getImmediatePaymentRequestsToExtract(null);
924            }
925            else {
926                java.sql.Date onOrBeforePaymentRequestPayDate = DateUtils.convertToSqlDate(purapRunDateService.calculateRunDate(processRunDate));
927                paymentRequests = paymentRequestService.getPaymentRequestsToExtract(onOrBeforePaymentRequestPayDate);
928            }
929    
930            for (PaymentRequestDocument prd : paymentRequests) {
931                if (!output.contains(prd.getProcessingCampusCode())) {
932                    output.add(prd.getProcessingCampusCode());
933                }
934            }
935    
936            return output;
937        }
938    
939        /**
940         * Holds total count and amount for extract
941         */
942        protected class Totals {
943            public Integer count = 0;
944            public KualiDecimal totalAmount = KualiDecimal.ZERO;
945        }
946    
947        /**
948         * Holds temporary accounting information for combining into payment accounting details
949         */
950        protected class AccountingInfo {
951            private String chart;
952            private String account;
953            private String subAccount;
954            private String objectCode;
955            private String subObjectCode;
956            private String orgReferenceId;
957            private String projectCode;
958    
959            public AccountingInfo(String c, String a, String s, String o, String so, String or, String pc) {
960                setChart(c);
961                setAccount(a);
962                setSubAccount(s);
963                setObjectCode(o);
964                setSubObjectCode(so);
965                setOrgReferenceId(or);
966                setProjectCode(pc);
967            }
968    
969            public void setAccount(String account) {
970                this.account = account;
971            }
972    
973            public void setChart(String chart) {
974                this.chart = chart;
975            }
976    
977            public void setObjectCode(String objectCode) {
978                this.objectCode = objectCode;
979            }
980    
981            public void setOrgReferenceId(String orgReferenceId) {
982                this.orgReferenceId = orgReferenceId;
983            }
984    
985            public void setProjectCode(String projectCode) {
986                if (projectCode == null) {
987                    this.projectCode = KFSConstants.getDashProjectCode();
988                }
989                else {
990                    this.projectCode = projectCode;
991                }
992            }
993    
994            public void setSubAccount(String subAccount) {
995                if (subAccount == null) {
996                    this.subAccount = KFSConstants.getDashSubAccountNumber();
997                }
998                else {
999                    this.subAccount = subAccount;
1000                }
1001            }
1002    
1003            public void setSubObjectCode(String subObjectCode) {
1004                if (subObjectCode == null) {
1005                    this.subObjectCode = KFSConstants.getDashFinancialSubObjectCode();
1006                }
1007                else {
1008                    this.subObjectCode = subObjectCode;
1009                }
1010            }
1011    
1012            protected String key() {
1013                return chart + "~" + account + "~" + subAccount + "~" + objectCode + "~" + subObjectCode + "~" + orgReferenceId + "~" + projectCode;
1014            }
1015    
1016            public int hashCode() {
1017                return new HashCodeBuilder(3, 5).append(key()).toHashCode();
1018            }
1019    
1020            public boolean equals(Object obj) {
1021                if (!(obj instanceof AccountingInfo)) {
1022                    return false;
1023                }
1024                AccountingInfo thisobj = (AccountingInfo) obj;
1025                return new EqualsBuilder().append(key(), thisobj.key()).isEquals();
1026            }
1027        }
1028    
1029        /**
1030         * Sets the paymentRequestService attribute value.
1031         * 
1032         * @param paymentRequestService The paymentRequestService to set.
1033         */
1034        public void setPaymentRequestService(PaymentRequestService paymentRequestService) {
1035            this.paymentRequestService = paymentRequestService;
1036        }
1037    
1038        /**
1039         * Sets the businessObjectService attribute value.
1040         * 
1041         * @param businessObjectService The businessObjectService to set.
1042         */
1043        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
1044            this.businessObjectService = businessObjectService;
1045        }
1046    
1047        /**
1048         * Sets the paymentFileService attribute value.
1049         * 
1050         * @param paymentFileService The paymentFileService to set.
1051         */
1052        public void setPaymentFileService(PaymentFileService paymentFileService) {
1053            this.paymentFileService = paymentFileService;
1054        }
1055    
1056        /**
1057         * Sets the parameterService attribute value.
1058         * 
1059         * @param parameterService The parameterService to set.
1060         */
1061        public void setParameterService(ParameterService parameterService) {
1062            this.parameterService = parameterService;
1063        }
1064    
1065        /**
1066         * Sets the customerProfileService attribute value.
1067         * 
1068         * @param customerProfileService The customerProfileService to set.
1069         */
1070        public void setCustomerProfileService(CustomerProfileService customerProfileService) {
1071            this.customerProfileService = customerProfileService;
1072        }
1073    
1074        /**
1075         * Sets the dateTimeService attribute value.
1076         * 
1077         * @param dateTimeService The dateTimeService to set.
1078         */
1079        public void setDateTimeService(DateTimeService dateTimeService) {
1080            this.dateTimeService = dateTimeService;
1081        }
1082    
1083        /**
1084         * Sets the paymentGroupService attribute value.
1085         * 
1086         * @param paymentGroupService The paymentGroupService to set.
1087         */
1088        public void setPaymentGroupService(PaymentGroupService paymentGroupService) {
1089            this.paymentGroupService = paymentGroupService;
1090        }
1091    
1092        /**
1093         * Sets the paymentDetailService attribute value.
1094         * 
1095         * @param paymentDetailService The paymentDetailService to set.
1096         */
1097        public void setPaymentDetailService(PaymentDetailService paymentDetailService) {
1098            this.paymentDetailService = paymentDetailService;
1099        }
1100    
1101        /**
1102         * Sets the creditMemoService attribute value.
1103         * 
1104         * @param creditMemoService The creditMemoService to set.
1105         */
1106        public void setCreditMemoService(CreditMemoService creditMemoService) {
1107            this.creditMemoService = creditMemoService;
1108        }
1109    
1110        /**
1111         * Sets the documentService attribute value.
1112         * 
1113         * @param documentService The documentService to set.
1114         */
1115        public void setDocumentService(DocumentService documentService) {
1116            this.documentService = documentService;
1117        }
1118    
1119        /**
1120         * Sets the purapRunDateService attribute value.
1121         * 
1122         * @param purapRunDateService The purapRunDateService to set.
1123         */
1124        public void setPurapRunDateService(PurapRunDateService purapRunDateService) {
1125            this.purapRunDateService = purapRunDateService;
1126        }
1127    
1128        /**
1129         * Sets the paymentFileEmailService attribute value.
1130         * 
1131         * @param paymentFileEmailService The paymentFileEmailService to set.
1132         */
1133        public void setPaymentFileEmailService(PdpEmailService paymentFileEmailService) {
1134            this.paymentFileEmailService = paymentFileEmailService;
1135        }
1136    
1137        /**
1138         * Sets the bankService attribute value.
1139         * 
1140         * @param bankService The bankService to set.
1141         */
1142        public void setBankService(BankService bankService) {
1143            this.bankService = bankService;
1144        }
1145    
1146        /**
1147         * Gets the dataDictionaryService attribute. 
1148         * @return Returns the dataDictionaryService.
1149         */
1150        public DataDictionaryService getDataDictionaryService() {
1151            return dataDictionaryService;
1152        }
1153    
1154        /**
1155         * Sets the dataDictionaryService attribute value.
1156         * @param dataDictionaryService The dataDictionaryService to set.
1157         */
1158        public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
1159            this.dataDictionaryService = dataDictionaryService;
1160        }
1161    
1162        public void setPurapAccountingService(PurapAccountingServiceImpl purapAccountingService) {
1163            this.purapAccountingService = purapAccountingService;
1164        }
1165        
1166        /**
1167         * @return Returns the personService.
1168         */
1169        protected PersonService<Person> getPersonService() {
1170            if(personService==null)
1171                personService = SpringContext.getBean(PersonService.class);
1172            return personService;
1173        }
1174    
1175    }