/*
* 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.ec.document.web.struts;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.coa.businessobject.Account;
import org.kuali.kfs.coa.businessobject.Chart;
import org.kuali.kfs.coa.businessobject.ObjectCode;
import org.kuali.kfs.coa.businessobject.SubAccount;
import org.kuali.kfs.coa.service.AccountService;
import org.kuali.kfs.integration.cg.ContractsAndGrantsModuleService;
import org.kuali.kfs.module.ec.EffortConstants;
import org.kuali.kfs.module.ec.EffortPropertyConstants;
import org.kuali.kfs.module.ec.businessobject.EffortCertificationDetail;
import org.kuali.kfs.module.ec.businessobject.EffortCertificationDetailLineOverride;
import org.kuali.kfs.module.ec.businessobject.inquiry.EffortLedgerBalanceInquirableImpl;
import org.kuali.kfs.module.ec.businessobject.inquiry.EffortPositionDataDetailsInquirableImpl;
import org.kuali.kfs.module.ec.document.EffortCertificationDocument;
import org.kuali.kfs.module.ec.util.PayrollAmountHolder;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.document.web.struts.FinancialSystemTransactionalDocumentFormBase;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.kim.api.identity.Person;
import org.kuali.rice.kns.inquiry.Inquirable;
import org.kuali.rice.kns.lookup.HtmlData;
import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
import org.kuali.rice.kns.lookup.LookupUtils;
import org.kuali.rice.krad.bo.BusinessObject;
import org.kuali.rice.krad.bo.DataObjectRelationship;
import org.kuali.rice.krad.service.PersistenceStructureService;
import org.kuali.rice.krad.util.ObjectUtils;
/**
* Action form for Effort Certification Document.
*/
public class EffortCertificationForm extends FinancialSystemTransactionalDocumentFormBase {
protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(EffortCertificationForm.class);
protected EffortCertificationDetail newDetailLine;
/**
* Constructs a EffortCertificationForm.java.
*/
public EffortCertificationForm() {
super();
this.setNewDetailLine(this.createNewDetailLine());
}
@Override
protected String getDefaultDocumentTypeName() {
return EffortConstants.EffortDocumentTypes.EFFORT_CERTIFICATION_DOCUMENT;
}
/**
* initialize a new detail line
* @return the initialized detail line
*/
public EffortCertificationDetail createNewDetailLine() {
EffortCertificationDetail detailLine = new EffortCertificationDetail();
detailLine.setEffortCertificationUpdatedOverallPercent(null);
detailLine.setEffortCertificationPayrollAmount(null);
detailLine.setSubAccountNumber(null);
return detailLine;
}
/**
* @return new detail line
*/
public EffortCertificationDetail getNewDetailLine() {
return newDetailLine;
}
/**
* Sets the new detail line
*
* @param newDetailLine
*/
public void setNewDetailLine(EffortCertificationDetail newDetailLine) {
this.newDetailLine = newDetailLine;
}
/**
* Gets the effortCertificationDocument attribute.
*
* @return Returns the effortCertificationDocument.
*/
public EffortCertificationDocument getEffortCertificationDocument() {
return (EffortCertificationDocument) this.getDocument();
}
/**
* @see org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase#populate(javax.servlet.http.HttpServletRequest)
*/
@Override
public void populate(HttpServletRequest request) {
super.populate(request);
for (EffortCertificationDetail detailLine : this.getDetailLines()) {
EffortCertificationDetailLineOverride.populateFromInput(detailLine);
}
}
/**
* Gets the detailLines attribute.
*
* @return Returns the detailLines.
*/
public List<EffortCertificationDetail> getDetailLines() {
EffortCertificationDocument effortCertificationDocument = (EffortCertificationDocument) this.getDocument();
return effortCertificationDocument.getEffortCertificationDetailLines();
}
/**
* get the relationship metadata for the detail line fields
*
* @return the relationship metadata for the detail line fields
*/
public Map<String, DataObjectRelationship> getRelationshipMetadata() {
LOG.debug("getRelationshipMetadata() start");
PersistenceStructureService persistenceStructureService = SpringContext.getBean(PersistenceStructureService.class);
Map<String, DataObjectRelationship> relationshipMetadata = new HashMap<String, DataObjectRelationship>();
for (String attributeName : this.getInquirableFieldNames()) {
Map<String, Class<? extends BusinessObject>> primitiveReference = LookupUtils.getPrimitiveReference(newDetailLine, attributeName);
if (primitiveReference != null && !primitiveReference.isEmpty()) {
DataObjectRelationship primitiveRelationship = this.getPrimitiveDataObjectRelationship(persistenceStructureService.getRelationshipMetadata(newDetailLine.getClass(), attributeName));
relationshipMetadata.put(attributeName, primitiveRelationship);
}
}
return relationshipMetadata;
}
/**
* Gets the inquiryUrl attribute.
*
* @return Returns the inquiryUrl for the detail lines in the document.
*/
public List<Map<String, HtmlData>> getDetailLineFieldInquiryUrl() {
LOG.debug("getDetailLineFieldInquiryUrl() start");
return this.getDetailLineFieldInquiryUrl(this.getDetailLines());
}
/**
* Gets the fieldInfo attribute.
*
* @return Returns the fieldInfo.
*/
public List<Map<String, String>> getFieldInfo() {
LOG.debug("getFieldInfo() start");
return this.getFieldInfo(this.getDetailLines());
}
/**
* pick up the primitive relationship for an attribute from a set of relationships. Generally, the primitive relationship is
* that has the minimum number of primary keys.
*
* @param relationshipMetadata the relationship metadata that contains the primitive relationship
* @return the primitive relationship for an attribute from a set of relationships.
*/
protected DataObjectRelationship getPrimitiveDataObjectRelationship(Map<String, DataObjectRelationship> relationshipMetadata) {
int minCountOfKeys = Integer.MAX_VALUE;
DataObjectRelationship primitiveRelationship = null;
for (String attribute : relationshipMetadata.keySet()) {
DataObjectRelationship currentRelationship = relationshipMetadata.get(attribute);
Map<String, String> parentToChildReferences = currentRelationship.getParentToChildReferences();
if (parentToChildReferences.size() < minCountOfKeys) {
minCountOfKeys = parentToChildReferences.size();
primitiveRelationship = currentRelationship;
}
}
return primitiveRelationship;
}
/**
* Gets the inquiryUrl attribute.
*
* @return Returns the inquiryUrl for the detail lines in the document.
*/
protected List<Map<String, HtmlData>> getDetailLineFieldInquiryUrl(List<EffortCertificationDetail> detailLines) {
LOG.debug("getDetailLineFieldInquiryUrl(List<EffortCertificationDetail>) start");
Map<String, String> noninquirableFieldValues = this.getNoninquirableFieldValues();
Inquirable inquirable = this.getInquirable();
List<Map<String, HtmlData>> inquiryURL = new ArrayList<Map<String, HtmlData>>();
for (EffortCertificationDetail detailLine : detailLines) {
detailLine.refreshNonUpdateableReferences();
Map<String, HtmlData> inquiryURLForAttribute = new HashMap<String, HtmlData>();
for (String attributeName : this.getInquirableFieldNames()) {
// exclude the non inquirable field values
Object attributeValue = ObjectUtils.getPropertyValue(detailLine, attributeName);
String noninquirableFieldValue = noninquirableFieldValues.get(attributeName);
if(noninquirableFieldValue!=null && noninquirableFieldValue.equals(attributeValue)) {
continue;
}
HtmlData inquiryHref;
if (this.getCustomizedInquirableFieldNames().contains(attributeName)) {
inquiryHref = this.getCustomizedInquiryUrl(detailLine, attributeName);
}
else {
inquiryHref = inquirable.getInquiryUrl(detailLine, attributeName, false);
}
inquiryURLForAttribute.put(attributeName, inquiryHref);
}
inquiryURL.add(inquiryURLForAttribute);
}
return inquiryURL;
}
/**
* get the inquiry URL for the specified attribute
*
* @param detailLine the detail line containing the given attribute
* @param attributeName the specified attribute name
* @return the inquiry URL for the specified attribute
*/
protected HtmlData getCustomizedInquiryUrl(EffortCertificationDetail detailLine, String attributeName) {
if (StringUtils.equals(attributeName, KFSPropertyConstants.POSITION_NUMBER)) {
AnchorHtmlData inquiryHref = (AnchorHtmlData) getEffortPositionDataDetailsInquirableImpl().getInquiryUrl(detailLine, attributeName);
inquiryHref.setHref(this.getCompleteURL(inquiryHref.getHref()));
return inquiryHref;
}
AnchorHtmlData inquiryHref = (AnchorHtmlData) getInquirable().getInquiryUrl(detailLine, attributeName, false);
inquiryHref.setHref(this.getCompleteURL(inquiryHref.getHref()));
return inquiryHref;
}
/**
* Gets the inquirableFieldNames attribute.
*
* @return Returns the inquirableFieldNames.
*/
public Map<String, String> getNoninquirableFieldValues() {
Map<String, String> inquirableFieldNames = new HashMap<String, String>();
inquirableFieldNames.put(KFSPropertyConstants.SUB_ACCOUNT_NUMBER, KFSConstants.getDashSubAccountNumber());
inquirableFieldNames.put(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, KFSConstants.getDashFinancialObjectCode());
inquirableFieldNames.put(KFSPropertyConstants.POSITION_NUMBER, EffortConstants.DASH_POSITION_NUMBER);
inquirableFieldNames.put(EffortPropertyConstants.SOURCE_CHART_OF_ACCOUNTS_CODE, EffortConstants.DASH_CHART_OF_ACCOUNTS_CODE);
inquirableFieldNames.put(EffortPropertyConstants.SOURCE_ACCOUNT_NUMBER, EffortConstants.DASH_ACCOUNT_NUMBER);
inquirableFieldNames.put(EffortPropertyConstants.COST_SHARE_SOURCE_SUB_ACCOUNT_NUMBER, KFSConstants.getDashSubAccountNumber());
return inquirableFieldNames;
}
/**
* Gets the inquirableFieldNames attribute.
*
* @return Returns the inquirableFieldNames.
*/
public List<String> getInquirableFieldNames() {
List<String> inquirableFieldNames = new ArrayList<String>();
inquirableFieldNames.add(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE);
inquirableFieldNames.add(KFSPropertyConstants.ACCOUNT_NUMBER);
inquirableFieldNames.add(KFSPropertyConstants.SUB_ACCOUNT_NUMBER);
inquirableFieldNames.add(KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
inquirableFieldNames.add(KFSPropertyConstants.POSITION_NUMBER);
inquirableFieldNames.add(EffortPropertyConstants.SOURCE_CHART_OF_ACCOUNTS_CODE);
inquirableFieldNames.add(EffortPropertyConstants.SOURCE_ACCOUNT_NUMBER);
inquirableFieldNames.add(EffortPropertyConstants.COST_SHARE_SOURCE_SUB_ACCOUNT_NUMBER);
inquirableFieldNames.add(EffortPropertyConstants.EFFORT_CERTIFICATION_ORIGINAL_PAYROLL_AMOUNT);
inquirableFieldNames.add(EffortPropertyConstants.EFFORT_CERTIFICATION_PAYROLL_AMOUNT);
return inquirableFieldNames;
}
/**
* get the inquirable field names that need to be handled specially
*
* @return the inquirable field names that need to be handled specially
*/
public List<String> getCustomizedInquirableFieldNames() {
List<String> inquirableFieldNames = new ArrayList<String>();
inquirableFieldNames.add(KFSPropertyConstants.POSITION_NUMBER);
inquirableFieldNames.add(EffortPropertyConstants.EFFORT_CERTIFICATION_ORIGINAL_PAYROLL_AMOUNT);
inquirableFieldNames.add(EffortPropertyConstants.EFFORT_CERTIFICATION_PAYROLL_AMOUNT);
return inquirableFieldNames;
}
/**
* append the extract query string into the given base URL
*
* @param baseURL the given base URL. If the parameter is blank, the base URL won't be changed
* @return the complete URL built from the given base URL and extra query strings
*/
protected String getCompleteURL(String baseURL) {
if (StringUtils.isBlank(baseURL)) {
return baseURL;
}
String completeURL = baseURL;
EffortCertificationDocument document = (EffortCertificationDocument) this.getDocument();
Properties properties = new Properties();
properties.put(KFSPropertyConstants.EMPLID, document.getEmplid());
properties.put(EffortPropertyConstants.EFFORT_CERTIFICATION_REPORT_NUMBER, document.getEffortCertificationReportNumber());
properties.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, document.getUniversityFiscalYear());
StringBuilder queryString = new StringBuilder();
for (Object key : properties.keySet()) {
queryString.append("&").append(key).append("=").append(properties.get(key));
}
return completeURL.concat(queryString.toString());
}
/**
* Gets the fieldInfo attribute.
*
* @return Returns the fieldInfo.
*/
protected Map<String, String> getFieldInfo(EffortCertificationDetail detailLine) {
LOG.info("getFieldInfo(List<EffortCertificationDetail>) start");
//Map<String, String> fieldInfo = new HashMap<String, String>();
EffortCertificationDocument document = (EffortCertificationDocument) this.getDocument();
KualiDecimal totalOriginalPayrollAmount = document.getTotalOriginalPayrollAmount();
detailLine.refreshNonUpdateableReferences();
Map<String, String> fieldInfoForAttribute = new HashMap<String, String>();
fieldInfoForAttribute.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, ObjectUtils.isNotNull(detailLine.getChartOfAccounts())? detailLine.getChartOfAccounts().getFinChartOfAccountDescription(): "");
String accountInfo = buildAccountInfo(detailLine.getAccount());
fieldInfoForAttribute.put(KFSPropertyConstants.ACCOUNT_NUMBER, accountInfo);
SubAccount subAccount = detailLine.getSubAccount();
if (ObjectUtils.isNotNull(subAccount)) {
fieldInfoForAttribute.put(KFSPropertyConstants.SUB_ACCOUNT_NUMBER, subAccount.getSubAccountName());
}
ObjectCode objectCode = detailLine.getFinancialObject();
if (ObjectUtils.isNotNull(objectCode)) {
fieldInfoForAttribute.put(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, objectCode.getFinancialObjectCodeName());
}
Account sourceAccount = detailLine.getSourceAccount();
if (ObjectUtils.isNotNull(sourceAccount)) {
fieldInfoForAttribute.put(EffortPropertyConstants.SOURCE_ACCOUNT_NUMBER, sourceAccount.getAccountName());
}
Chart sourceChart = detailLine.getSourceChartOfAccounts();
if (ObjectUtils.isNotNull(sourceChart)) {
fieldInfoForAttribute.put(EffortPropertyConstants.SOURCE_CHART_OF_ACCOUNTS_CODE, sourceChart.getFinChartOfAccountDescription());
}
KualiDecimal originalPayrollAmount = detailLine.getEffortCertificationOriginalPayrollAmount();
String actualOriginalPercent = PayrollAmountHolder.recalculateEffortPercentAsString(totalOriginalPayrollAmount, originalPayrollAmount);
fieldInfoForAttribute.put(EffortPropertyConstants.EFFORT_CERTIFICATION_CALCULATED_OVERALL_PERCENT, actualOriginalPercent);
//fieldInfo.add(fieldInfoForAttribute);
return fieldInfoForAttribute;
}
/**
* Gets the fieldInfo attribute.
*
* @return Returns the fieldInfo.
*/
public Map<String, String> getDetailLineFieldInfo() {
LOG.info("getSummarizedDetailLineFieldInfo() start");
return this.getFieldInfo(this.getNewDetailLine());
}
/**
* Gets the fieldInfo attribute.
*
* @return Returns the fieldInfo.
*/
protected List<Map<String, String>> getFieldInfo(List<EffortCertificationDetail> detailLines) {
LOG.debug("getFieldInfo(List<EffortCertificationDetail>) start");
List<Map<String, String>> fieldInfo = new ArrayList<Map<String, String>>();
EffortCertificationDocument document = (EffortCertificationDocument) this.getDocument();
KualiDecimal totalOriginalPayrollAmount = document.getTotalOriginalPayrollAmount();
for (EffortCertificationDetail detailLine : detailLines) {
detailLine.refreshNonUpdateableReferences();
Map<String, String> fieldInfoForAttribute = new HashMap<String, String>();
fieldInfoForAttribute.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, detailLine.getChartOfAccounts().getFinChartOfAccountDescription());
String accountInfo = buildAccountInfo(detailLine.getAccount());
fieldInfoForAttribute.put(KFSPropertyConstants.ACCOUNT_NUMBER, accountInfo);
SubAccount subAccount = detailLine.getSubAccount();
if (ObjectUtils.isNotNull(subAccount)) {
fieldInfoForAttribute.put(KFSPropertyConstants.SUB_ACCOUNT_NUMBER, subAccount.getSubAccountName());
}
ObjectCode objectCode = detailLine.getFinancialObject();
if (ObjectUtils.isNotNull(objectCode)) {
fieldInfoForAttribute.put(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, objectCode.getFinancialObjectCodeName());
}
Account sourceAccount = detailLine.getSourceAccount();
if (ObjectUtils.isNotNull(sourceAccount)) {
fieldInfoForAttribute.put(EffortPropertyConstants.SOURCE_ACCOUNT_NUMBER, sourceAccount.getAccountName());
}
Chart sourceChart = detailLine.getSourceChartOfAccounts();
if (ObjectUtils.isNotNull(sourceChart)) {
fieldInfoForAttribute.put(EffortPropertyConstants.SOURCE_CHART_OF_ACCOUNTS_CODE, sourceChart.getFinChartOfAccountDescription());
}
KualiDecimal originalPayrollAmount = detailLine.getEffortCertificationOriginalPayrollAmount();
String actualOriginalPercent = PayrollAmountHolder.recalculateEffortPercentAsString(totalOriginalPayrollAmount, originalPayrollAmount);
fieldInfoForAttribute.put(EffortPropertyConstants.EFFORT_CERTIFICATION_CALCULATED_OVERALL_PERCENT, actualOriginalPercent);
fieldInfo.add(fieldInfoForAttribute);
}
return fieldInfo;
}
/**
* get the inquirable implmentation
*
* @return the inquirable implmentation
*/
protected Inquirable getInquirable() {
return new EffortLedgerBalanceInquirableImpl();
}
/**
* get the EffortPositionDataDetailsInquirableImpl implmentation
*
* @return the EffortPositionDataDetailsInquirableImpl implmentation
*/
protected EffortPositionDataDetailsInquirableImpl getEffortPositionDataDetailsInquirableImpl() {
return new EffortPositionDataDetailsInquirableImpl();
}
/**
* build the descriptive information of the given account. The information includes account name and project director's name if
* any
*
* @param chartOfAccountsCode the given chart of accounts code
* @param accountNumber the given account number
* @return the descriptive information of the given account
*/
public static String buildAccountInfo(Account account) {
if (ObjectUtils.isNull(account)) {
return KFSConstants.EMPTY_STRING;
}
String projectDirectorName = KFSConstants.EMPTY_STRING;
try {
ContractsAndGrantsModuleService contractsAndGrantsModuleService = SpringContext.getBean(ContractsAndGrantsModuleService.class);
Person projectDirector = contractsAndGrantsModuleService.getProjectDirectorForAccount(account);
projectDirectorName = projectDirector != null ? MessageFormat.format(" ({0})", projectDirector.getName()) : KFSConstants.EMPTY_STRING;
}
catch (Exception e) {
LOG.error("Cannot find a project director for the account:" + account);
}
return MessageFormat.format("{0}{1}", account.getAccountName(), projectDirectorName);
}
/**
* load the descriptive information of the given account. This method is used by DWR.
*
* @param chartOfAccountsCode the given chart of accounts code
* @param accountNumber the given account number
* @return the descriptive information of the given account
*/
public static String loadAccountInfo(String chartOfAccountsCode, String accountNumber) {
Account account = SpringContext.getBean(AccountService.class).getByPrimaryIdWithCaching(chartOfAccountsCode, accountNumber);
return buildAccountInfo(account);
}
}