/* * 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.validation.impl; import java.util.List; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.coa.businessobject.Account; import org.kuali.kfs.integration.ld.LaborModuleService; import org.kuali.kfs.module.ec.EffortConstants; import org.kuali.kfs.module.ec.EffortKeyConstants; import org.kuali.kfs.module.ec.EffortPropertyConstants; import org.kuali.kfs.module.ec.batch.service.EffortCertificationExtractService; import org.kuali.kfs.module.ec.businessobject.EffortCertificationDetail; import org.kuali.kfs.module.ec.businessobject.EffortCertificationDocumentBuild; import org.kuali.kfs.module.ec.businessobject.EffortCertificationReportDefinition; import org.kuali.kfs.module.ec.document.EffortCertificationDocument; import org.kuali.kfs.module.ec.document.validation.AddDetailLineRule; import org.kuali.kfs.module.ec.document.validation.CheckDetailLineAmountRule; import org.kuali.kfs.module.ec.document.validation.LoadDetailLineRule; import org.kuali.kfs.module.ec.document.validation.UpdateDetailLineRule; import org.kuali.kfs.module.ec.service.EffortCertificationDocumentService; import org.kuali.kfs.module.ec.service.EffortCertificationReportDefinitionService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.document.service.AccountingLineRuleHelperService; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.kns.rules.TransactionalDocumentRuleBase; import org.kuali.rice.kns.service.DataDictionaryService; import org.kuali.rice.krad.bo.Note; import org.kuali.rice.krad.datadictionary.DataDictionary; import org.kuali.rice.krad.document.Document; import org.kuali.rice.krad.rules.rule.event.ApproveDocumentEvent; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.ObjectUtils; /** * To define the rules that may be applied to the effort certification document, a transactional document */ public class EffortCertificationDocumentRules extends TransactionalDocumentRuleBase implements AddDetailLineRule<EffortCertificationDocument, EffortCertificationDetail>, UpdateDetailLineRule<EffortCertificationDocument, EffortCertificationDetail>, CheckDetailLineAmountRule<EffortCertificationDocument, EffortCertificationDetail>, LoadDetailLineRule<EffortCertificationDocument> { protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(EffortCertificationDocumentRules.class); protected EffortCertificationDocumentService effortCertificationDocumentService = SpringContext.getBean(EffortCertificationDocumentService.class); protected EffortCertificationReportDefinitionService effortCertificationReportDefinitionService = SpringContext.getBean(EffortCertificationReportDefinitionService.class); protected EffortCertificationExtractService effortCertificationExtractService = SpringContext.getBean(EffortCertificationExtractService.class); protected BusinessObjectService businessObjectService = SpringContext.getBean(BusinessObjectService.class); protected LaborModuleService laborModuleService = SpringContext.getBean(LaborModuleService.class); protected AccountingLineRuleHelperService accountingLineRuleHelperService = SpringContext.getBean(AccountingLineRuleHelperService.class); /** * @see org.kuali.kfs.module.ec.document.validation.AddDetailLineRule#processAddDetailLineRules(org.kuali.kfs.module.ec.document.EffortCertificationDocument, * org.kuali.kfs.module.ec.businessobject.EffortCertificationDetail) */ @Override public boolean processAddDetailLineRules(EffortCertificationDocument document, EffortCertificationDetail detailLine) { LOG.debug("processAddDetailLineRules() start"); document.refreshNonUpdateableReferences(); detailLine.refreshNonUpdateableReferences(); if (!this.checkDetailLineAttributes(detailLine)) { return false; } if(!this.processCheckDetailLineAmountRules(document, detailLine)) { return false; } List<String> comparableFields = EffortConstants.DETAIL_LINES_CONSOLIDATION_FILEDS; if (detailLine.isNewLineIndicator() && EffortCertificationDocumentRuleUtil.hasSameExistingLine(document, detailLine, comparableFields)) { reportError(EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, EffortKeyConstants.ERROR_LINE_EXISTS); return false; } if (EffortCertificationDocumentRuleUtil.hasClosedAccount(detailLine)) { reportError(EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, EffortKeyConstants.ERROR_ACCOUNT_CLOSED); return false; } if (detailLine.isNewLineIndicator() && !EffortCertificationDocumentRuleUtil.canExpiredAccountBeUsed(detailLine)) { Account account = detailLine.getAccount(); Account continuation = account.getContinuationAccount(); reportError(EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_ACCOUNT_EXPIRED, account.getAccountNumber(), continuation.getChartOfAccountsCode(), continuation.getAccountNumber()); return false; } return true; } /** * @see org.kuali.kfs.module.ec.document.validation.UpdateDetailLineRule#processUpdateDetailLineRules(org.kuali.kfs.module.ec.document.EffortCertificationDocument, * org.kuali.kfs.module.ec.businessobject.EffortCertificationDetail) */ @Override public boolean processUpdateDetailLineRules(EffortCertificationDocument document, EffortCertificationDetail detailLine) { LOG.debug("processUpdateDetailLineRules() start"); // Don't execute add rules unless this is a new line if (detailLine.isNewLineIndicator() && !this.processAddDetailLineRules(document, detailLine)) { return false; } if(!this.processCheckDetailLineAmountRules(document, detailLine)) { return false; } KualiDecimal originalTotalAmount = document.getTotalOriginalPayrollAmount(); if (EffortCertificationDocumentRuleUtil.isPayrollAmountOverChanged(detailLine, originalTotalAmount, EffortConstants.PERCENT_LIMIT_OF_LINE_SALARY_CHANGE)) { reportError(EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, EffortKeyConstants.ERROR_PAYROLL_AMOUNT_OVERCHANGED, (Double.valueOf(EffortConstants.PERCENT_LIMIT_OF_LINE_SALARY_CHANGE)).toString()); return false; } return true; } /** * @see org.kuali.rice.krad.rules.DocumentRuleBase#processCustomApproveDocumentBusinessRules(org.kuali.rice.krad.rule.event.ApproveDocumentEvent) */ @Override public boolean processCustomApproveDocumentBusinessRules(ApproveDocumentEvent approveEvent) { LOG.debug("processAddLineBusinessRules() start"); EffortCertificationDocument effortCertificationDocument = (EffortCertificationDocument) (approveEvent.getDocument()); if (this.bypassBusinessRuleIfInitiation(effortCertificationDocument)) { return true; } boolean valid = true; for (EffortCertificationDetail detailLine : effortCertificationDocument.getEffortCertificationDetailLines()) { valid &= this.processUpdateDetailLineRules(effortCertificationDocument, detailLine); } valid &= this.processCustomRouteDocumentBusinessRules(effortCertificationDocument); return valid; } /** * @see org.kuali.rice.krad.rules.DocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.krad.document.Document) */ @Override public boolean processCustomRouteDocumentBusinessRules(Document document) { LOG.debug("processAddLineBusinessRules() start"); EffortCertificationDocument effortCertificationDocument = (EffortCertificationDocument) document; // the docuemnt must have at least one detail line if (!EffortCertificationDocumentRuleUtil.hasDetailLine(effortCertificationDocument)) { reportError(EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, EffortKeyConstants.ERROR_NOT_HAVE_DETAIL_LINE); return false; } if (this.bypassBusinessRuleIfInitiation(effortCertificationDocument)) { return true; } if (EffortCertificationDocumentRuleUtil.isEffortPercentChangedFromPersisted(effortCertificationDocument)) { List<Note> notes = effortCertificationDocument.getNotes(); boolean noteHasBeenAdded = false; for(Note note : notes) { if(note.isNewCollectionRecord()) { noteHasBeenAdded = true; break; } } if (!noteHasBeenAdded) { reportError(EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, EffortKeyConstants.ERROR_NOTE_REQUIRED_WHEN_EFFORT_CHANGED); return false; } } if (EffortCertificationDocumentRuleUtil.isTotalPayrollAmountOverChanged(effortCertificationDocument, EffortConstants.AMOUNT_LIMIT_OF_TOTAL_SALARY_CHANGE)) { reportError(EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, EffortKeyConstants.ERROR_TOTAL_PAYROLL_AMOUNT_OVERCHANGED, (Double.valueOf(EffortConstants.AMOUNT_LIMIT_OF_TOTAL_SALARY_CHANGE)).toString()); return false; } if (!EffortCertificationDocumentRuleUtil.isTotalEffortPercentageAs100(effortCertificationDocument)) { reportError(EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, EffortKeyConstants.ERROR_TOTAL_EFFORT_PERCENTAGE_NOT_100); return false; } String emplid = effortCertificationDocument.getEmplid(); effortCertificationDocument.refreshReferenceObject(EffortPropertyConstants.EFFORT_CERTIFICATION_REPORT_DEFINITION); EffortCertificationReportDefinition reportDefinition = effortCertificationDocument.getEffortCertificationReportDefinition(); if (effortCertificationReportDefinitionService.hasApprovedEffortCertification(emplid, reportDefinition)) { List<Note> notes = effortCertificationDocument.getNotes(); if (notes == null || notes.isEmpty()) { reportError(EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, EffortKeyConstants.ERROR_NOTE_REQUIRED_WHEN_APPROVED_EFFORT_CERTIFICATION_EXIST, emplid, reportDefinition.getUniversityFiscalYear().toString(), reportDefinition.getEffortCertificationReportNumber()); return false; } } return true; } /** * @see org.kuali.kfs.module.ec.document.validation.CheckDetailLineAmountRule#processCheckDetailLineAmountRules(org.kuali.kfs.module.ec.document.EffortCertificationDocument, * org.kuali.kfs.module.ec.businessobject.EffortCertificationDetail) */ @Override public boolean processCheckDetailLineAmountRules(EffortCertificationDocument effortCertificationDocument, EffortCertificationDetail effortCertificationDetail) { if (!EffortCertificationDocumentRuleUtil.hasValidEffortPercent(effortCertificationDetail)) { reportError(EffortPropertyConstants.EFFORT_CERTIFICATION_UPDATED_OVERALL_PERCENT, EffortKeyConstants.ERROR_INVALID_EFFORT_PERCENT); return false; } if (!EffortCertificationDocumentRuleUtil.hasNonnegativePayrollAmount(effortCertificationDetail)) { reportError(EffortPropertyConstants.EFFORT_CERTIFICATION_PAYROLL_AMOUNT, EffortKeyConstants.ERROR_NEGATIVE_PAYROLL_AMOUNT); return false; } return true; } /** * @see org.kuali.kfs.module.ec.document.validation.LoadDetailLineRule#processLoadDetailLineRules(org.kuali.kfs.module.ec.document.EffortCertificationDocument) */ @Override public boolean processLoadDetailLineRules(EffortCertificationDocument effortCertificationDocument) { LOG.debug("processLoadDetailLineRules() start"); boolean isValid = true; String emplid = effortCertificationDocument.getEmplid(); effortCertificationDocument.refreshReferenceObject(EffortPropertyConstants.EFFORT_CERTIFICATION_REPORT_DEFINITION); EffortCertificationReportDefinition reportDefinition = effortCertificationDocument.getEffortCertificationReportDefinition(); if (ObjectUtils.isNull(reportDefinition)) { reportError(EffortConstants.EFFORT_DETAIL_IMPORT_ERRORS, EffortKeyConstants.ERROR_REPORT_DEFINITION_NOT_EXIST); return false; } if (!reportDefinition.isActive()) { reportError(EffortConstants.EFFORT_DETAIL_IMPORT_ERRORS, EffortKeyConstants.ERROR_REPORT_DEFINITION_INACTIVE); return false; } isValid = StringUtils.equals(KFSConstants.PeriodStatusCodes.OPEN, reportDefinition.getEffortCertificationReportPeriodStatusCode()); if (!isValid) { reportError(EffortConstants.EFFORT_DETAIL_IMPORT_ERRORS, EffortKeyConstants.ERROR_REPORT_DEFINITION_PERIOD_NOT_OPENED); return false; } isValid = !effortCertificationReportDefinitionService.hasPendingEffortCertification(emplid, reportDefinition); if (!isValid) { reportError(EffortConstants.EFFORT_DETAIL_IMPORT_ERRORS, EffortKeyConstants.ERROR_PENDING_EFFORT_CERTIFICATION_EXIST); return false; } isValid = effortCertificationReportDefinitionService.hasBeenUsedForEffortCertificationGeneration(reportDefinition); if (!isValid) { reportError(EffortConstants.EFFORT_DETAIL_IMPORT_ERRORS, EffortKeyConstants.ERROR_CREATE_PROCESS_HAS_NOT_BEEN_COMPLETED); return false; } isValid = effortCertificationExtractService.isEmployeeEligibleForEffortCertification(emplid, reportDefinition); if (!isValid) { reportError(EffortConstants.EFFORT_DETAIL_IMPORT_ERRORS, EffortKeyConstants.ERROR_EMPLOYEE_NOT_ELIGIBLE, emplid); return false; } int countOfPendingSalaryExpenseTransfer = laborModuleService.countPendingSalaryExpenseTransfer(emplid); if (countOfPendingSalaryExpenseTransfer > 0) { reportError(EffortConstants.EFFORT_DETAIL_IMPORT_ERRORS, EffortKeyConstants.ERROR_PENDING_SALARAY_EXPENSE_TRANSFER_EXIST, emplid, Integer.toString(countOfPendingSalaryExpenseTransfer)); return false; } return this.populateEffortCertificationDocument(effortCertificationDocument); } /** * check if the attributes in the detail line are valid for the defintions in data dictionary and have valid references * * @param detailLine the given effort certification detail line * @return true if the attributes in the detail line are valid for the defintions in data dictionary and have valid references; * otherwise, false */ protected boolean checkDetailLineAttributes(EffortCertificationDetail detailLine) { LOG.debug("checkDetailLine() start"); DataDictionary dataDictionary = SpringContext.getBean(DataDictionaryService.class).getDataDictionary(); // check if the fields in the detail line are in the correct formats defined in the data dictionary boolean hasValidFormat = EffortCertificationDocumentRuleUtil.hasValidFormat(detailLine); // if the formats of the fields are correct, check if there exist the references of a set of specified fields boolean hasValidReference = true; if (hasValidFormat) { hasValidReference &= accountingLineRuleHelperService.isValidAccount(detailLine.getAccount(), dataDictionary, EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, ""); hasValidReference &= accountingLineRuleHelperService.isValidChart(detailLine.getChartOfAccounts(), dataDictionary, EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, ""); if (!KFSConstants.getDashSubAccountNumber().equals(detailLine.getSubAccountNumber()) && StringUtils.isNotBlank(detailLine.getSubAccountNumber())) { hasValidReference &= accountingLineRuleHelperService.isValidSubAccount(detailLine.getSubAccount(), dataDictionary, EffortConstants.EFFORT_CERTIFICATION_TAB_ERRORS, ""); } } return hasValidFormat && hasValidReference; } /** * determine if the business rule needs to be bypassed. If the given document is in the state of initiation, bypass * @param effortCertificationDocument the given document * @return true if the given document is in the state of initiation; otherwise, false */ protected boolean bypassBusinessRuleIfInitiation(EffortCertificationDocument effortCertificationDocument) { return effortCertificationDocument.getDocumentHeader().getWorkflowDocument().isInitiated(); } /** * determine if the given document can be populated. If so, populate it and return true * * @param effortCertificationDocument the given document * @return true if the given document can be populated; otherwise, return false and the document is not changed */ protected boolean populateEffortCertificationDocument(EffortCertificationDocument effortCertificationDocument) { String emplid = effortCertificationDocument.getEmplid(); EffortCertificationReportDefinition reportDefinition = effortCertificationDocument.getEffortCertificationReportDefinition(); EffortCertificationDocumentBuild documentBuild = effortCertificationExtractService.extract(emplid, reportDefinition); if (documentBuild == null) { reportError(EffortConstants.EFFORT_DETAIL_IMPORT_ERRORS, EffortKeyConstants.ERROR_EMPLOYEE_NO_ELIGIBLE_LABOR_BALANCE, emplid); return false; } effortCertificationDocumentService.removeEffortCertificationDetailLines(effortCertificationDocument); boolean success = effortCertificationDocumentService.populateEffortCertificationDocument(effortCertificationDocument, documentBuild); if (effortCertificationReportDefinitionService.hasBeenUsedForEffortCertificationGeneration(emplid, reportDefinition)) { effortCertificationDocument.setEffortCertificationDocumentCode(true); } return success; } // record the error into the global error map protected void reportError(String propertyName, String errorKey, String... errorParameters) { GlobalVariables.getMessageMap().putError(propertyName, errorKey, errorParameters); } }