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.fp.document.validation.impl; 017 018 import java.util.ArrayList; 019 import java.util.List; 020 import java.util.Set; 021 022 import org.apache.commons.lang.StringUtils; 023 import org.kuali.kfs.fp.businessobject.DisbursementVoucherNonResidentAlienTax; 024 import org.kuali.kfs.fp.businessobject.DisbursementVoucherPayeeDetail; 025 import org.kuali.kfs.fp.businessobject.NonResidentAlienTaxPercent; 026 import org.kuali.kfs.fp.document.DisbursementVoucherConstants; 027 import org.kuali.kfs.fp.document.DisbursementVoucherDocument; 028 import org.kuali.kfs.sys.KFSConstants; 029 import org.kuali.kfs.sys.KFSKeyConstants; 030 import org.kuali.kfs.sys.KFSPropertyConstants; 031 import org.kuali.kfs.sys.KfsAuthorizationConstants; 032 import org.kuali.kfs.sys.context.SpringContext; 033 import org.kuali.kfs.sys.document.AccountingDocument; 034 import org.kuali.kfs.sys.document.validation.GenericValidation; 035 import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent; 036 import org.kuali.rice.kim.bo.Person; 037 import org.kuali.rice.kns.bo.PersistableBusinessObject; 038 import org.kuali.rice.kns.document.authorization.TransactionalDocumentAuthorizer; 039 import org.kuali.rice.kns.document.authorization.TransactionalDocumentPresentationController; 040 import org.kuali.rice.kns.service.BusinessObjectService; 041 import org.kuali.rice.kns.service.DocumentHelperService; 042 import org.kuali.rice.kns.util.GlobalVariables; 043 import org.kuali.rice.kns.util.KualiDecimal; 044 import org.kuali.rice.kns.util.MessageMap; 045 046 public class DisbursementVoucherNonResidentAlienInformationValidation extends GenericValidation implements DisbursementVoucherConstants { 047 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DisbursementVoucherNonResidentAlienInformationValidation.class); 048 049 private AccountingDocument accountingDocumentForValidation; 050 051 /** 052 * @see org.kuali.kfs.sys.document.validation.Validation#validate(org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent) 053 */ 054 public boolean validate(AttributedDocumentEvent event) { 055 LOG.debug("validate start"); 056 boolean isValid = true; 057 058 DisbursementVoucherDocument document = (DisbursementVoucherDocument) accountingDocumentForValidation; 059 DisbursementVoucherNonResidentAlienTax nonResidentAlienTax = document.getDvNonResidentAlienTax(); 060 DisbursementVoucherPayeeDetail payeeDetail = document.getDvPayeeDetail(); 061 062 Person financialSystemUser = GlobalVariables.getUserSession().getPerson(); 063 064 List<String> taxEditMode = this.getTaxEditMode(); 065 if (!payeeDetail.isDisbVchrAlienPaymentCode() || !this.hasRequiredEditMode(document, financialSystemUser, taxEditMode)) { 066 return true; 067 } 068 069 MessageMap errors = GlobalVariables.getMessageMap(); 070 errors.addToErrorPath(KFSPropertyConstants.DOCUMENT); 071 errors.addToErrorPath(KFSPropertyConstants.DV_NON_RESIDENT_ALIEN_TAX); 072 073 /* income class code required */ 074 if (StringUtils.isBlank(nonResidentAlienTax.getIncomeClassCode())) { 075 errors.putError(KFSPropertyConstants.INCOME_CLASS_CODE, KFSKeyConstants.ERROR_REQUIRED, "Income class code "); 076 isValid = false; 077 } 078 else { 079 /* for foreign source or treaty exempt, non reportable, tax percents must be 0 and gross indicator can not be checked */ 080 if (nonResidentAlienTax.isForeignSourceIncomeCode() || nonResidentAlienTax.isIncomeTaxTreatyExemptCode() || NRA_TAX_INCOME_CLASS_NON_REPORTABLE.equals(nonResidentAlienTax.getIncomeClassCode())) { 081 082 if ((nonResidentAlienTax.getFederalIncomeTaxPercent() != null && !(KualiDecimal.ZERO.equals(nonResidentAlienTax.getFederalIncomeTaxPercent())))) { 083 errors.putError(KFSPropertyConstants.FEDERAL_INCOME_TAX_PERCENT, KFSKeyConstants.ERROR_DV_FEDERAL_TAX_NOT_ZERO); 084 isValid = false; 085 } 086 087 if ((nonResidentAlienTax.getStateIncomeTaxPercent() != null && !(KualiDecimal.ZERO.equals(nonResidentAlienTax.getStateIncomeTaxPercent())))) { 088 errors.putError(KFSPropertyConstants.STATE_INCOME_TAX_PERCENT, KFSKeyConstants.ERROR_DV_STATE_TAX_NOT_ZERO); 089 isValid = false; 090 } 091 092 if (nonResidentAlienTax.isIncomeTaxGrossUpCode()) { 093 errors.putError(KFSPropertyConstants.INCOME_TAX_GROSS_UP_CODE, KFSKeyConstants.ERROR_DV_GROSS_UP_INDICATOR); 094 isValid = false; 095 } 096 097 if (NRA_TAX_INCOME_CLASS_NON_REPORTABLE.equals(nonResidentAlienTax.getIncomeClassCode()) && StringUtils.isNotBlank(nonResidentAlienTax.getPostalCountryCode())) { 098 errors.putError(KFSPropertyConstants.POSTAL_COUNTRY_CODE, KFSKeyConstants.ERROR_DV_POSTAL_COUNTRY_CODE); 099 isValid = false; 100 } 101 } 102 else { 103 if (nonResidentAlienTax.getFederalIncomeTaxPercent() == null) { 104 errors.putError(KFSPropertyConstants.FEDERAL_INCOME_TAX_PERCENT, KFSKeyConstants.ERROR_REQUIRED, "Federal tax percent "); 105 isValid = false; 106 } 107 else { 108 // check tax percent is in non-resident alien tax percent table for income class code 109 NonResidentAlienTaxPercent taxPercent = new NonResidentAlienTaxPercent(); 110 taxPercent.setIncomeClassCode(nonResidentAlienTax.getIncomeClassCode()); 111 taxPercent.setIncomeTaxTypeCode(FEDERAL_TAX_TYPE_CODE); 112 taxPercent.setIncomeTaxPercent(nonResidentAlienTax.getFederalIncomeTaxPercent()); 113 114 NonResidentAlienTaxPercent retrievedPercent = (NonResidentAlienTaxPercent) SpringContext.getBean(BusinessObjectService.class).retrieve(taxPercent); 115 if (retrievedPercent == null) { 116 errors.putError(KFSPropertyConstants.FEDERAL_INCOME_TAX_PERCENT, KFSKeyConstants.ERROR_DV_INVALID_FED_TAX_PERCENT, new String[] { nonResidentAlienTax.getFederalIncomeTaxPercent().toString(), nonResidentAlienTax.getIncomeClassCode() }); 117 isValid = false; 118 } 119 } 120 121 if (nonResidentAlienTax.getStateIncomeTaxPercent() == null) { 122 errors.putError(KFSPropertyConstants.STATE_INCOME_TAX_PERCENT, KFSKeyConstants.ERROR_REQUIRED, "State tax percent "); 123 isValid = false; 124 } 125 else { 126 NonResidentAlienTaxPercent taxPercent = new NonResidentAlienTaxPercent(); 127 taxPercent.setIncomeClassCode(nonResidentAlienTax.getIncomeClassCode()); 128 taxPercent.setIncomeTaxTypeCode(STATE_TAX_TYPE_CODE); 129 taxPercent.setIncomeTaxPercent(nonResidentAlienTax.getStateIncomeTaxPercent()); 130 131 PersistableBusinessObject retrievedPercent = SpringContext.getBean(BusinessObjectService.class).retrieve(taxPercent); 132 if (retrievedPercent == null) { 133 errors.putError(KFSPropertyConstants.STATE_INCOME_TAX_PERCENT, KFSKeyConstants.ERROR_DV_INVALID_STATE_TAX_PERCENT, nonResidentAlienTax.getStateIncomeTaxPercent().toString(), nonResidentAlienTax.getIncomeClassCode()); 134 isValid = false; 135 } 136 } 137 138 // verify tax lines have been generated 139 if (isValid && (nonResidentAlienTax.getFederalIncomeTaxPercent().isNonZero() || nonResidentAlienTax.getStateIncomeTaxPercent().isNonZero())) { 140 if (StringUtils.isBlank(nonResidentAlienTax.getFinancialDocumentAccountingLineText())) { 141 errors.putErrorWithoutFullErrorPath(KFSConstants.GENERAL_NRATAX_TAB_ERRORS, KFSKeyConstants.ERROR_DV_NRA_NO_TAXLINES_GENERATED); 142 isValid = false; 143 } 144 } 145 } 146 } 147 148 /* country code required, unless income type is nonreportable */ 149 if (StringUtils.isBlank(nonResidentAlienTax.getPostalCountryCode()) && !NRA_TAX_INCOME_CLASS_NON_REPORTABLE.equals(nonResidentAlienTax.getIncomeClassCode())) { 150 errors.putError(KFSPropertyConstants.POSTAL_COUNTRY_CODE, KFSKeyConstants.ERROR_REQUIRED, "Country code "); 151 isValid = false; 152 } 153 154 errors.removeFromErrorPath(KFSPropertyConstants.DV_NON_RESIDENT_ALIEN_TAX); 155 errors.removeFromErrorPath(KFSPropertyConstants.DOCUMENT); 156 157 return isValid; 158 } 159 160 /** 161 * determine whether the give user has permission to any edit mode defined in the given candidate edit modes 162 * 163 * @param accountingDocument the given accounting document 164 * @param financialSystemUser the given user 165 * @param candidateEditEditModes the given candidate edit modes 166 * @return true if the give user has permission to any edit mode defined in the given candidate edit modes; otherwise, false 167 */ 168 private boolean hasRequiredEditMode(AccountingDocument accountingDocument, Person financialSystemUser, List<String> candidateEditModes) { 169 DocumentHelperService documentHelperService = SpringContext.getBean(DocumentHelperService.class); 170 TransactionalDocumentAuthorizer documentAuthorizer = (TransactionalDocumentAuthorizer) documentHelperService.getDocumentAuthorizer(accountingDocument); 171 TransactionalDocumentPresentationController presentationController = (TransactionalDocumentPresentationController) documentHelperService.getDocumentPresentationController(accountingDocument); 172 173 Set<String> presentationControllerEditModes = presentationController.getEditModes(accountingDocument); 174 Set<String> editModes = documentAuthorizer.getEditModes(accountingDocument, financialSystemUser, presentationControllerEditModes); 175 176 for (String editMode : candidateEditModes) { 177 if (editModes.contains(editMode)) { 178 return true; 179 } 180 } 181 182 return false; 183 } 184 185 /** 186 * define the tax edit mode name 187 * 188 * @return the tax edit mode name 189 */ 190 protected List<String> getTaxEditMode() { 191 List<String> candidateEdiModes = new ArrayList<String>(); 192 candidateEdiModes.add(KfsAuthorizationConstants.DisbursementVoucherEditMode.TAX_ENTRY); 193 194 return candidateEdiModes; 195 } 196 197 /** 198 * Sets the accountingDocumentForValidation attribute value. 199 * 200 * @param accountingDocumentForValidation The accountingDocumentForValidation to set. 201 */ 202 public void setAccountingDocumentForValidation(AccountingDocument accountingDocumentForValidation) { 203 this.accountingDocumentForValidation = accountingDocumentForValidation; 204 } 205 206 /** 207 * Gets the accountingDocumentForValidation attribute. 208 * 209 * @return Returns the accountingDocumentForValidation. 210 */ 211 public AccountingDocument getAccountingDocumentForValidation() { 212 return accountingDocumentForValidation; 213 } 214 215 }