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.ar.document.service.impl;
017    
018    import java.sql.Date;
019    import java.sql.Timestamp;
020    import java.text.ParseException;
021    import java.util.ArrayList;
022    import java.util.Calendar;
023    import java.util.Collection;
024    import java.util.HashMap;
025    import java.util.List;
026    import java.util.Map;
027    
028    import org.apache.commons.lang.StringUtils;
029    import org.kuali.kfs.module.ar.ArConstants;
030    import org.kuali.kfs.module.ar.businessobject.AccountsReceivableDocumentHeader;
031    import org.kuali.kfs.module.ar.businessobject.Customer;
032    import org.kuali.kfs.module.ar.businessobject.CustomerAddress;
033    import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceDetail;
034    import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceRecurrenceDetails;
035    import org.kuali.kfs.module.ar.businessobject.InvoicePaidApplied;
036    import org.kuali.kfs.module.ar.businessobject.NonInvoicedDistribution;
037    import org.kuali.kfs.module.ar.businessobject.OrganizationOptions;
038    import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument;
039    import org.kuali.kfs.module.ar.document.dataaccess.CustomerInvoiceDocumentDao;
040    import org.kuali.kfs.module.ar.document.service.AccountsReceivableDocumentHeaderService;
041    import org.kuali.kfs.module.ar.document.service.CustomerAddressService;
042    import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDetailService;
043    import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService;
044    import org.kuali.kfs.module.ar.document.service.InvoicePaidAppliedService;
045    import org.kuali.kfs.module.ar.document.service.NonInvoicedDistributionService;
046    import org.kuali.kfs.sys.KFSConstants;
047    import org.kuali.kfs.sys.businessobject.ChartOrgHolder;
048    import org.kuali.kfs.sys.businessobject.FinancialSystemDocumentHeader;
049    import org.kuali.kfs.sys.context.SpringContext;
050    import org.kuali.kfs.sys.service.FinancialSystemUserService;
051    import org.kuali.kfs.sys.service.UniversityDateService;
052    import org.kuali.rice.kew.exception.WorkflowException;
053    import org.kuali.rice.kim.bo.Person;
054    import org.kuali.rice.kim.service.PersonService;
055    import org.kuali.rice.kns.dao.DocumentDao;
056    import org.kuali.rice.kns.document.Document;
057    import org.kuali.rice.kns.exception.InfrastructureException;
058    import org.kuali.rice.kns.service.BusinessObjectService;
059    import org.kuali.rice.kns.service.DateTimeService;
060    import org.kuali.rice.kns.service.DocumentService;
061    import org.kuali.rice.kns.service.ParameterService;
062    import org.kuali.rice.kns.util.GlobalVariables;
063    import org.kuali.rice.kns.util.KualiDecimal;
064    import org.kuali.rice.kns.util.ObjectUtils;
065    import org.springframework.transaction.annotation.Transactional;
066    
067    @Transactional
068    public class CustomerInvoiceDocumentServiceImpl implements CustomerInvoiceDocumentService {
069    
070        private PersonService<Person> personService;
071        private BusinessObjectService businessObjectService;
072        private DateTimeService dateTimeService;
073        private ReceivableAccountingLineService receivableAccountingLineService;
074        private AccountsReceivableDocumentHeaderService accountsReceivableDocumentHeaderService;
075        private CustomerAddressService customerAddressService;
076        private CustomerInvoiceDocumentDao customerInvoiceDocumentDao;
077        private DocumentService documentService;
078        private DocumentDao documentDao;
079        private InvoicePaidAppliedService<CustomerInvoiceDetail> invoicePaidAppliedService;
080        private NonInvoicedDistributionService nonInvoicedDistributionService;
081        private CustomerInvoiceDetailService customerInvoiceDetailService;
082        private CustomerInvoiceRecurrenceDetails customerInvoiceRecurrenceDetails;
083        private UniversityDateService universityDateService;
084    
085        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CustomerInvoiceDocumentServiceImpl.class);
086    
087        public void convertDiscountsToPaidApplieds(CustomerInvoiceDocument invoice) {
088    
089            // this needs a little explanation. we have to calculate manually
090            // whether we've written off the whole thing, because the regular
091            // code uses the invoice paid applieds to discount, but since those
092            // are added but not committed in this transaction, they're also not
093            // visible in this transaction, so we do it manually.
094            KualiDecimal openAmount = invoice.getOpenAmount();
095    
096            String invoiceNumber = invoice.getDocumentNumber();
097            List<CustomerInvoiceDetail> discounts = invoice.getDiscounts();
098    
099            // retrieve the number of current paid applieds, so we dont have item number overlap
100            Integer paidAppliedItemNumber = 0;
101    
102            for (CustomerInvoiceDetail discount : discounts) {
103    
104                // if credit amount is zero, do nothing
105                if (KualiDecimal.ZERO.equals(discount.getAmount())) {
106                    continue;
107                }
108    
109                if (paidAppliedItemNumber == 0) {
110                    paidAppliedItemNumber = invoicePaidAppliedService.getNumberOfInvoicePaidAppliedsForInvoiceDetail(invoiceNumber, discount.getInvoiceItemNumber());
111                }
112    
113                // create and save the paidApplied
114                InvoicePaidApplied invoicePaidApplied = new InvoicePaidApplied();
115                invoicePaidApplied.setDocumentNumber(invoiceNumber);
116                invoicePaidApplied.setPaidAppliedItemNumber(paidAppliedItemNumber++);
117                invoicePaidApplied.setFinancialDocumentReferenceInvoiceNumber(invoiceNumber);
118                invoicePaidApplied.setInvoiceItemNumber(discount.getInvoiceItemNumber());
119                invoicePaidApplied.setUniversityFiscalYear(universityDateService.getCurrentFiscalYear());
120                invoicePaidApplied.setUniversityFiscalPeriodCode(universityDateService.getCurrentUniversityDate().getUniversityFiscalAccountingPeriod());
121                invoicePaidApplied.setInvoiceItemAppliedAmount(discount.getAmount().abs());
122                openAmount = openAmount.subtract(discount.getAmount().abs());
123                businessObjectService.save(invoicePaidApplied);
124            }
125    
126            // if its open, but now with a zero openamount, then close it
127            if (KualiDecimal.ZERO.equals(openAmount)) {
128                invoice.setOpenInvoiceIndicator(false);
129                invoice.setClosedDate(dateTimeService.getCurrentSqlDate());
130                documentService.updateDocument(invoice);
131            }
132        }
133    
134        public Collection<CustomerInvoiceDocument> getAllOpenCustomerInvoiceDocuments() {
135            return getAllOpenCustomerInvoiceDocuments(true);
136        }
137    
138        public Collection<CustomerInvoiceDocument> getAllOpenCustomerInvoiceDocumentsWithoutWorkflow() {
139            return getAllOpenCustomerInvoiceDocuments(false);
140        }
141    
142        public Collection<CustomerInvoiceDocument> getAllOpenCustomerInvoiceDocuments(boolean includeWorkflowHeaders) {
143            Collection<CustomerInvoiceDocument> invoices = new ArrayList<CustomerInvoiceDocument>();
144    
145            // retrieve the set of documents without workflow headers
146            invoices = customerInvoiceDocumentDao.getAllOpen();
147    
148            // if we dont need workflow headers, then we're done
149            if (!includeWorkflowHeaders) {
150                return invoices;
151            }
152    
153            // make a list of necessary workflow docs to retrieve
154            List<String> documentHeaderIds = new ArrayList<String>();
155            for (CustomerInvoiceDocument invoice : invoices) {
156                documentHeaderIds.add(invoice.getDocumentNumber());
157            }
158    
159            // get all of our docs with full workflow headers
160            List<CustomerInvoiceDocument> docs = new ArrayList<CustomerInvoiceDocument>();
161            try {
162                docs = documentService.getDocumentsByListOfDocumentHeaderIds(CustomerInvoiceDocument.class, documentHeaderIds);
163            }
164            catch (WorkflowException e) {
165                throw new InfrastructureException("Unable to retrieve Customer Invoice Documents", e);
166            }
167    
168            return docs;
169        }
170    
171        public Collection<CustomerInvoiceDocument> attachWorkflowHeadersToTheInvoices(Collection<CustomerInvoiceDocument> invoices) {
172            List<CustomerInvoiceDocument> docs = new ArrayList<CustomerInvoiceDocument>();
173            if (invoices == null || invoices.isEmpty()) {
174                return docs;
175            }
176    
177            // make a list of necessary workflow docs to retrieve
178            List<String> documentHeaderIds = new ArrayList<String>();
179            for (CustomerInvoiceDocument invoice : invoices) {
180                documentHeaderIds.add(invoice.getDocumentNumber());
181            }
182    
183            // get all of our docs with full workflow headers
184            try {
185                docs = documentService.getDocumentsByListOfDocumentHeaderIds(CustomerInvoiceDocument.class, documentHeaderIds);
186            }
187            catch (WorkflowException e) {
188                throw new InfrastructureException("Unable to retrieve Customer Invoice Documents", e);
189            }
190    
191            return docs;
192        }
193    
194        public Collection<CustomerInvoiceDocument> getOpenInvoiceDocumentsByCustomerNumber(String customerNumber) {
195            Collection<CustomerInvoiceDocument> invoices = new ArrayList<CustomerInvoiceDocument>();
196    
197            // customer number is not required to be populated, so we need to check that it's not null first
198            if (StringUtils.isNotEmpty(customerNumber)) {
199                // trim and force-caps the customer number
200                customerNumber = customerNumber.trim().toUpperCase();
201            }
202    
203            invoices.addAll(customerInvoiceDocumentDao.getOpenByCustomerNumber(customerNumber));
204            return invoices;
205        }
206    
207        public Collection<CustomerInvoiceDocument> getOpenInvoiceDocumentsByCustomerNameByCustomerType(String customerName, String customerTypeCode) {
208            Collection<CustomerInvoiceDocument> invoices = new ArrayList<CustomerInvoiceDocument>();
209    
210            // trim and force-caps the customer name
211            customerName = StringUtils.replace(customerName, KFSConstants.WILDCARD_CHARACTER, KFSConstants.PERCENTAGE_SIGN);
212            customerName = customerName.trim();
213            if (customerName.indexOf("%") < 0)
214                customerName += "%";
215    
216            // trim and force-caps
217            customerTypeCode = customerTypeCode.trim().toUpperCase();
218    
219            invoices.addAll(customerInvoiceDocumentDao.getOpenByCustomerNameByCustomerType(customerName, customerTypeCode));
220            return invoices;
221        }
222    
223        public Collection<CustomerInvoiceDocument> getOpenInvoiceDocumentsByCustomerName(String customerName) {
224            Collection<CustomerInvoiceDocument> invoices = new ArrayList<CustomerInvoiceDocument>();
225    
226            // trim and force-caps the customer name
227            customerName = StringUtils.replace(customerName, KFSConstants.WILDCARD_CHARACTER, KFSConstants.PERCENTAGE_SIGN);
228            customerName = customerName.trim();
229            if (customerName.indexOf("%") < 0)
230                customerName += "%";
231    
232            invoices.addAll(customerInvoiceDocumentDao.getOpenByCustomerName(customerName));
233            return invoices;
234        }
235    
236        public Collection<CustomerInvoiceDocument> getOpenInvoiceDocumentsByCustomerType(String customerTypeCode) {
237            Collection<CustomerInvoiceDocument> invoices = new ArrayList<CustomerInvoiceDocument>();
238    
239            // trim and force-caps
240            customerTypeCode = customerTypeCode.trim().toUpperCase();
241    
242            invoices.addAll(customerInvoiceDocumentDao.getOpenByCustomerType(customerTypeCode));
243            return invoices;
244        }
245    
246        /**
247         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getCustomerInvoiceDetailsForCustomerInvoiceDocument(org.kuali.kfs.module.ar.document.CustomerInvoiceDocument)
248         */
249        public Collection<CustomerInvoiceDetail> getCustomerInvoiceDetailsForCustomerInvoiceDocument(CustomerInvoiceDocument customerInvoiceDocument) {
250            return getCustomerInvoiceDetailsForCustomerInvoiceDocument(customerInvoiceDocument.getDocumentNumber());
251        }
252    
253        /**
254         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getCustomerInvoiceDetailsForCustomerInvoiceDocumentWithCaching(org.kuali.kfs.module.ar.document.CustomerInvoiceDocument)
255         */
256        public Collection<CustomerInvoiceDetail> getCustomerInvoiceDetailsForCustomerInvoiceDocumentWithCaching(CustomerInvoiceDocument customerInvoiceDocument) {
257            return customerInvoiceDetailService.getCustomerInvoiceDetailsForInvoiceWithCaching(customerInvoiceDocument.getDocumentNumber());
258        }
259    
260        /**
261         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getCustomerInvoiceDetailsForCustomerInvoiceDocument(java.lang.String)
262         */
263        public Collection<CustomerInvoiceDetail> getCustomerInvoiceDetailsForCustomerInvoiceDocument(String customerInvoiceDocumentNumber) {
264            return customerInvoiceDetailService.getCustomerInvoiceDetailsForInvoice(customerInvoiceDocumentNumber);
265        }
266    
267    
268        public KualiDecimal getOpenAmountForCustomerInvoiceDocument(String customerInvoiceDocumentNumber) {
269            if (null == customerInvoiceDocumentNumber) {
270                return null;
271            }
272            return getOpenAmountForCustomerInvoiceDocument(getInvoiceByInvoiceDocumentNumber(customerInvoiceDocumentNumber));
273        }
274    
275        public KualiDecimal getOpenAmountForCustomerInvoiceDocument(CustomerInvoiceDocument customerInvoiceDocument) {
276            KualiDecimal total = new KualiDecimal(0);
277            if (customerInvoiceDocument.isOpenInvoiceIndicator()) {
278                Collection<CustomerInvoiceDetail> customerInvoiceDetails = customerInvoiceDocument.getCustomerInvoiceDetailsWithoutDiscounts();
279                for (CustomerInvoiceDetail detail : customerInvoiceDetails) {
280                    // note that we're now dealing with conditionally applying discounts
281                    // depending on whether the doc is saved or approved one level down,
282                    // in the CustomerInvoiceDetail.getAmountOpen()
283                    detail.setCustomerInvoiceDocument(customerInvoiceDocument);
284                    total = total.add(detail.getAmountOpen());
285                }
286            }
287            return total;
288        }
289    
290        public KualiDecimal getOriginalTotalAmountForCustomerInvoiceDocument(CustomerInvoiceDocument customerInvoiceDocument) {
291            LOG.info("\n\n\n\t\t invoice: " + customerInvoiceDocument.getDocumentNumber() + "\n\t\t 111111111 HEADER TOTAL AMOUNT (should be null): " + customerInvoiceDocument.getDocumentHeader().getFinancialDocumentTotalAmount() + "\n\n");
292            customerInvoiceDocument.getDocumentNumber();
293            // original-amount = SpringContext.getBean(FinancialSystemDocumentService.class).get
294            HashMap criteria = new HashMap();
295            criteria.put("documentNumber", customerInvoiceDocument.getDocumentHeader().getDocumentTemplateNumber());
296            businessObjectService = SpringContext.getBean(BusinessObjectService.class);
297            FinancialSystemDocumentHeader financialSystemDocumentHeader = (FinancialSystemDocumentHeader) businessObjectService.findByPrimaryKey(FinancialSystemDocumentHeader.class, criteria);
298            KualiDecimal originalTotalAmount = KualiDecimal.ZERO;
299            originalTotalAmount = financialSystemDocumentHeader.getFinancialDocumentTotalAmount();
300    
301            LOG.info("\n\n\n\t\t invoice: " + customerInvoiceDocument.getDocumentNumber() + "\n\t\t 333333333333 HEADER TOTAL AMOUNT (should be set now): " + customerInvoiceDocument.getDocumentHeader().getFinancialDocumentTotalAmount() + "\n\n");
302            return originalTotalAmount;
303        }
304    
305        /**
306         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getInvoicesByCustomerNumber(java.lang.String)
307         */
308        public Collection<CustomerInvoiceDocument> getCustomerInvoiceDocumentsByCustomerNumber(String customerNumber) {
309    
310            Collection<CustomerInvoiceDocument> invoices = new ArrayList<CustomerInvoiceDocument>();
311    
312            Map<String, String> fieldValues = new HashMap<String, String>();
313            fieldValues.put("customerNumber", customerNumber);
314    
315            Collection<AccountsReceivableDocumentHeader> documentHeaders = businessObjectService.findMatching(AccountsReceivableDocumentHeader.class, fieldValues);
316    
317            List<String> documentHeaderIds = new ArrayList<String>();
318            for (AccountsReceivableDocumentHeader header : documentHeaders) {
319                String documentNumber = null;
320                try {
321                    Long.parseLong(header.getDocumentHeader().getDocumentNumber());
322                    documentNumber = header.getDocumentHeader().getDocumentNumber();
323                    documentHeaderIds.add(documentNumber);
324                }
325                catch (NumberFormatException nfe) {
326                }
327            }
328    
329            if (0 < documentHeaderIds.size()) {
330                try {
331                    invoices = documentService.getDocumentsByListOfDocumentHeaderIds(CustomerInvoiceDocument.class, documentHeaderIds);
332                }
333                catch (WorkflowException e) {
334                    LOG.error(e.getMessage(), e);
335                }
336            }
337            return invoices;
338        }
339    
340        /**
341         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getCustomerByOrganizationInvoiceNumber(java.lang.String)
342         */
343        public Customer getCustomerByOrganizationInvoiceNumber(String organizationInvoiceNumber) {
344            CustomerInvoiceDocument invoice = getInvoiceByOrganizationInvoiceNumber(organizationInvoiceNumber);
345            return invoice.getAccountsReceivableDocumentHeader().getCustomer();
346        }
347    
348        /**
349         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getInvoiceByOrganizationInvoiceNumber(java.lang.String)
350         */
351        public CustomerInvoiceDocument getInvoiceByOrganizationInvoiceNumber(String organizationInvoiceNumber) {
352            return customerInvoiceDocumentDao.getInvoiceByOrganizationInvoiceNumber(organizationInvoiceNumber);
353        }
354    
355        /**
356         * @param invoiceDocumentNumber
357         * @return
358         */
359        public Customer getCustomerByInvoiceDocumentNumber(String invoiceDocumentNumber) {
360            CustomerInvoiceDocument invoice = getInvoiceByInvoiceDocumentNumber(invoiceDocumentNumber);
361            return invoice.getAccountsReceivableDocumentHeader().getCustomer();
362        }
363    
364        /**
365         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getInvoiceByInvoiceDocumentNumber(java.lang.String)
366         */
367        public CustomerInvoiceDocument getInvoiceByInvoiceDocumentNumber(String invoiceDocumentNumber) {
368            return customerInvoiceDocumentDao.getInvoiceByInvoiceDocumentNumber(invoiceDocumentNumber);
369        }
370    
371        public List<CustomerInvoiceDocument> getPrintableCustomerInvoiceDocumentsByInitiatorPrincipalName(String initiatorPrincipalName) {
372            if (StringUtils.isBlank(initiatorPrincipalName)) {
373                throw new IllegalArgumentException("The parameter [initiatorPrincipalName] passed in was null or blank.");
374            }
375    
376            // IMPORTANT NOTES ABOUT THIS METHOD
377            //
378            // This method behaves differently than the other invoice printing methods. This is
379            // because there's no way from within KFS to do a direct DB call to get all the invoices
380            // you want. This is because workflow holds the document initiator, and you cant guarantee
381            // that in a given implementation that you have access to that other db. It could be on
382            // another box in another network, and you only have web-services access to the Rice box.
383            //
384            // Given that, we try to minimize the resource hit of this call as much as possible. First
385            // we retrieve all invoices that havent been printed (ie, dont have a print date) and that
386            // are marked for the USER print queue. At any given time that should be a manageable number of
387            // documents.
388            //
389            // Then we walk through them, retrieve the full workflow-populated version of it, and only
390            // return the ones that match the initiator.
391            //
392            // This isnt as performant a solution as the other getPrintableCustomerInvoiceBy...
393            // methods, but its the best we can do in this release, and it should be manageable.
394    
395            // 
396            // attempt to retrieve the initiator person specified, and puke if not found
397            Person initiator = getPersonService().getPersonByPrincipalName(initiatorPrincipalName);
398            if (initiator == null) {
399                throw new IllegalArgumentException("The parameter value for initiatorPrincipalName [" + initiatorPrincipalName + "] passed in doesnt map to a person.");
400            }
401    
402            // retrieve all the ready-to-print docs in the user-queue for all users
403            List<String> printableUserQueueDocNumbers = customerInvoiceDocumentDao.getPrintableCustomerInvoiceDocumentNumbersFromUserQueue();
404    
405            // get all the documents that might be right, but this set includes documents generated
406            // by the wrong user
407            List<CustomerInvoiceDocument> customerInvoiceDocumentsSuperSet;
408            if (printableUserQueueDocNumbers.size() > 0) {
409                try {
410                    customerInvoiceDocumentsSuperSet = documentService.getDocumentsByListOfDocumentHeaderIds(CustomerInvoiceDocument.class, printableUserQueueDocNumbers);
411                }
412                catch (WorkflowException e) {
413                    throw new InfrastructureException("Unable to retrieve Customer Invoice Documents", e);
414                }
415            }
416            else {
417                customerInvoiceDocumentsSuperSet = new ArrayList<CustomerInvoiceDocument>();
418            }
419    
420            // filter only the ones initiated by the correct user
421            List<CustomerInvoiceDocument> customerInvoiceDocuments = new ArrayList<CustomerInvoiceDocument>();
422            for (CustomerInvoiceDocument superSetDocument : customerInvoiceDocumentsSuperSet) {
423                if (superSetDocument.getDocumentHeader().getWorkflowDocument().userIsInitiator(initiator)) {
424                    customerInvoiceDocuments.add(superSetDocument);
425                }
426            }
427            return customerInvoiceDocuments;
428        }
429    
430        public List<CustomerInvoiceDocument> getPrintableCustomerInvoiceDocumentsByBillingChartAndOrg(String chartOfAccountsCode, String organizationCode) {
431            List<String> documentHeaderIds = customerInvoiceDocumentDao.getPrintableCustomerInvoiceDocumentNumbersByBillingChartAndOrg(chartOfAccountsCode, organizationCode);
432    
433            List<CustomerInvoiceDocument> customerInvoiceDocuments = new ArrayList<CustomerInvoiceDocument>();
434            if (documentHeaderIds != null && !documentHeaderIds.isEmpty()) {
435                try {
436                    customerInvoiceDocuments = documentService.getDocumentsByListOfDocumentHeaderIds(CustomerInvoiceDocument.class, documentHeaderIds);
437                }
438                catch (WorkflowException e) {
439                    throw new InfrastructureException("Unable to retrieve Customer Invoice Documents", e);
440                }
441            }
442            return customerInvoiceDocuments;
443        }
444    
445        public List<CustomerInvoiceDocument> getPrintableCustomerInvoiceDocumentsForBillingStatementByBillingChartAndOrg(String chartOfAccountsCode, String organizationCode) {
446            List<String> documentHeaderIds = customerInvoiceDocumentDao.getPrintableCustomerInvoiceDocumentNumbersForBillingStatementByBillingChartAndOrg(chartOfAccountsCode, organizationCode);
447    
448            List<CustomerInvoiceDocument> customerInvoiceDocuments = new ArrayList<CustomerInvoiceDocument>();
449            if (documentHeaderIds != null && !documentHeaderIds.isEmpty()) {
450                try {
451                    customerInvoiceDocuments = documentService.getDocumentsByListOfDocumentHeaderIds(CustomerInvoiceDocument.class, documentHeaderIds);
452                }
453                catch (WorkflowException e) {
454                    throw new InfrastructureException("Unable to retrieve Customer Invoice Documents", e);
455                }
456            }
457            return customerInvoiceDocuments;
458        }
459    
460        /**
461         * @see org.kuali.module.ar.service.CustomerInvoiceDocumentService#getCustomerInvoiceDocumentsByCustomerNumber(java.lang.String)
462         */
463        public List<CustomerInvoiceDocument> getPrintableCustomerInvoiceDocumentsByProcessingChartAndOrg(String chartOfAccountsCode, String organizationCode) {
464    
465            List<String> documentHeaderIds = customerInvoiceDocumentDao.getPrintableCustomerInvoiceDocumentNumbersByProcessingChartAndOrg(chartOfAccountsCode, organizationCode);
466    
467            List<CustomerInvoiceDocument> customerInvoiceDocuments = new ArrayList<CustomerInvoiceDocument>();
468            if (documentHeaderIds != null && !documentHeaderIds.isEmpty()) {
469                try {
470                    customerInvoiceDocuments = documentService.getDocumentsByListOfDocumentHeaderIds(CustomerInvoiceDocument.class, documentHeaderIds);
471                }
472                catch (WorkflowException e) {
473                    throw new InfrastructureException("Unable to retrieve Customer Invoice Documents", e);
474                }
475            }
476            return customerInvoiceDocuments;
477        }
478    
479        public Collection<CustomerInvoiceDocument> getCustomerInvoiceDocumentsByAccountNumber(String accountNumber) {
480    
481            List<String> docNumbers = customerInvoiceDetailService.getCustomerInvoiceDocumentNumbersByAccountNumber(accountNumber);
482    
483            Collection<CustomerInvoiceDocument> customerInvoiceDocuments = new ArrayList<CustomerInvoiceDocument>();
484    
485            if (docNumbers.size() != 0) {
486                System.out.println(docNumbers);
487                // customerInvoiceDocuments.clear();
488                try {
489                    customerInvoiceDocuments = documentService.getDocumentsByListOfDocumentHeaderIds(CustomerInvoiceDocument.class, docNumbers);
490                }
491                catch (WorkflowException e) {
492                    throw new InfrastructureException("Unable to retrieve Customer Invoice Documents", e);
493                }
494            }
495            return customerInvoiceDocuments;
496        }
497    
498        public List<CustomerInvoiceDocument> getCustomerInvoiceDocumentsByBillingChartAndOrg(String chartOfAccountsCode, String organizationCode) {
499            List<String> documentHeaderIds = customerInvoiceDocumentDao.getCustomerInvoiceDocumentNumbersByBillingChartAndOrg(chartOfAccountsCode, organizationCode);
500    
501            List<CustomerInvoiceDocument> customerInvoiceDocuments = new ArrayList<CustomerInvoiceDocument>();
502            if (documentHeaderIds != null && !documentHeaderIds.isEmpty()) {
503                try {
504                    customerInvoiceDocuments = documentService.getDocumentsByListOfDocumentHeaderIds(CustomerInvoiceDocument.class, documentHeaderIds);
505                }
506                catch (WorkflowException e) {
507                    throw new InfrastructureException("Unable to retrieve Customer Invoice Documents", e);
508                }
509            }
510            return customerInvoiceDocuments;
511        }
512    
513        /**
514         * @see org.kuali.module.ar.service.CustomerInvoiceDocumentService#getCustomerInvoiceDocumentsByCustomerNumber(java.lang.String)
515         */
516        public List<CustomerInvoiceDocument> getCustomerInvoiceDocumentsByProcessingChartAndOrg(String chartOfAccountsCode, String organizationCode) {
517    
518            List<String> documentHeaderIds = customerInvoiceDocumentDao.getCustomerInvoiceDocumentNumbersByProcessingChartAndOrg(chartOfAccountsCode, organizationCode);
519    
520            List<CustomerInvoiceDocument> customerInvoiceDocuments = new ArrayList<CustomerInvoiceDocument>();
521            if (documentHeaderIds != null && !documentHeaderIds.isEmpty()) {
522                try {
523                    customerInvoiceDocuments = documentService.getDocumentsByListOfDocumentHeaderIds(CustomerInvoiceDocument.class, documentHeaderIds);
524                }
525                catch (WorkflowException e) {
526                    throw new InfrastructureException("Unable to retrieve Customer Invoice Documents", e);
527                }
528            }
529            return customerInvoiceDocuments;
530        }
531    
532        /**
533         * Refactor to have all the setters in here.
534         * 
535         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#setupDefaultValuesForNewCustomerInvoiceDocument(org.kuali.kfs.module.ar.document.CustomerInvoiceDocument)
536         */
537        public void setupDefaultValuesForNewCustomerInvoiceDocument(CustomerInvoiceDocument document) {
538    
539            setupBasicDefaultValuesForCustomerInvoiceDocument(document);
540    
541            // set up the default values for the AR DOC Header
542    
543            AccountsReceivableDocumentHeader accountsReceivableDocumentHeader = accountsReceivableDocumentHeaderService.getNewAccountsReceivableDocumentHeaderForCurrentUser();
544            accountsReceivableDocumentHeader.setDocumentNumber(document.getDocumentNumber());
545            document.setAccountsReceivableDocumentHeader(accountsReceivableDocumentHeader);
546    
547            // set up the primary key for AR_INV_RCURRNC_DTL_T
548            CustomerInvoiceRecurrenceDetails recurrenceDetails = new CustomerInvoiceRecurrenceDetails();
549            recurrenceDetails.setInvoiceNumber(document.getDocumentNumber());
550            // recurrenceDetails.setCustomerNumber(document.getCustomer().getCustomerNumber());
551            document.setCustomerInvoiceRecurrenceDetails(recurrenceDetails);
552    
553            Map<String, String> criteria = new HashMap<String, String>();
554            criteria.put("chartOfAccountsCode", document.getBillByChartOfAccountCode());
555            criteria.put("organizationCode", document.getBilledByOrganizationCode());
556            OrganizationOptions organizationOptions = (OrganizationOptions) businessObjectService.findByPrimaryKey(OrganizationOptions.class, criteria);
557    
558            if (ObjectUtils.isNotNull(organizationOptions)) {
559                document.setPrintInvoiceIndicator(organizationOptions.getPrintInvoiceIndicator());
560                document.setInvoiceTermsText(organizationOptions.getOrganizationPaymentTermsText());
561            }
562    
563            // If document is using receivable option, set receivable accounting line for customer invoice document
564            String receivableOffsetOption = SpringContext.getBean(ParameterService.class).getParameterValue(CustomerInvoiceDocument.class, ArConstants.GLPE_RECEIVABLE_OFFSET_GENERATION_METHOD);
565            boolean isUsingReceivableFAU = ArConstants.GLPE_RECEIVABLE_OFFSET_GENERATION_METHOD_FAU.equals(receivableOffsetOption);
566            if (isUsingReceivableFAU) {
567                receivableAccountingLineService.setReceivableAccountingLineForCustomerInvoiceDocument(document);
568            }
569        }
570    
571        /**
572         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#loadCustomerAddressesForCustomerInvoiceDocument(org.kuali.kfs.module.ar.document.CustomerInvoiceDocument)
573         */
574        public void loadCustomerAddressesForCustomerInvoiceDocument(CustomerInvoiceDocument customerInvoiceDocument) {
575            // if address identifier is provided, try to refresh customer address data
576            if (ObjectUtils.isNotNull(customerInvoiceDocument.getAccountsReceivableDocumentHeader())) {
577                CustomerAddressService customerAddressService = SpringContext.getBean(CustomerAddressService.class);
578                CustomerAddress customerShipToAddress = customerAddressService.getByPrimaryKey(customerInvoiceDocument.getAccountsReceivableDocumentHeader().getCustomerNumber(), customerInvoiceDocument.getCustomerShipToAddressIdentifier());
579                CustomerAddress customerBillToAddress = customerAddressService.getByPrimaryKey(customerInvoiceDocument.getAccountsReceivableDocumentHeader().getCustomerNumber(), customerInvoiceDocument.getCustomerBillToAddressIdentifier());
580    
581                if (ObjectUtils.isNotNull(customerShipToAddress)) {
582                    customerInvoiceDocument.setCustomerShipToAddress(customerShipToAddress);
583                    customerInvoiceDocument.setCustomerShipToAddressOnInvoice(customerShipToAddress);
584                }
585    
586                if (ObjectUtils.isNotNull(customerBillToAddress)) {
587                    customerInvoiceDocument.setCustomerBillToAddress(customerBillToAddress);
588                    customerInvoiceDocument.setCustomerBillToAddressOnInvoice(customerBillToAddress);
589                }
590            }
591        }
592    
593        /**
594         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#setupDefaultValuesForCopiedCustomerInvoiceDocument(org.kuali.kfs.module.ar.document.CustomerInvoiceDocument)
595         */
596        public void setupDefaultValuesForCopiedCustomerInvoiceDocument(CustomerInvoiceDocument document) {
597    
598            setupBasicDefaultValuesForCustomerInvoiceDocument(document);
599    
600            // Save customer number since it will get overwritten when we retrieve the accounts receivable document header from service
601            String customerNumber = document.getAccountsReceivableDocumentHeader().getCustomerNumber();
602    
603            // Set up the default values for the AR DOC Header
604            AccountsReceivableDocumentHeader accountsReceivableDocumentHeader = accountsReceivableDocumentHeaderService.getNewAccountsReceivableDocumentHeaderForCurrentUser();
605            accountsReceivableDocumentHeader.setDocumentNumber(document.getDocumentNumber());
606            accountsReceivableDocumentHeader.setCustomerNumber(customerNumber);
607            document.setAccountsReceivableDocumentHeader(accountsReceivableDocumentHeader);
608    
609            // set up the primary key for AR_INV_RCURRNC_DTL_T
610            CustomerInvoiceRecurrenceDetails recurrenceDetails = new CustomerInvoiceRecurrenceDetails();
611            recurrenceDetails.setInvoiceNumber(document.getDocumentNumber());
612            // recurrenceDetails.setCustomerNumber(document.getAccountsReceivableDocumentHeader().getCustomerNumber());
613            document.setCustomerInvoiceRecurrenceDetails(recurrenceDetails);
614    
615            // make open invoice indicator to true
616            document.setOpenInvoiceIndicator(true);
617            document.setPrintDate(null);
618            document.setBillingDate(SpringContext.getBean(DateTimeService.class).getCurrentSqlDateMidnight());
619        }
620    
621        /**
622         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getInvoicePaidAppliedsForCustomerInvoiceDocument(java.lang.String)
623         */
624        // public Collection<InvoicePaidApplied> getInvoicePaidAppliedsForInvoice(String documentNumber) {
625        // return invoicePaidAppliedService.getInvoicePaidAppliedsForInvoice(documentNumber);
626        // }
627        /**
628         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getNonInvoicedDistributionsForInvoice(java.lang.String)
629         */
630        public Collection<NonInvoicedDistribution> getNonInvoicedDistributionsForInvoice(String documentNumber) {
631            return nonInvoicedDistributionService.getNonInvoicedDistributionsForInvoice(documentNumber);
632        }
633    
634        /**
635         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getNonInvoicedTotalForInvoice(org.kuali.kfs.module.ar.document.CustomerInvoiceDocument)
636         */
637        public KualiDecimal getNonInvoicedTotalForInvoice(CustomerInvoiceDocument invoice) {
638            Collection<NonInvoicedDistribution> payments = this.nonInvoicedDistributionService.getNonInvoicedDistributionsForInvoice(invoice);
639            KualiDecimal total = new KualiDecimal(0);
640            for (NonInvoicedDistribution payment : payments) {
641                total = total.add(payment.getFinancialDocumentLineAmount());
642            }
643            return total;
644        }
645    
646        /**
647         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getNonInvoicedTotalForInvoice(java.lang.String)
648         */
649        public KualiDecimal getNonInvoicedTotalForInvoice(String documentNumber) {
650            return getNonInvoicedTotalForInvoice(getInvoiceByInvoiceDocumentNumber(documentNumber));
651        }
652    
653        /**
654         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getPaidAppliedTotalForInvoice(org.kuali.kfs.module.ar.document.CustomerInvoiceDocument)
655         */
656        public KualiDecimal getPaidAppliedTotalForInvoice(CustomerInvoiceDocument invoice) {
657            Collection<InvoicePaidApplied> payments = invoicePaidAppliedService.getInvoicePaidAppliedsForInvoice(invoice);
658            KualiDecimal total = new KualiDecimal(0);
659            for (InvoicePaidApplied payment : payments) {
660                total = total.add(payment.getInvoiceItemAppliedAmount());
661            }
662            return total;
663        }
664    
665        /**
666         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#getPaidAppliedTotalForInvoice(java.lang.String)
667         */
668        public KualiDecimal getPaidAppliedTotalForInvoice(String documentNumber) {
669            return getPaidAppliedTotalForInvoice(getInvoiceByInvoiceDocumentNumber(documentNumber));
670        }
671    
672        /**
673         * @param document
674         */
675        protected void setupBasicDefaultValuesForCustomerInvoiceDocument(CustomerInvoiceDocument document) {
676            ChartOrgHolder currentUser = SpringContext.getBean(FinancialSystemUserService.class).getPrimaryOrganization(GlobalVariables.getUserSession().getPerson(), ArConstants.AR_NAMESPACE_CODE);
677            if (currentUser != null) {
678                document.setBillByChartOfAccountCode(currentUser.getChartOfAccountsCode());
679                document.setBilledByOrganizationCode(currentUser.getOrganizationCode());
680            }
681            document.setInvoiceDueDate(getDefaultInvoiceDueDate());
682            document.setOpenInvoiceIndicator(true);
683        }
684    
685        /**
686         * This method sets due date equal to todays date +30 days by default
687         * 
688         * @param dateTimeService
689         */
690        protected Date getDefaultInvoiceDueDate() {
691            Calendar cal = dateTimeService.getCurrentCalendar();
692            cal.add(Calendar.DATE, 30);
693            Date sqlDueDate = null;
694            try {
695                sqlDueDate = dateTimeService.convertToSqlDate(new Timestamp(cal.getTime().getTime()));
696            }
697            catch (ParseException e) {
698                // TODO: throw an error here, but don't die
699            }
700            return sqlDueDate;
701        }
702    
703        public void closeCustomerInvoiceDocument(CustomerInvoiceDocument customerInvoiceDocument) {
704            customerInvoiceDocument.setOpenInvoiceIndicator(false);
705            customerInvoiceDocument.setClosedDate(dateTimeService.getCurrentSqlDate());
706            businessObjectService.save(customerInvoiceDocument);
707        }
708    
709        public CustomerInvoiceDocumentDao getCustomerInvoiceDocumentDao() {
710            return customerInvoiceDocumentDao;
711        }
712    
713        public void setCustomerInvoiceDocumentDao(CustomerInvoiceDocumentDao customerInvoiceDocumentDao) {
714            this.customerInvoiceDocumentDao = customerInvoiceDocumentDao;
715        }
716    
717        public DocumentService getDocumentService() {
718            return documentService;
719        }
720    
721        public void setDocumentService(DocumentService documentService) {
722            this.documentService = documentService;
723        }
724    
725        public BusinessObjectService getBusinessObjectService() {
726            return businessObjectService;
727        }
728    
729        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
730            this.businessObjectService = businessObjectService;
731        }
732    
733        public DateTimeService getDateTimeService() {
734            return dateTimeService;
735        }
736    
737        public void setDateTimeService(DateTimeService dateTimeService) {
738            this.dateTimeService = dateTimeService;
739        }
740    
741        public ReceivableAccountingLineService getReceivableAccountingLineService() {
742            return receivableAccountingLineService;
743        }
744    
745        public void setReceivableAccountingLineService(ReceivableAccountingLineService receivableAccountingLineService) {
746            this.receivableAccountingLineService = receivableAccountingLineService;
747        }
748    
749        public AccountsReceivableDocumentHeaderService getAccountsReceivableDocumentHeaderService() {
750            return accountsReceivableDocumentHeaderService;
751        }
752    
753        public void setAccountsReceivableDocumentHeaderService(AccountsReceivableDocumentHeaderService accountsReceivableDocumentHeaderService) {
754            this.accountsReceivableDocumentHeaderService = accountsReceivableDocumentHeaderService;
755        }
756    
757        public CustomerAddressService getCustomerAddressService() {
758            return customerAddressService;
759        }
760    
761        public void setCustomerAddressService(CustomerAddressService customerAddressService) {
762            this.customerAddressService = customerAddressService;
763        }
764    
765        public void setDocumentDao(DocumentDao documentDao) {
766            this.documentDao = documentDao;
767        }
768    
769        public void setInvoicePaidAppliedService(InvoicePaidAppliedService invoicePaidAppliedService) {
770            this.invoicePaidAppliedService = invoicePaidAppliedService;
771        }
772    
773        public void setNonInvoicedDistributionService(NonInvoicedDistributionService nonInvoicedDistributionService) {
774            this.nonInvoicedDistributionService = nonInvoicedDistributionService;
775        }
776    
777        public void setCustomerInvoiceDetailService(CustomerInvoiceDetailService customerInvoiceDetailService) {
778            this.customerInvoiceDetailService = customerInvoiceDetailService;
779        }
780    
781        public void setUniversityDateService(UniversityDateService universityDateService) {
782            this.universityDateService = universityDateService;
783        }
784    
785        /**
786         * @return Returns the personService.
787         */
788        protected PersonService<Person> getPersonService() {
789            if (personService == null)
790                personService = SpringContext.getBean(PersonService.class);
791            return personService;
792        }
793    
794        /**
795         * @see org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService#checkIfInvoiceNumberIsFinal(java.lang.String)
796         */
797        public boolean checkIfInvoiceNumberIsFinal(String invDocumentNumber) {
798            boolean success = true;
799            if (StringUtils.isBlank(invDocumentNumber)) {
800                success &= false;
801            }
802            else {
803                CustomerInvoiceDocumentService service = SpringContext.getBean(CustomerInvoiceDocumentService.class);
804                CustomerInvoiceDocument customerInvoiceDocument = service.getInvoiceByInvoiceDocumentNumber(invDocumentNumber);
805    
806                if (ObjectUtils.isNull(customerInvoiceDocument)) {
807                    success &= false;
808                }
809                else {
810                    Document doc = null;
811                    try {
812                        doc = SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(invDocumentNumber);
813                    }
814                    catch (WorkflowException e) {
815                        success &= false;
816                    }
817                    if (ObjectUtils.isNull(doc) || ObjectUtils.isNull(doc.getDocumentHeader()) || doc.getDocumentHeader().getWorkflowDocument() == null || !(doc.getDocumentHeader().getWorkflowDocument().stateIsApproved() || doc.getDocumentHeader().getWorkflowDocument().stateIsProcessed())) {
818                        success &= false;
819                    }
820                }
821            }
822            return success;
823        }
824    
825    }