org.kuali.kfs.module.ar.document.service.impl.DunningLetterServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.kuali.kfs.module.ar.document.service.impl.DunningLetterServiceImpl.java

Source

/*
 * The Kuali Financial System, a comprehensive financial management system for higher education.
 * 
 * Copyright 2005-2014 The Kuali Foundation
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kuali.kfs.module.ar.document.service.impl;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.integration.cg.ContractsAndGrantsBillingAward;
import org.kuali.kfs.module.ar.ArConstants;
import org.kuali.kfs.module.ar.ArKeyConstants;
import org.kuali.kfs.module.ar.businessobject.CollectionActivityType;
import org.kuali.kfs.module.ar.businessobject.CollectionEvent;
import org.kuali.kfs.module.ar.businessobject.CustomerAddress;
import org.kuali.kfs.module.ar.businessobject.DunningLetterTemplate;
import org.kuali.kfs.module.ar.businessobject.GenerateDunningLettersLookupResult;
import org.kuali.kfs.module.ar.businessobject.InvoiceAddressDetail;
import org.kuali.kfs.module.ar.document.ContractsGrantsInvoiceDocument;
import org.kuali.kfs.module.ar.document.dataaccess.ContractsGrantsInvoiceDocumentDao;
import org.kuali.kfs.module.ar.document.service.ContractsGrantsInvoiceDocumentService;
import org.kuali.kfs.module.ar.document.service.DunningLetterService;
import org.kuali.kfs.module.ar.service.ContractsGrantsBillingUtilityService;
import org.kuali.kfs.sys.FinancialSystemModuleConfiguration;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.PdfFormFillerUtil;
import org.kuali.kfs.sys.businessobject.ChartOrgHolder;
import org.kuali.kfs.sys.service.FinancialSystemUserService;
import org.kuali.rice.core.api.datetime.DateTimeService;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kim.api.identity.Person;
import org.kuali.rice.krad.bo.ModuleConfiguration;
import org.kuali.rice.krad.bo.Note;
import org.kuali.rice.krad.service.BusinessObjectService;
import org.kuali.rice.krad.service.KualiModuleService;
import org.kuali.rice.krad.service.NoteService;
import org.kuali.rice.krad.util.GlobalVariables;
import org.kuali.rice.krad.util.ObjectUtils;
import org.springframework.transaction.annotation.Transactional;

import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfCopyFields;
import com.lowagie.text.pdf.PdfReader;

/**
 * Implementation class for DunningLetterDistributionService.
 */
@Transactional
public class DunningLetterServiceImpl implements DunningLetterService {
    protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
            .getLogger(DunningLetterServiceImpl.class);

    protected BusinessObjectService businessObjectService;
    protected ContractsGrantsInvoiceDocumentDao contractsGrantsInvoiceDocumentDao;
    protected ContractsGrantsInvoiceDocumentService contractsGrantsInvoiceDocumentService;
    protected ContractsGrantsBillingUtilityService contractsGrantsBillingUtilityService;
    protected DateTimeService dateTimeService;
    protected FinancialSystemUserService financialSystemUserService;
    protected KualiModuleService kualiModuleService;
    protected NoteService noteService;
    private ParameterService parameterService;

    /**
     * This method generates the actual pdf file with related invoices to the template to print.
     *
     * @param dunningLetterTemplate
     * @param dunningLetterDistributionLookupResult
     * @return
     */
    protected byte[] createDunningLetters(DunningLetterTemplate dunningLetterTemplate,
            GenerateDunningLettersLookupResult dunningLetterDistributionLookupResult) {

        List<ContractsGrantsInvoiceDocument> selectedInvoices = new ArrayList<ContractsGrantsInvoiceDocument>();
        byte[] reportStream = null;
        byte[] finalReportStream = null;
        int lastEventCode;

        if (ObjectUtils.isNotNull(dunningLetterTemplate) && dunningLetterTemplate.isActive()
                && ObjectUtils.isNotNull(dunningLetterTemplate.getFilename())) {
            // To get list of invoices per award per dunning letter template
            for (ContractsGrantsInvoiceDocument cgInvoice : dunningLetterDistributionLookupResult.getInvoices()) {
                if (StringUtils.equals(cgInvoice.getInvoiceGeneralDetail().getDunningLetterTemplateAssigned(),
                        dunningLetterTemplate.getDunningLetterTemplateCode())) {
                    selectedInvoices.add(cgInvoice);
                    // 1. Now we know that the invoice is going to have its dunning letter processed. So we assume the letter is
                    // sent and set the event for it.
                    CollectionEvent event = new CollectionEvent();
                    event.setInvoiceNumber(cgInvoice.getDocumentNumber());
                    event.setCollectionEventCode(cgInvoice.getNextCollectionEventCode());
                    String activityCode = parameterService.getParameterValueAsString(CollectionActivityType.class,
                            ArConstants.DUNNING_LETTER_GENERATION_CODE);
                    if (StringUtils.isNotBlank(activityCode)) {
                        event.setActivityCode(activityCode);
                        event.setActivityDate(new java.sql.Date(new Date().getTime()));
                        event.setActivityText(ArConstants.DunningLetters.DUNNING_LETTER_SENT_TXT);
                        final Timestamp now = dateTimeService.getCurrentTimestamp();
                        event.setPostedDate(now);

                        if (GlobalVariables.getUserSession() != null
                                && GlobalVariables.getUserSession().getPerson() != null) {
                            Person authorUniversal = GlobalVariables.getUserSession().getPerson();
                            event.setUserPrincipalId(authorUniversal.getPrincipalId());
                            event.setUser(authorUniversal);
                        }
                        businessObjectService.save(event);
                        cgInvoice.getCollectionEvents().add(event);
                    }

                    // 2. To set the Last sent date of the dunning letter.

                    cgInvoice.getInvoiceGeneralDetail()
                            .setDunningLetterTemplateSentDate(new java.sql.Date(new Date().getTime()));
                    businessObjectService.save(cgInvoice);
                }
            }

            // to generate dunning letter from templates.
            ModuleConfiguration systemConfiguration = kualiModuleService
                    .getModuleServiceByNamespaceCode(KFSConstants.OptionalModuleNamespaces.ACCOUNTS_RECEIVABLE)
                    .getModuleConfiguration();
            String templateFolderPath = ((FinancialSystemModuleConfiguration) systemConfiguration)
                    .getTemplateFileDirectories().get(KFSConstants.TEMPLATES_DIRECTORY_KEY);
            String templateFilePath = templateFolderPath + File.separator + dunningLetterTemplate.getFilename();
            File templateFile = new File(templateFilePath);
            File outputDirectory = null;
            String outputFileName;
            try {
                // Step2. add parameters to the dunning letter
                outputFileName = dunningLetterDistributionLookupResult.getProposalNumber()
                        + getDateTimeService().toDateStringForFilename(getDateTimeService().getCurrentDate())
                        + ArConstants.TemplateUploadSystem.EXTENSION;
                Map<String, String> replacementList = getTemplateParameterList(selectedInvoices);
                CustomerAddress address;
                Map<String, Object> primaryKeys = new HashMap<String, Object>();
                primaryKeys.put(KFSPropertyConstants.CUSTOMER_NUMBER,
                        dunningLetterDistributionLookupResult.getCustomerNumber());
                primaryKeys.put("customerAddressTypeCode", "P");
                address = businessObjectService.findByPrimaryKey(CustomerAddress.class, primaryKeys);
                replacementList.put("agency.fullAddressInline",
                        contractsGrantsBillingUtilityService.buildFullAddress(address));
                replacementList.put("agency.fullName", address.getCustomer().getCustomerName());
                replacementList.put("agency.contactName", address.getCustomer().getCustomerContactName());
                if (CollectionUtils.isNotEmpty(selectedInvoices)) {
                    reportStream = PdfFormFillerUtil.populateTemplate(templateFile, replacementList);

                    // Step3. attach each dunning letter to invoice pdfs.
                    finalReportStream = generateListOfInvoicesPdfToPrint(selectedInvoices, reportStream);
                }
            } catch (DocumentException | IOException ex) {
                // This means that the invoice pdfs were not generated properly. So get only the Dunning letters created.
                LOG.error("An exception occurred while retrieving invoice pdfs." + ex.getMessage());
                finalReportStream = reportStream;
            }
        } else {
            GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS,
                    ArKeyConstants.ERROR_FILE_UPLOAD_NO_PDF_FILE_SELECTED_FOR_SAVE, "test");
        }

        return finalReportStream;
    }

    /**
     * Loops through the collection of lookup results, creating pdfs for each and appending the bytes of the pdfs onto the returned "finalReport"
     * @see org.kuali.kfs.module.ar.document.service.DunningLetterDistributionService#createDunningLettersForAllResults(org.kuali.kfs.module.ar.businessobject.DunningLetterTemplate, java.util.Collection)
     */
    @Override
    public byte[] createDunningLettersForAllResults(Collection<GenerateDunningLettersLookupResult> results)
            throws DocumentException, IOException {
        ByteArrayOutputStream zos = null;
        PdfCopyFields reportCopy = null;
        byte[] finalReport = null;
        try {
            zos = new ByteArrayOutputStream();
            reportCopy = new PdfCopyFields(zos);
            reportCopy.open();
            List<DunningLetterTemplate> dunningLetterTemplates = (List<DunningLetterTemplate>) getBusinessObjectService()
                    .findAll(DunningLetterTemplate.class);
            for (DunningLetterTemplate dunningLetterTemplate : dunningLetterTemplates) {
                for (GenerateDunningLettersLookupResult generateDunningLettersLookupResult : results) {
                    final byte[] report = createDunningLetters(dunningLetterTemplate,
                            generateDunningLettersLookupResult);
                    if (ObjectUtils.isNotNull(report)) {
                        reportCopy.addDocument(new PdfReader(report));
                    }
                }
            }
            reportCopy.close();
            finalReport = zos.toByteArray();
        } finally {
            if (zos != null) {
                zos.close();
            }
        }
        return finalReport;
    }

    /**
     * This method generated the template parameter list to populate the pdf invoices that are attached to the Document.
     *
     * @return
     */
    protected Map<String, String> getTemplateParameterList(List<ContractsGrantsInvoiceDocument> invoices) {

        Map<String, String> parameterMap = new HashMap<String, String>();

        if (CollectionUtils.isNotEmpty(invoices)) {
            ContractsAndGrantsBillingAward award = invoices.get(0).getInvoiceGeneralDetail().getAward();
            Map primaryKeys = new HashMap<String, Object>();
            contractsGrantsBillingUtilityService.putValueOrEmptyString(parameterMap, "award.proposalNumber",
                    org.apache.commons.lang.ObjectUtils.toString(award.getProposalNumber()));
            contractsGrantsBillingUtilityService.putValueOrEmptyString(parameterMap, "currentDate",
                    getDateTimeService().toDateTimeString(getDateTimeService().getCurrentDate()));
            if (CollectionUtils.isNotEmpty(invoices)) {
                for (int i = 0; i < invoices.size(); i++) {
                    contractsGrantsBillingUtilityService.putValueOrEmptyString(parameterMap,
                            "invoice[" + i + "].documentNumber", invoices.get(i).getDocumentNumber());
                    contractsGrantsBillingUtilityService.putValueOrEmptyString(parameterMap,
                            "invoice[" + i + "].billingDate",
                            getDateTimeService().toDateString(invoices.get(i).getBillingDate()));
                    contractsGrantsBillingUtilityService.putValueOrEmptyString(parameterMap,
                            "invoice[" + i + "].totalAmount", contractsGrantsBillingUtilityService
                                    .formatForCurrency(invoices.get(i).getTotalDollarAmount()));
                    contractsGrantsBillingUtilityService.putValueOrEmptyString(parameterMap,
                            "invoice[" + i + "].customerName", invoices.get(i).getCustomerName());
                    contractsGrantsBillingUtilityService.putValueOrEmptyString(parameterMap,
                            "invoice[" + i + "].customerNumber",
                            invoices.get(i).getAccountsReceivableDocumentHeader().getCustomerNumber());
                }
            }
            if (ObjectUtils.isNotNull(award)) {
                contractsGrantsBillingUtilityService.putValueOrEmptyString(parameterMap, "award.awardProjectTitle",
                        award.getAwardProjectTitle());
            }
        }
        return parameterMap;
    }

    /**
     * This method generates the actual pdf files to print.
     *
     * @param mapping
     * @param form
     * @param list
     * @return
     */
    @Override
    public boolean createZipOfPDFs(byte[] report, ByteArrayOutputStream baos) throws IOException {

        ZipOutputStream zos = new ZipOutputStream(baos);
        int bytesRead;
        byte[] buffer = new byte[1024];
        CRC32 crc = new CRC32();

        if (ObjectUtils.isNotNull(report)) {
            BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(report));
            crc.reset();
            while ((bytesRead = bis.read(buffer)) != -1) {
                crc.update(buffer, 0, bytesRead);
            }
            bis.close();
            // Reset to beginning of input stream
            bis = new BufferedInputStream(new ByteArrayInputStream(report));
            ZipEntry entry = new ZipEntry("DunningLetters&Invoices-"
                    + getDateTimeService().toDateStringForFilename(getDateTimeService().getCurrentDate()) + ".pdf");
            entry.setMethod(ZipEntry.STORED);
            entry.setCompressedSize(report.length);
            entry.setSize(report.length);
            entry.setCrc(crc.getValue());
            zos.putNextEntry(entry);
            while ((bytesRead = bis.read(buffer)) != -1) {
                zos.write(buffer, 0, bytesRead);
            }
            bis.close();
        }

        zos.close();
        return true;
    }

    /**
     * @see org.kuali.kfs.module.ar.report.service.ContractsGrantsInvoiceReportService#generateListOfInvoicesPdfToPrint(java.util.Collection)
     */
    public byte[] generateListOfInvoicesPdfToPrint(Collection<ContractsGrantsInvoiceDocument> list, byte[] report)
            throws DocumentException, IOException {
        Date runDate = new Date();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        generateCombinedPdfForInvoices(list, report, baos);
        return baos.toByteArray();
    }

    /**
     * Generates the pdf file for printing the invoices.
     *
     * @param list
     * @param outputStream
     * @throws DocumentException
     * @throws IOException
     */
    protected void generateCombinedPdfForInvoices(Collection<ContractsGrantsInvoiceDocument> list, byte[] report,
            OutputStream outputStream) throws DocumentException, IOException {
        PdfCopyFields copy = new PdfCopyFields(outputStream);
        copy.open();
        copy.addDocument(new PdfReader(report));
        for (ContractsGrantsInvoiceDocument invoice : list) {
            for (InvoiceAddressDetail invoiceAddressDetail : invoice.getInvoiceAddressDetails()) {
                Note note = noteService.getNoteByNoteId(invoiceAddressDetail.getNoteId());
                if (ObjectUtils.isNotNull(note) && note.getAttachment().getAttachmentFileSize() > 0) {
                    copy.addDocument(new PdfReader(note.getAttachment().getAttachmentContents()));
                }
            }
        }
        copy.close();
    }

    /**
     *
     * @see org.kuali.kfs.module.ar.document.service.DunningLetterDistributionService#isValidOrganizationForTemplate(org.kuali.kfs.module.ar.businessobject.DunningLetterTemplate, org.kuali.rice.kim.api.identity.Person)
     */
    @Override
    public boolean isValidOrganizationForTemplate(DunningLetterTemplate template, Person user) {
        final ChartOrgHolder userChartOrg = getFinancialSystemUserService().getPrimaryOrganization(user,
                ArConstants.AR_NAMESPACE_CODE);

        if (!StringUtils.isBlank(template.getBillByChartOfAccountCode())
                && !StringUtils.isBlank(template.getBilledByOrganizationCode())) {
            return StringUtils.equals(template.getBillByChartOfAccountCode(), userChartOrg.getChartOfAccountsCode())
                    && StringUtils.equals(template.getBilledByOrganizationCode(),
                            userChartOrg.getOrganizationCode());
        }
        return false;
    }

    /**
     * @see org.kuali.kfs.module.ar.document.service.DunningLetterDistributionService#getPopulatedDunningLetterDistributionLookupResults(java.util.Collection)
     */
    @Override
    public Collection<GenerateDunningLettersLookupResult> getPopulatedGenerateDunningLettersLookupResults(
            Collection<ContractsGrantsInvoiceDocument> invoices) {
        Collection<GenerateDunningLettersLookupResult> populatedGenerateDunningLettersLookupResults = new ArrayList<GenerateDunningLettersLookupResult>();

        if (CollectionUtils.isEmpty(invoices)) {
            return populatedGenerateDunningLettersLookupResults;
        }

        Iterator iter = getContractsGrantsInvoiceDocumentService().getInvoicesByAward(invoices).entrySet()
                .iterator();
        GenerateDunningLettersLookupResult generateDunningLettersLookupResult = null;
        while (iter.hasNext()) {

            Map.Entry entry = (Map.Entry) iter.next();
            List<ContractsGrantsInvoiceDocument> list = (List<ContractsGrantsInvoiceDocument>) entry.getValue();

            if (CollectionUtils.isNotEmpty(list)) {
                // Get data from first award for agency data
                ContractsGrantsInvoiceDocument document = list.get(0);
                ContractsAndGrantsBillingAward award = document.getInvoiceGeneralDetail().getAward();
                if (ObjectUtils.isNotNull(award) && !award.isStopWorkIndicator()) {
                    generateDunningLettersLookupResult = new GenerateDunningLettersLookupResult();
                    generateDunningLettersLookupResult.setProposalNumber(award.getProposalNumber());
                    generateDunningLettersLookupResult.setInvoiceDocumentNumber(document.getDocumentNumber());
                    generateDunningLettersLookupResult.setAgencyNumber(award.getAgencyNumber());
                    generateDunningLettersLookupResult
                            .setCustomerNumber(document.getAccountsReceivableDocumentHeader().getCustomerNumber());
                    generateDunningLettersLookupResult.setAwardTotal(award.getAwardTotalAmount());
                    generateDunningLettersLookupResult.setCampaignID(award.getDunningCampaign());
                    if (CollectionUtils.isNotEmpty(document.getAccountDetails())) {
                        generateDunningLettersLookupResult
                                .setAccountNumber(document.getAccountDetails().get(0).getAccountNumber());
                    }
                    generateDunningLettersLookupResult.setInvoices(list);

                    populatedGenerateDunningLettersLookupResults.add(generateDunningLettersLookupResult);
                }
            }
        }

        return populatedGenerateDunningLettersLookupResults;
    }

    /**
     * Maps the given ContractsGrantsInvoiceDocuments by their agency number
     * @param invoices the invoices to Map to agency number
     * @return the Map of the invoices
     */
    protected Map<Long, List<ContractsGrantsInvoiceDocument>> getInvoicesByAward(
            Collection<ContractsGrantsInvoiceDocument> invoices) {
        Map<Long, List<ContractsGrantsInvoiceDocument>> invoicesByAward = new HashMap<Long, List<ContractsGrantsInvoiceDocument>>();
        for (ContractsGrantsInvoiceDocument invoice : invoices) {
            Long proposalNumber = invoice.getInvoiceGeneralDetail().getProposalNumber();
            if (invoicesByAward.containsKey(proposalNumber)) {
                invoicesByAward.get(proposalNumber).add(invoice);
            } else {
                List<ContractsGrantsInvoiceDocument> invoicesByProposalNumber = new ArrayList<ContractsGrantsInvoiceDocument>();
                invoicesByProposalNumber.add(invoice);
                invoicesByAward.put(proposalNumber, invoicesByProposalNumber);
            }
        }
        return invoicesByAward;
    }

    /**
     * Gets the businessObjectService attribute.
     *
     * @return Returns the businessObjectService.
     */
    public BusinessObjectService getBusinessObjectService() {
        return businessObjectService;
    }

    /**
     * Sets the businessObjectService attribute value.
     *
     * @param businessObjectService The businessObjectService to set.
     */
    public void setBusinessObjectService(BusinessObjectService businessObjectService) {
        this.businessObjectService = businessObjectService;
    }

    /**
     * Gets the contractsGrantsInvoiceDocumentDao attribute.
     *
     * @return Returns the contractsGrantsInvoiceDocumentDao.
     */
    public ContractsGrantsInvoiceDocumentDao getContractsGrantsInvoiceDocumentDao() {
        return contractsGrantsInvoiceDocumentDao;
    }

    /**
     * Sets the contractsGrantsInvoiceDocumentDao attribute value.
     *
     * @param contractsGrantsInvoiceDocumentDao The contractsGrantsInvoiceDocumentDao to set.
     */
    public void setContractsGrantsInvoiceDocumentDao(
            ContractsGrantsInvoiceDocumentDao contractsGrantsInvoiceDocumentDao) {
        this.contractsGrantsInvoiceDocumentDao = contractsGrantsInvoiceDocumentDao;
    }

    public DateTimeService getDateTimeService() {
        return dateTimeService;
    }

    public void setDateTimeService(DateTimeService dateTimeService) {
        this.dateTimeService = dateTimeService;
    }

    /**
     * Sets the kualiModuleService attribute value.
     *
     * @param kualiModuleService The kualiModuleService to set.
     */
    public void setKualiModuleService(KualiModuleService kualiModuleService) {
        this.kualiModuleService = kualiModuleService;
    }

    public NoteService getNoteService() {
        return noteService;
    }

    public void setNoteService(NoteService noteService) {
        this.noteService = noteService;
    }

    public FinancialSystemUserService getFinancialSystemUserService() {
        return financialSystemUserService;
    }

    public void setFinancialSystemUserService(FinancialSystemUserService financialSystemUserService) {
        this.financialSystemUserService = financialSystemUserService;
    }

    public ContractsGrantsBillingUtilityService getContractsGrantsBillingUtilityService() {
        return contractsGrantsBillingUtilityService;
    }

    public void setContractsGrantsBillingUtilityService(
            ContractsGrantsBillingUtilityService contractsGrantsBillingUtilityService) {
        this.contractsGrantsBillingUtilityService = contractsGrantsBillingUtilityService;
    }

    public ContractsGrantsInvoiceDocumentService getContractsGrantsInvoiceDocumentService() {
        return contractsGrantsInvoiceDocumentService;
    }

    public void setContractsGrantsInvoiceDocumentService(
            ContractsGrantsInvoiceDocumentService contractsGrantsInvoiceDocumentService) {
        this.contractsGrantsInvoiceDocumentService = contractsGrantsInvoiceDocumentService;
    }

    public ParameterService getParameterService() {
        return parameterService;
    }

    public void setParameterService(ParameterService parameterService) {
        this.parameterService = parameterService;
    }
}