/*
* 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.batch.service.impl;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.collections.CollectionUtils;
import org.kuali.kfs.module.ar.ArConstants;
import org.kuali.kfs.module.ar.ArKeyConstants;
import org.kuali.kfs.module.ar.ArPropertyConstants;
import org.kuali.kfs.module.ar.batch.service.LetterOfCreditCreateService;
import org.kuali.kfs.module.ar.businessobject.AccountsReceivableDocumentHeader;
import org.kuali.kfs.module.ar.businessobject.CashControlDetail;
import org.kuali.kfs.module.ar.document.CashControlDocument;
import org.kuali.kfs.module.ar.document.ContractsGrantsInvoiceDocument;
import org.kuali.kfs.module.ar.document.PaymentApplicationDocument;
import org.kuali.kfs.module.ar.document.service.CashControlDocumentService;
import org.kuali.kfs.module.ar.document.service.ContractsGrantsInvoiceDocumentService;
import org.kuali.kfs.module.ar.document.service.PaymentApplicationDocumentService;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.document.service.FinancialSystemDocumentService;
import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
import org.kuali.kfs.sys.service.NonTransactional;
import org.kuali.rice.core.api.config.property.ConfigurationService;
import org.kuali.rice.core.api.datetime.DateTimeService;
import org.kuali.rice.core.api.search.SearchOperator;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kew.api.exception.WorkflowException;
import org.kuali.rice.krad.service.DocumentService;
import org.kuali.rice.krad.service.KualiModuleService;
import org.kuali.rice.krad.util.ObjectUtils;
import org.kuali.rice.krad.workflow.service.WorkflowDocumentService;
import org.springframework.transaction.annotation.Transactional;
/**
* Defines a service class for creating Cash Control documents from the LOC Review Document.
*/
@NonTransactional
public class LetterOfCreditCreateServiceImpl implements LetterOfCreditCreateService {
private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LetterOfCreditCreateServiceImpl.class);
protected CashControlDocumentService cashControlDocumentService;
protected ConfigurationService configService;
protected ContractsGrantsInvoiceDocumentService contractsGrantsInvoiceDocumentService;
protected DateTimeService dateTimeService;
protected DocumentService documentService;
protected FinancialSystemDocumentService financialSystemDocumentService;
protected GeneralLedgerPendingEntryService generalLedgerPendingEntryService;
protected KualiModuleService kualiModuleService;
protected ParameterService parameterService;
protected WorkflowDocumentService workflowDocumentService;
protected PaymentApplicationDocumentService paymentApplicationDocumentService;
/**
* @see org.kuali.kfs.module.ar.batch.service.LetterOfCreditCreateService#routeCashControlDocument(org.kuali.kfs.module.ar.document.CashControlDocument, java.io.PrintWriter)
*/
@Override
@Transactional
public void routeCashControlDocument(CashControlDocument cashControlDocument, PrintWriter errorFile) {
try {
if (LOG.isInfoEnabled()) {
LOG.info("Routing Cash control document # " + cashControlDocument.getDocumentNumber() + ".");
}
documentService.prepareWorkflowDocument(cashControlDocument);
// calling workflow service to bypass business rule checks
workflowDocumentService.route(cashControlDocument.getDocumentHeader().getWorkflowDocument(), "", null);
}
catch (WorkflowException e) {
final String errorString = "Error routing document # " + cashControlDocument.getDocumentNumber();
errorFile.println(errorString);
LOG.error(errorString + " " + e.getMessage());
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* @see org.kuali.kfs.module.ar.batch.service.LetterOfCreditCreateService#processLettersOfCreditByFund(java.lang.String)
*/
@Override
public void processLettersOfCredit(String batchFileDirectoryName) {
String customerNumber = null;
String locValue = null;
String locCreationType = null;
boolean cashControlDocumentExists = false;
String runtimeStamp = dateTimeService.toDateTimeStringForFilename(new java.util.Date());
String errOutputFile = batchFileDirectoryName + File.separator + ArConstants.BatchFileSystem.LOC_CREATION_BY_LOCF_ERROR_OUTPUT_FILE + "_" + runtimeStamp + ArConstants.BatchFileSystem.EXTENSION;
File errOutPutFile = new File(errOutputFile);
PrintWriter errorFile = null;
try {
errorFile = new PrintWriter(errOutPutFile);
Collection<ContractsGrantsInvoiceDocument> cgInvoices = retrieveLetterOfCreditInvoices();
if (CollectionUtils.isNotEmpty(cgInvoices)) {
CashControlDocument cashControlDoc = createCashControlDocument(errorFile);
for (ContractsGrantsInvoiceDocument cgInvoice : cgInvoices) {
if (cgInvoice.getOpenAmount().isGreaterThan(KualiDecimal.ZERO)) {
processLetterOfCreditInvoice(cgInvoice, cashControlDoc, errorFile);
} else {
String errorString = configService.getPropertyValueAsString(ArKeyConstants.LOC_CREATION_ERROR_INVOICE_PAID);
errorFile.println(MessageFormat.format(errorString, cgInvoice.getDocumentNumber()));
}
}
routeCashControlDocument(cashControlDoc, errorFile);
} else {
String errorString = configService.getPropertyValueAsString(ArKeyConstants.LOC_CREATION_ERROR_NO_INVOICES_TO_PROCESS);
errorFile.println(errorString);
}
} catch (FileNotFoundException fnfe) {
throw new RuntimeException("Could not write to file in "+batchFileDirectoryName, fnfe);
} finally {
// Close the error file.
if (errorFile != null) {
errorFile.close();
}
}
}
/**
* @see org.kuali.kfs.module.ar.batch.service.LetterOfCreditCreateService#processLetterOfCreditInvoice(org.kuali.kfs.module.ar.document.ContractsGrantsInvoiceDocument, org.kuali.kfs.module.ar.document.CashControlDocument, java.io.PrintWriter)
*/
@Override
@Transactional
public void processLetterOfCreditInvoice(ContractsGrantsInvoiceDocument cgInvoice, CashControlDocument cashControlDoc, PrintWriter errorFile) {
CashControlDetail cashControlDetail = createCashControlDetail(cgInvoice);
try {
cashControlDocumentService.addNewCashControlDetail(configService.getPropertyValueAsString(ArKeyConstants.CREATED_BY_CASH_CTRL_DOC), cashControlDoc, cashControlDetail);
String payAppDocNumber = cashControlDetail.getReferenceFinancialDocumentNumber();
PaymentApplicationDocument payAppDoc;
payAppDoc = (PaymentApplicationDocument) documentService.getByDocumentHeaderId(payAppDocNumber);
payAppDoc = paymentApplicationDocumentService.createInvoicePaidAppliedsForEntireInvoiceDocument(cgInvoice, payAppDoc);
getGeneralLedgerPendingEntryService().generateGeneralLedgerPendingEntries(payAppDoc);
documentService.saveDocument(payAppDoc);
if (LOG.isInfoEnabled()) {
LOG.info("Routing Payment Application document # " + payAppDoc.getDocumentNumber() + ".");
}
documentService.prepareWorkflowDocument(payAppDoc);
// calling workflow service to bypass business rule checks
workflowDocumentService.route(payAppDoc.getDocumentHeader().getWorkflowDocument(), "", null);
} catch (WorkflowException ex) {
String error = "Error creating Cash Control Detail/Payment Application Document, Cash Control doc # " + cashControlDoc.getDocumentNumber();
errorFile.println(error);
LOG.error(error + " " + ex.getMessage());
throw new RuntimeException(ex.getMessage(), ex);
}
}
/**
* @see org.kuali.kfs.module.ar.batch.service.LetterOfCreditCreateService#createCashControlDocument(java.io.PrintWriter)
*/
@Override
@Transactional
public CashControlDocument createCashControlDocument(PrintWriter errorFile) {
CashControlDocument cashControlDoc = null;
try {
cashControlDoc = (CashControlDocument) documentService.getNewDocument(CashControlDocument.class);
cashControlDoc.getDocumentHeader().setDocumentDescription(configService.getPropertyValueAsString(ArKeyConstants.CASH_CTRL_DOC_CREATED_BY_BATCH));
AccountsReceivableDocumentHeader accountsReceivableDocumentHeader = new AccountsReceivableDocumentHeader();
accountsReceivableDocumentHeader.setDocumentNumber(cashControlDoc.getDocumentNumber());
String defaultProcessingChartCode = parameterService.getParameterValueAsString(CashControlDocument.class, ArConstants.DEFAULT_PROCESSING_CHART);
String defaultProcessingOrgCode = parameterService.getParameterValueAsString(CashControlDocument.class, ArConstants.DEFAULT_PROCESSING_ORG);
accountsReceivableDocumentHeader.setProcessingChartOfAccountCode(defaultProcessingChartCode);
accountsReceivableDocumentHeader.setProcessingOrganizationCode(defaultProcessingOrgCode);
cashControlDoc.setAccountsReceivableDocumentHeader(accountsReceivableDocumentHeader);
cashControlDoc.setCustomerPaymentMediumCode(ArConstants.PaymentMediumCode.WIRE_TRANSFER);
documentService.saveDocument(cashControlDoc);
} catch (WorkflowException ex) {
String error = "Error creating Cash Control Document, Cash Control doc # " + (ObjectUtils.isNotNull(cashControlDoc)?cashControlDoc.getDocumentNumber():null);
errorFile.println(error);
LOG.error(error + " " + ex.getMessage());
throw new RuntimeException(ex.getMessage(), ex);
}
return cashControlDoc;
}
/**
* This method created cashcontrol documents and payment application based on the loc creation type and loc value passed.
*
* @param contractsGrantsInvoiceDocument
* @return
*/
protected CashControlDetail createCashControlDetail(ContractsGrantsInvoiceDocument contractsGrantsInvoiceDocument) {
CashControlDetail cashControlDetail = new CashControlDetail();
cashControlDetail.setCustomerNumber(contractsGrantsInvoiceDocument.getAccountsReceivableDocumentHeader().getCustomerNumber());
cashControlDetail.setFinancialDocumentLineAmount(contractsGrantsInvoiceDocument.getOpenAmount());
Timestamp ts = new Timestamp(new java.util.Date().getTime());
java.sql.Date today = new java.sql.Date(ts.getTime());
cashControlDetail.setCustomerPaymentDate(today);
return cashControlDetail;
}
/**
* Retrieves ContractsAndGrantsInvoiceDocument documents which are open and which have the given letter of credit fund and letter of credit creation type (either fund or fund group)
* @return a Collection of matching letter of credit created Contracts & Grants Invoices
*/
protected Collection<ContractsGrantsInvoiceDocument> retrieveLetterOfCreditInvoices() {
Map<String, String> fieldValues = new HashMap<>();
fieldValues.put(ArPropertyConstants.ContractsGrantsInvoiceDocumentFields.LETTER_OF_CREDIT_CREATION_TYPE, SearchOperator.NOT_NULL.op());
fieldValues.put(ArPropertyConstants.OPEN_INVOICE_IND, KFSConstants.Booleans.TRUE);
fieldValues.put(ArPropertyConstants.DOCUMENT_STATUS_CODE, KFSConstants.DocumentStatusCodes.APPROVED);
Collection<ContractsGrantsInvoiceDocument> cgInvoices = contractsGrantsInvoiceDocumentService.retrieveAllCGInvoicesByCriteria(fieldValues);
return cgInvoices;
}
/**
* Gets the documentService attribute.
*
* @return Returns the documentService.
*/
public DocumentService getDocumentService() {
return documentService;
}
/**
* Sets the documentService attribute value.
*
* @param documentService The documentService to set.
*/
public void setDocumentService(DocumentService documentService) {
this.documentService = documentService;
}
/**
* Gets the cashControlDocumentService attribute.
*
* @return Returns the cashControlDocumentService.
*/
public CashControlDocumentService getCashControlDocumentService() {
return cashControlDocumentService;
}
/**
* Sets the cashControlDocumentService attribute value.
*
* @param cashControlDocumentService The cashControlDocumentService to set.
*/
public void setCashControlDocumentService(CashControlDocumentService cashControlDocumentService) {
this.cashControlDocumentService = cashControlDocumentService;
}
public WorkflowDocumentService getWorkflowDocumentService() {
return workflowDocumentService;
}
public void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) {
this.workflowDocumentService = workflowDocumentService;
}
public FinancialSystemDocumentService getFinancialSystemDocumentService() {
return financialSystemDocumentService;
}
public void setFinancialSystemDocumentService(FinancialSystemDocumentService financialSystemDocumentService) {
this.financialSystemDocumentService = financialSystemDocumentService;
}
public DateTimeService getDateTimeService() {
return dateTimeService;
}
public void setDateTimeService(DateTimeService dateTimeService) {
this.dateTimeService = dateTimeService;
}
public ContractsGrantsInvoiceDocumentService getContractsGrantsInvoiceDocumentService() {
return contractsGrantsInvoiceDocumentService;
}
public void setContractsGrantsInvoiceDocumentService(ContractsGrantsInvoiceDocumentService contractsGrantsInvoiceDocumentService) {
this.contractsGrantsInvoiceDocumentService = contractsGrantsInvoiceDocumentService;
}
public GeneralLedgerPendingEntryService getGeneralLedgerPendingEntryService() {
return generalLedgerPendingEntryService;
}
public void setGeneralLedgerPendingEntryService(GeneralLedgerPendingEntryService generalLedgerPendingEntryService) {
this.generalLedgerPendingEntryService = generalLedgerPendingEntryService;
}
public KualiModuleService getKualiModuleService() {
return kualiModuleService;
}
public void setKualiModuleService(KualiModuleService kualiModuleService) {
this.kualiModuleService = kualiModuleService;
}
public ConfigurationService getConfigService() {
return configService;
}
public void setConfigService(ConfigurationService configService) {
this.configService = configService;
}
public ParameterService getParameterService() {
return parameterService;
}
public void setParameterService(ParameterService parameterService) {
this.parameterService = parameterService;
}
public PaymentApplicationDocumentService getPaymentApplicationDocumentService() {
return paymentApplicationDocumentService;
}
public void setPaymentApplicationDocumentService(PaymentApplicationDocumentService paymentApplicationDocumentService) {
this.paymentApplicationDocumentService = paymentApplicationDocumentService;
}
}