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.module.cam.document.validation.impl; 017 018 import java.util.ArrayList; 019 import java.util.Date; 020 import java.util.HashMap; 021 import java.util.HashSet; 022 import java.util.List; 023 import java.util.Map; 024 025 import org.apache.commons.lang.StringUtils; 026 import org.kuali.kfs.coa.businessobject.Account; 027 import org.kuali.kfs.coa.businessobject.ObjectCode; 028 import org.kuali.kfs.coa.service.ObjectCodeService; 029 import org.kuali.kfs.integration.cam.CapitalAssetManagementModuleService; 030 import org.kuali.kfs.module.cam.CamsConstants; 031 import org.kuali.kfs.module.cam.CamsConstants.DocumentTypeName; 032 import org.kuali.kfs.module.cam.CamsKeyConstants; 033 import org.kuali.kfs.module.cam.CamsPropertyConstants; 034 import org.kuali.kfs.module.cam.businessobject.Asset; 035 import org.kuali.kfs.module.cam.businessobject.AssetGlobal; 036 import org.kuali.kfs.module.cam.businessobject.AssetGlobalDetail; 037 import org.kuali.kfs.module.cam.businessobject.AssetPaymentDetail; 038 import org.kuali.kfs.module.cam.businessobject.AssetType; 039 import org.kuali.kfs.module.cam.document.gl.AssetGlobalGeneralLedgerPendingEntrySource; 040 import org.kuali.kfs.module.cam.document.service.AssetAcquisitionTypeService; 041 import org.kuali.kfs.module.cam.document.service.AssetGlobalService; 042 import org.kuali.kfs.module.cam.document.service.AssetLocationService; 043 import org.kuali.kfs.module.cam.document.service.AssetLocationService.LocationField; 044 import org.kuali.kfs.module.cam.document.service.AssetPaymentService; 045 import org.kuali.kfs.module.cam.document.service.AssetService; 046 import org.kuali.kfs.module.cam.document.service.PaymentSummaryService; 047 import org.kuali.kfs.sys.KFSPropertyConstants; 048 import org.kuali.kfs.sys.businessobject.Building; 049 import org.kuali.kfs.sys.businessobject.FinancialSystemDocumentHeader; 050 import org.kuali.kfs.sys.businessobject.Room; 051 import org.kuali.kfs.sys.context.SpringContext; 052 import org.kuali.kfs.sys.document.authorization.FinancialSystemMaintenanceDocumentAuthorizerBase; 053 import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService; 054 import org.kuali.rice.kns.bo.Campus; 055 import org.kuali.rice.kns.bo.PersistableBusinessObject; 056 import org.kuali.rice.kns.document.Document; 057 import org.kuali.rice.kns.document.MaintenanceDocument; 058 import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase; 059 import org.kuali.rice.kns.service.BusinessObjectService; 060 import org.kuali.rice.kns.service.DataDictionaryService; 061 import org.kuali.rice.kns.service.DateTimeService; 062 import org.kuali.rice.kns.service.KNSServiceLocator; 063 import org.kuali.rice.kns.service.KualiModuleService; 064 import org.kuali.rice.kns.service.ParameterEvaluator; 065 import org.kuali.rice.kns.service.ParameterService; 066 import org.kuali.rice.kns.util.GlobalVariables; 067 import org.kuali.rice.kns.util.KualiDecimal; 068 import org.kuali.rice.kns.util.ObjectUtils; 069 import org.kuali.rice.kns.util.RiceKeyConstants; 070 import org.kuali.rice.kns.web.format.CurrencyFormatter; 071 072 /** 073 * Rule implementation for Asset Global document. 074 */ 075 public class AssetGlobalRule extends MaintenanceDocumentRuleBase { 076 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AssetGlobalRule.class); 077 protected static final Map<LocationField, String> LOCATION_FIELD_MAP = new HashMap<LocationField, String>(); 078 static { 079 LOCATION_FIELD_MAP.put(LocationField.CAMPUS_CODE, CamsPropertyConstants.AssetGlobalDetail.CAMPUS_CODE); 080 LOCATION_FIELD_MAP.put(LocationField.BUILDING_CODE, CamsPropertyConstants.AssetGlobalDetail.BUILDING_CODE); 081 LOCATION_FIELD_MAP.put(LocationField.ROOM_NUMBER, CamsPropertyConstants.AssetGlobalDetail.BUILDING_ROOM_NUMBER); 082 LOCATION_FIELD_MAP.put(LocationField.SUB_ROOM_NUMBER, CamsPropertyConstants.AssetGlobalDetail.BUILDING_SUB_ROOM_NUMBER); 083 LOCATION_FIELD_MAP.put(LocationField.CONTACT_NAME, CamsPropertyConstants.AssetGlobalDetail.OFF_CAMPUS_NAME); 084 LOCATION_FIELD_MAP.put(LocationField.STREET_ADDRESS, CamsPropertyConstants.AssetGlobalDetail.OFF_CAMPUS_ADDRESS); 085 LOCATION_FIELD_MAP.put(LocationField.CITY_NAME, CamsPropertyConstants.AssetGlobalDetail.OFF_CAMPUS_CITY_NAME); 086 LOCATION_FIELD_MAP.put(LocationField.STATE_CODE, CamsPropertyConstants.AssetGlobalDetail.OFF_CAMPUS_STATE_CODE); 087 LOCATION_FIELD_MAP.put(LocationField.ZIP_CODE, CamsPropertyConstants.AssetGlobalDetail.OFF_CAMPUS_ZIP_CODE); 088 LOCATION_FIELD_MAP.put(LocationField.COUNTRY_CODE, CamsPropertyConstants.AssetGlobalDetail.OFF_CAMPUS_COUNTRY_CODE); 089 } 090 091 /** 092 * This method checks reference fields when adding new payment into collection. 093 * 094 * @param assetGlobal 095 * @param assetPaymentDetail 096 * @return 097 */ 098 protected boolean checkReferenceExists(AssetGlobal assetGlobal, AssetPaymentDetail assetPaymentDetail) { 099 boolean valid = true; 100 101 // validate required field for object code. Skip the error message because the maintenance DD 'defaultExistenceChecks' can 102 // generate the same error message. We won't duplicate it. 103 if (StringUtils.isBlank(assetPaymentDetail.getFinancialObjectCode())) { 104 valid = false; 105 } 106 107 // Validate Financial Posted date 108 if (assetPaymentDetail.getExpenditureFinancialDocumentPostedDate() != null) { 109 valid &= validatePostedDate(assetPaymentDetail); 110 111 } 112 113 if (valid) { 114 // Check for ObjectCode 115 116 if (StringUtils.isNotBlank(assetPaymentDetail.getFinancialObjectCode())) { 117 assetPaymentDetail.refreshReferenceObject(KFSPropertyConstants.OBJECT_CODE); 118 if (ObjectUtils.isNull(assetPaymentDetail.getObjectCode())) { 119 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.FINANCIAL_OBJECT_CODE).getLabel(); 120 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.FINANCIAL_OBJECT_CODE, RiceKeyConstants.ERROR_EXISTENCE, label); 121 valid &= false; 122 } 123 } 124 } 125 126 if (StringUtils.isBlank(assetGlobal.getAcquisitionTypeCode()) || ObjectUtils.isNull(assetGlobal.getAcquisitionType())) { 127 putFieldError(CamsPropertyConstants.AssetGlobal.ACQUISITION_TYPE_CODE, CamsKeyConstants.AssetGlobal.ERROR_ACQUISITION_TYPE_CODE_REQUIRED); 128 valid &= false; 129 } 130 131 if (StringUtils.isBlank(assetGlobal.getInventoryStatusCode())) { 132 putFieldError(CamsPropertyConstants.AssetGlobal.INVENTORY_STATUS_CODE, CamsKeyConstants.AssetGlobal.ERROR_INVENTORY_STATUS_REQUIRED_FOR_PAYMENT); 133 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.SEQUENCE_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_ASSET_PAYMENT_DEPENDENCY); 134 valid &= false; 135 } 136 if (StringUtils.isBlank(assetGlobal.getCapitalAssetTypeCode())) { 137 putFieldError(CamsPropertyConstants.AssetGlobal.CAPITAL_ASSET_TYPE_CODE, CamsKeyConstants.AssetGlobal.ERROR_ASSET_TYPE_REQUIRED); 138 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.SEQUENCE_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_ASSET_PAYMENT_DEPENDENCY); 139 valid &= false; 140 } 141 142 // check for existence and active when not separating. This can't be done in the DD because we have a condition on it. 143 // Note: Even though on separate the payment lines can't be edited we still can't force the rules because data may have 144 // gone inactive since then. 145 if (!getAssetGlobalService().isAssetSeparate(assetGlobal)) { 146 assetPaymentDetail.refreshReferenceObject(CamsPropertyConstants.AssetPaymentDetail.ACCOUNT); 147 if (StringUtils.isBlank(assetPaymentDetail.getAccountNumber()) || isAccountInvalid(assetPaymentDetail.getAccount())) { 148 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.ACCOUNT_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_PAYMENT_ACCT_NOT_VALID, new String[] { assetPaymentDetail.getChartOfAccountsCode(), assetPaymentDetail.getAccountNumber() }); 149 valid &= false; 150 } 151 else if (!StringUtils.isBlank(assetPaymentDetail.getAccountNumber()) && !assetPaymentDetail.getAccount().isActive()) { 152 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.ACCOUNT_NUMBER).getLabel(); 153 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.ACCOUNT_NUMBER, RiceKeyConstants.ERROR_INACTIVE, label); 154 valid &= false; 155 } 156 157 assetPaymentDetail.refreshReferenceObject(KFSPropertyConstants.SUB_ACCOUNT); 158 if (!StringUtils.isBlank(assetPaymentDetail.getSubAccountNumber()) && ObjectUtils.isNull(assetPaymentDetail.getSubAccount())) { 159 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.SUB_ACCOUNT_NUMBER).getLabel(); 160 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.SUB_ACCOUNT_NUMBER, RiceKeyConstants.ERROR_EXISTENCE, label); 161 valid &= false; 162 } 163 else if (!StringUtils.isBlank(assetPaymentDetail.getSubAccountNumber()) && !assetPaymentDetail.getSubAccount().isActive()) { 164 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.SUB_ACCOUNT_NUMBER).getLabel(); 165 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.SUB_ACCOUNT_NUMBER, RiceKeyConstants.ERROR_INACTIVE, label); 166 valid &= false; 167 } 168 169 assetPaymentDetail.refreshReferenceObject(KFSPropertyConstants.OBJECT_CODE); 170 if (!StringUtils.isBlank(assetPaymentDetail.getFinancialObjectCode()) && ObjectUtils.isNull(assetPaymentDetail.getObjectCode())) { 171 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.FINANCIAL_OBJECT_CODE).getLabel(); 172 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.FINANCIAL_OBJECT_CODE, RiceKeyConstants.ERROR_EXISTENCE, label); 173 valid &= false; 174 } 175 else if (!StringUtils.isBlank(assetPaymentDetail.getFinancialObjectCode()) && !assetPaymentDetail.getObjectCode().isActive()) { 176 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.FINANCIAL_OBJECT_CODE).getLabel(); 177 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.FINANCIAL_OBJECT_CODE, RiceKeyConstants.ERROR_INACTIVE, label); 178 valid &= false; 179 } 180 181 assetPaymentDetail.refreshReferenceObject(KFSPropertyConstants.SUB_OBJECT_CODE); 182 if (!StringUtils.isBlank(assetPaymentDetail.getFinancialSubObjectCode()) && ObjectUtils.isNull(assetPaymentDetail.getSubObjectCode())) { 183 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.SUB_OBJECT_CODE).getLabel(); 184 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.SUB_OBJECT_CODE, RiceKeyConstants.ERROR_EXISTENCE, label); 185 valid &= false; 186 } 187 else if (!StringUtils.isBlank(assetPaymentDetail.getFinancialSubObjectCode()) && !assetPaymentDetail.getSubObjectCode().isActive()) { 188 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.SUB_OBJECT_CODE).getLabel(); 189 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.SUB_OBJECT_CODE, RiceKeyConstants.ERROR_INACTIVE, label); 190 valid &= false; 191 } 192 193 assetPaymentDetail.refreshReferenceObject(KFSPropertyConstants.PROJECT); 194 if (!StringUtils.isBlank(assetPaymentDetail.getProjectCode()) && ObjectUtils.isNull(assetPaymentDetail.getProject())) { 195 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.PROJECT_CODE).getLabel(); 196 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.PROJECT_CODE, RiceKeyConstants.ERROR_EXISTENCE, label); 197 valid &= false; 198 } 199 else if (!StringUtils.isBlank(assetPaymentDetail.getProjectCode()) && !assetPaymentDetail.getProject().isActive()) { 200 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.PROJECT_CODE).getLabel(); 201 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.PROJECT_CODE, RiceKeyConstants.ERROR_INACTIVE, label); 202 valid &= false; 203 } 204 205 assetPaymentDetail.refreshReferenceObject(CamsPropertyConstants.AssetPaymentDetail.ORIGINATION); 206 if (!StringUtils.isBlank(assetPaymentDetail.getExpenditureFinancialSystemOriginationCode()) && ObjectUtils.isNull(assetPaymentDetail.getExpenditureFinancialSystemOrigination())) { 207 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.ORIGINATION_CODE).getLabel(); 208 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.ORIGINATION_CODE, RiceKeyConstants.ERROR_EXISTENCE, label); 209 valid &= false; 210 } 211 else if (!StringUtils.isBlank(assetPaymentDetail.getExpenditureFinancialSystemOriginationCode()) && !assetPaymentDetail.getExpenditureFinancialSystemOrigination().isActive()) { 212 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.ORIGINATION_CODE).getLabel(); 213 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.ORIGINATION_CODE, RiceKeyConstants.ERROR_INACTIVE, label); 214 valid &= false; 215 } 216 217 if (!StringUtils.isBlank(assetPaymentDetail.getExpenditureFinancialDocumentTypeCode()) && ObjectUtils.isNull(assetPaymentDetail.getExpenditureFinancialSystemDocumentTypeCode())) { 218 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.DOCUMENT_TYPE_CODE).getLabel(); 219 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.DOCUMENT_TYPE_CODE, RiceKeyConstants.ERROR_EXISTENCE, label); 220 valid &= false; 221 return valid; 222 } 223 if (!StringUtils.isBlank(assetPaymentDetail.getExpenditureFinancialDocumentTypeCode()) && !assetPaymentDetail.getExpenditureFinancialSystemDocumentTypeCode().isActive()) { 224 String label = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(AssetPaymentDetail.class.getName()).getAttributeDefinition(CamsPropertyConstants.AssetPaymentDetail.DOCUMENT_TYPE_CODE).getLabel(); 225 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.DOCUMENT_TYPE_CODE, RiceKeyConstants.ERROR_INACTIVE, label); 226 valid &= false; 227 } 228 } 229 return valid; 230 } 231 232 /** 233 * This method checks reference fields when adding one shared location information into collection. 234 * 235 * @param assetGlobalDetail 236 * @return 237 */ 238 protected boolean checkReferenceExists(AssetGlobalDetail assetGlobalDetail) { 239 boolean valid = true; 240 if (StringUtils.isNotBlank(assetGlobalDetail.getCampusCode())) { 241 Map<String, Object> criteria = new HashMap<String, Object>(); 242 criteria.put(CamsPropertyConstants.Asset.CAMPUS_CODE, assetGlobalDetail.getCampusCode()); 243 Campus campus = SpringContext.getBean(KualiModuleService.class).getResponsibleModuleService(Campus.class).getExternalizableBusinessObject(Campus.class, criteria); 244 245 if (ObjectUtils.isNull(campus)) { 246 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.CAMPUS_CODE, CamsKeyConstants.AssetLocation.ERROR_INVALID_CAMPUS_CODE, assetGlobalDetail.getCampusCode()); 247 valid &= false; 248 } 249 else if (!campus.isActive()) { 250 String label = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(Campus.class.getName()).getAttributeDefinition(KFSPropertyConstants.CAMPUS_CODE).getLabel(); 251 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.CAMPUS_CODE, RiceKeyConstants.ERROR_INACTIVE, label); 252 valid &= false; 253 } 254 } 255 256 if (StringUtils.isNotBlank(assetGlobalDetail.getBuildingCode())) { 257 Map<String, String> objectKeys = new HashMap<String, String>(); 258 objectKeys.put(CamsPropertyConstants.AssetGlobalDetail.CAMPUS_CODE, assetGlobalDetail.getCampusCode()); 259 objectKeys.put(CamsPropertyConstants.AssetGlobalDetail.BUILDING_CODE, assetGlobalDetail.getBuildingCode()); 260 Building building = (Building) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(Building.class, objectKeys); 261 262 if (ObjectUtils.isNull(building)) { 263 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.BUILDING_CODE, CamsKeyConstants.AssetLocation.ERROR_INVALID_BUILDING_CODE, assetGlobalDetail.getBuildingCode(), assetGlobalDetail.getCampusCode()); 264 valid &= false; 265 } 266 else if (!building.isActive()) { 267 String label = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(Building.class.getName()).getAttributeDefinition(KFSPropertyConstants.BUILDING_CODE).getLabel(); 268 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.BUILDING_CODE, RiceKeyConstants.ERROR_INACTIVE, label); 269 valid &= false; 270 } 271 } 272 273 if (StringUtils.isNotBlank(assetGlobalDetail.getBuildingRoomNumber())) { 274 Map<String, String> objectKeys = new HashMap<String, String>(); 275 objectKeys.put(CamsPropertyConstants.AssetGlobalDetail.CAMPUS_CODE, assetGlobalDetail.getCampusCode()); 276 objectKeys.put(CamsPropertyConstants.AssetGlobalDetail.BUILDING_CODE, assetGlobalDetail.getBuildingCode()); 277 objectKeys.put(CamsPropertyConstants.AssetGlobalDetail.BUILDING_ROOM_NUMBER, assetGlobalDetail.getBuildingRoomNumber()); 278 Room room = (Room) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(Room.class, objectKeys); 279 280 if (ObjectUtils.isNull(room)) { 281 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.BUILDING_ROOM_NUMBER, CamsKeyConstants.AssetLocation.ERROR_INVALID_ROOM_NUMBER, assetGlobalDetail.getBuildingCode(), assetGlobalDetail.getBuildingRoomNumber(), assetGlobalDetail.getCampusCode()); 282 valid &= false; 283 } 284 else if (!room.isActive()) { 285 String label = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(Room.class.getName()).getAttributeDefinition(KFSPropertyConstants.BUILDING_ROOM_NUMBER).getLabel(); 286 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.BUILDING_ROOM_NUMBER, RiceKeyConstants.ERROR_INACTIVE, label); 287 valid &= false; 288 } 289 } 290 return valid; 291 } 292 293 294 protected boolean isCapitalStatus(AssetGlobal assetGlobal) { 295 return getParameterService().getParameterValues(Asset.class, CamsConstants.Parameters.CAPITAL_ASSET_STATUS_CODES).contains(assetGlobal.getInventoryStatusCode()); 296 } 297 298 protected boolean isStatusCodeRetired(String statusCode) { 299 return getParameterService().getParameterValues(Asset.class, CamsConstants.Parameters.RETIRED_STATUS_CODES).contains(statusCode); 300 } 301 302 @Override 303 public boolean processCustomAddCollectionLineBusinessRules(MaintenanceDocument document, String collectionName, PersistableBusinessObject line) { 304 boolean success = super.processCustomAddCollectionLineBusinessRules(document, collectionName, line); 305 if (GlobalVariables.getMessageMap().hasErrors()) { 306 return false; 307 } 308 309 AssetGlobal assetGlobal = (AssetGlobal) document.getNewMaintainableObject().getBusinessObject(); 310 List<AssetGlobalDetail> assetSharedDetails = assetGlobal.getAssetSharedDetails(); 311 if (CamsPropertyConstants.AssetGlobal.ASSET_SHARED_DETAILS.equals(collectionName)) { 312 // handle location information 313 AssetGlobalDetail assetGlobalDetail = (AssetGlobalDetail) line; 314 success &= checkReferenceExists(assetGlobalDetail); 315 success &= validateLocation(assetGlobal, assetGlobalDetail); 316 317 // qty. of assets (unique) to be created 318 success &= validateLocationQuantity(line); 319 } 320 else if (StringUtils.isNotBlank(collectionName) && collectionName.contains(CamsPropertyConstants.AssetGlobalDetail.ASSET_UNIQUE_DETAILS)) { 321 // handle unique information 322 AssetGlobalDetail assetUniqueDetail = (AssetGlobalDetail) line; 323 String campusTagNumber = assetUniqueDetail.getCampusTagNumber(); 324 if (StringUtils.isNotBlank(campusTagNumber)) { 325 success &= validateTagDuplication(assetSharedDetails, campusTagNumber); 326 } 327 } 328 else if (CamsPropertyConstants.AssetGlobal.ASSET_PAYMENT_DETAILS.equals(collectionName)) { 329 AssetPaymentDetail assetPaymentDetail = (AssetPaymentDetail) line; 330 331 if (success &= checkReferenceExists(assetGlobal, assetPaymentDetail)) { 332 success &= validatePaymentLine(document, assetGlobal, assetPaymentDetail); 333 success &= checkNegativeOrZeroPayment(document, assetPaymentDetail); 334 } 335 } 336 337 338 // only for "Asset Separate" document 339 if (getAssetGlobalService().isAssetSeparate(assetGlobal)) { 340 // total cost must be > 0 341 success &= validateTotalCostAmount(assetGlobal); 342 } 343 return success; 344 } 345 346 /** 347 * Validated the location quantity 348 * 349 * @param line 350 * @return boolean 351 */ 352 protected boolean validateLocationQuantity(PersistableBusinessObject line) { 353 boolean success = true; 354 AssetGlobalDetail assetGlobalDetail = (AssetGlobalDetail) line; 355 if (assetGlobalDetail.getLocationQuantity() <= 0) { 356 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.LOCATION_QUANTITY, CamsKeyConstants.AssetSeparate.ERROR_ZERO_OR_NEGATIVE_LOCATION_QUANTITY, assetGlobalDetail.getLocationQuantity().toString()); 357 success &= false; 358 } 359 return success; 360 } 361 362 protected boolean validateTagDuplication(List<AssetGlobalDetail> assetSharedDetails, String campusTagNumber) { 363 boolean success = true; 364 if (!campusTagNumber.equalsIgnoreCase(CamsConstants.Asset.NON_TAGGABLE_ASSET)) { 365 for (AssetGlobalDetail assetSharedDetail : assetSharedDetails) { 366 List<AssetGlobalDetail> assetGlobalUniqueDetails = assetSharedDetail.getAssetGlobalUniqueDetails(); 367 for (AssetGlobalDetail assetSharedUniqueDetail : assetGlobalUniqueDetails) { 368 if (campusTagNumber.equalsIgnoreCase(assetSharedUniqueDetail.getCampusTagNumber())) { 369 success &= false; 370 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.CAMPUS_TAG_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_CAMPUS_TAG_NUMBER_DUPLICATE, campusTagNumber); 371 } 372 } 373 } 374 if (success) { 375 List<Asset> tagMatches = getAssetService().findActiveAssetsMatchingTagNumber(campusTagNumber); 376 if (!tagMatches.isEmpty()) { 377 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.CAMPUS_TAG_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_CAMPUS_TAG_NUMBER_DUPLICATE, campusTagNumber); 378 success &= false; 379 } 380 } 381 } 382 return success; 383 } 384 385 protected boolean validateTagDuplication(List<AssetGlobalDetail> assetSharedDetails) { 386 HashSet<String> assetTags = new HashSet<String>(); 387 boolean success = true; 388 int parentIndex = -1; 389 int childIndex = -1; 390 for (AssetGlobalDetail assetSharedDetail : assetSharedDetails) { 391 parentIndex++; 392 List<AssetGlobalDetail> assetGlobalUniqueDetails = assetSharedDetail.getAssetGlobalUniqueDetails(); 393 for (AssetGlobalDetail assetSharedUniqueDetail : assetGlobalUniqueDetails) { 394 childIndex++; 395 String campusTagNumber = assetSharedUniqueDetail.getCampusTagNumber(); 396 if (StringUtils.isNotBlank(campusTagNumber) && !assetTags.add(campusTagNumber) && !campusTagNumber.equalsIgnoreCase(CamsConstants.Asset.NON_TAGGABLE_ASSET)) { 397 success &= false; 398 String errorPath = MAINTAINABLE_ERROR_PREFIX + CamsPropertyConstants.AssetGlobal.ASSET_SHARED_DETAILS + "[" + parentIndex + "]." + CamsPropertyConstants.AssetGlobalDetail.ASSET_UNIQUE_DETAILS + "[" + childIndex + "]"; 399 GlobalVariables.getMessageMap().addToErrorPath(errorPath); 400 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.CAMPUS_TAG_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_CAMPUS_TAG_NUMBER_DUPLICATE, campusTagNumber); 401 GlobalVariables.getMessageMap().removeFromErrorPath(errorPath); 402 403 } 404 } 405 childIndex = -1; 406 for (AssetGlobalDetail assetSharedUniqueDetail : assetGlobalUniqueDetails) { 407 childIndex++; 408 String campusTagNumber = assetSharedUniqueDetail.getCampusTagNumber(); 409 if (StringUtils.isNotBlank(campusTagNumber) && !campusTagNumber.equalsIgnoreCase(CamsConstants.Asset.NON_TAGGABLE_ASSET)) { 410 List<Asset> tagMatches = getAssetService().findActiveAssetsMatchingTagNumber(campusTagNumber); 411 if (!tagMatches.isEmpty()) { 412 success &= false; 413 String errorPath = MAINTAINABLE_ERROR_PREFIX + CamsPropertyConstants.AssetGlobal.ASSET_SHARED_DETAILS + "[" + parentIndex + "]." + CamsPropertyConstants.AssetGlobalDetail.ASSET_UNIQUE_DETAILS + "[" + childIndex + "]"; 414 GlobalVariables.getMessageMap().addToErrorPath(errorPath); 415 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.CAMPUS_TAG_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_CAMPUS_TAG_NUMBER_DUPLICATE, campusTagNumber); 416 GlobalVariables.getMessageMap().removeFromErrorPath(errorPath); 417 } 418 } 419 } 420 } 421 return success; 422 } 423 424 protected boolean validatePaymentLine(MaintenanceDocument maintenanceDocument, AssetGlobal assetGlobal, AssetPaymentDetail assetPaymentDetail) { 425 boolean success = true; 426 427 // If Acquisition type is "New" or "non-capital", check required fields including Document number, Document type code, 428 // Posted date. 429 430 if (getAssetGlobalService().existsInGroup(getAssetGlobalService().getNewAcquisitionTypeCode(), assetGlobal.getAcquisitionTypeCode()) || !getAssetGlobalService().existsInGroup(getAssetGlobalService().getCapitalObjectAcquisitionCodeGroup(), assetGlobal.getAcquisitionTypeCode())) { 431 success &= checkRequiredFieldsForNewOrNonCapital(assetPaymentDetail); 432 } 433 else { 434 // Validate Financial Document Type Code 435 success &= validateDocumentTypeForNonNew(assetGlobal.getAcquisitionTypeCode(), assetPaymentDetail); 436 } 437 438 success &= validateObjectCode(assetPaymentDetail.getObjectCode(), assetGlobal); 439 440 441 return success; 442 } 443 444 /** 445 * "Add Negative Payment" permission check. 446 * 447 * @param maintenanceDocument 448 * @param assetPaymentDetail 449 * @return 450 */ 451 protected boolean checkNegativeOrZeroPayment(MaintenanceDocument maintenanceDocument, AssetPaymentDetail assetPaymentDetail) { 452 boolean success = true; 453 FinancialSystemMaintenanceDocumentAuthorizerBase documentAuthorizer = (FinancialSystemMaintenanceDocumentAuthorizerBase) KNSServiceLocator.getDocumentHelperService().getDocumentAuthorizer(maintenanceDocument); 454 boolean isAuthorized = documentAuthorizer.isAuthorized(maintenanceDocument, CamsConstants.CAM_MODULE_CODE, CamsConstants.PermissionNames.ADD_NEGATIVE_PAYMENTS, GlobalVariables.getUserSession().getPerson().getPrincipalId()); 455 456 if (!isAuthorized && assetPaymentDetail.getAmount() != null && assetPaymentDetail.getAmount().isNegative()) { 457 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.AMOUNT, CamsKeyConstants.AssetGlobal.ERROR_INVALID_PAYMENT_AMOUNT); 458 success = false; 459 } 460 461 // amount can not be zero for any user 462 if (assetPaymentDetail.getAmount().isZero()) { 463 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.AMOUNT, CamsKeyConstants.AssetGlobal.ERROR_INVALID_PAYMENT_AMOUNT); 464 success = false; 465 } 466 return success; 467 } 468 469 /** 470 * This method check the required fields for acquisition type New . 471 * 472 * @param assetPaymentDetail 473 * @return 474 */ 475 protected boolean checkRequiredFieldsForNewOrNonCapital(AssetPaymentDetail assetPaymentDetail) { 476 boolean valid = true; 477 478 if (StringUtils.isBlank(assetPaymentDetail.getExpenditureFinancialDocumentNumber())) { 479 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.DOCUMENT_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_EXPENDITURE_FINANCIAL_DOCUMENT_NUMBER_REQUIRED); 480 valid &= false; 481 } 482 if (assetPaymentDetail.getExpenditureFinancialDocumentPostedDate() == null) { 483 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.DOCUMENT_POSTING_DATE, CamsKeyConstants.AssetGlobal.ERROR_DOCUMENT_POSTING_DATE_REQUIRED); 484 valid &= false; 485 } 486 if (StringUtils.isBlank(assetPaymentDetail.getExpenditureFinancialDocumentTypeCode())) { 487 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.DOCUMENT_TYPE_CODE, CamsKeyConstants.AssetGlobal.ERROR_EXPENDITURE_FINANCIAL_DOCUMENT_TYPE_CODE_REQUIRED); 488 valid &= false; 489 } 490 return valid; 491 } 492 493 /** 494 * Validates the posted date payment posted date can't be a future date 495 * 496 * @param assetPaymentDetail 497 * @return boolean 498 */ 499 protected boolean validatePostedDate(AssetPaymentDetail assetPaymentDetail) { 500 boolean valid = true; 501 Date currentDate = SpringContext.getBean(DateTimeService.class).getCurrentDate(); 502 503 if (!getAssetPaymentService().extractPostedDatePeriod(assetPaymentDetail)) { 504 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.DOCUMENT_POSTING_FISCAL_YEAR, CamsKeyConstants.AssetGlobal.ERROR_UNIVERSITY_NOT_DEFINED_FOR_DATE, new String[] { assetPaymentDetail.getExpenditureFinancialDocumentPostedDate().toString() }); 505 valid &= false; 506 } 507 else if (assetPaymentDetail.getExpenditureFinancialDocumentPostedDate().compareTo(currentDate) > 0) { 508 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.DOCUMENT_POSTING_DATE, CamsKeyConstants.Payment.ERROR_INVALID_DOC_POST_DATE); 509 valid = false; 510 } 511 return valid; 512 } 513 514 /** 515 * When acquisition type code is Capital (Gifts, Transfer-in, State excess, and Found), payment document type code will be 516 * assigned to AA for Add Asset Document. 517 * 518 * @param documentTypeCode 519 * @return 520 */ 521 protected boolean validateDocumentTypeForNonNew(String acquisitionTypeCode, AssetPaymentDetail assetPaymentDetail) { 522 String documentTypeCode = assetPaymentDetail.getExpenditureFinancialDocumentTypeCode(); 523 524 boolean valid = true; 525 if (StringUtils.isNotBlank(acquisitionTypeCode) && getAssetGlobalService().existsInGroup(getAssetGlobalService().getNonNewAcquisitionCodeGroup(), acquisitionTypeCode)) { 526 527 if (StringUtils.isNotBlank(documentTypeCode) && !CamsConstants.DocumentTypeName.ASSET_ADD_GLOBAL.equalsIgnoreCase(documentTypeCode)) { 528 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetPaymentDetail.DOCUMENT_TYPE_CODE, CamsKeyConstants.AssetGlobal.ERROR_DOCUMENT_TYPE_CODE_NOT_ALLOWED, documentTypeCode); 529 valid = false; 530 } 531 else { 532 // system set document type code as 'AA' 533 assetPaymentDetail.setExpenditureFinancialDocumentTypeCode(CamsConstants.DocumentTypeName.ASSET_ADD_GLOBAL); 534 } 535 } 536 return valid; 537 } 538 539 /** 540 * Check object code is set to capital only when the status is capital. 541 * 542 * @param assetGlobal 543 * @param assetPaymentDetail 544 * @return valid 545 */ 546 protected boolean validateObjectCode(ObjectCode objectCode, AssetGlobal assetGlobal) { 547 boolean valid = true; 548 549 // The acquisition type code of (F, G, N, S, T) requires a capital object code. 550 ParameterService parameterService = SpringContext.getBean(ParameterService.class); 551 ParameterEvaluator parameterEvaluator = getParameterService().getParameterEvaluator(AssetGlobal.class, CamsConstants.Parameters.VALID_OBJECT_SUB_TYPES_BY_ACQUISITION_TYPE, CamsConstants.Parameters.INVALID_OBJECT_SUB_TYPES_BY_ACQUISITION_TYPE, assetGlobal.getAcquisitionTypeCode(), objectCode.getFinancialObjectSubTypeCode()); 552 valid &= parameterEvaluator.evaluateAndAddError(ObjectCode.class, CamsPropertyConstants.Asset.FINANCIAL_OBJECT_SUB_TYP_CODE, CamsPropertyConstants.AssetPaymentDetail.FINANCIAL_OBJECT_CODE); 553 554 return valid; 555 } 556 557 protected boolean isAccountInvalid(Account account) { 558 return ObjectUtils.isNull(account) || account.isExpired(); 559 } 560 561 @Override 562 protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) { 563 AssetGlobal assetGlobal = (AssetGlobal) document.getNewMaintainableObject().getBusinessObject(); 564 List<AssetGlobalDetail> assetSharedDetails = assetGlobal.getAssetSharedDetails(); 565 boolean success = super.processCustomRouteDocumentBusinessRules(document); 566 if (GlobalVariables.getMessageMap().hasErrors()) { 567 return false; 568 } 569 570 // need at least one asset location 571 if (assetSharedDetails.isEmpty() || assetSharedDetails.get(0).getAssetGlobalUniqueDetails().isEmpty()) { 572 putFieldError(CamsPropertyConstants.AssetGlobal.ASSET_SHARED_DETAILS, CamsKeyConstants.AssetGlobal.MIN_ONE_ASSET_REQUIRED); 573 success &= false; 574 } 575 576 // Capital Asset must have payment zone. 577 if (isCapitalStatus(assetGlobal) && assetGlobal.getAssetPaymentDetails().isEmpty()) { 578 putFieldError(CamsPropertyConstants.AssetGlobal.ASSET_PAYMENT_DETAILS, CamsKeyConstants.AssetGlobal.MIN_ONE_PAYMENT_REQUIRED); 579 success &= false; 580 } 581 // check total amount for Asset Create 582 if (!getAssetGlobalService().isAssetSeparate(assetGlobal)) { 583 success &= validateAssetTotalAmount(document); 584 } 585 else { 586 // only for "Asset Separate" document 587 if (getAssetPaymentService().getAssetPaymentDetailQuantity(assetGlobal) >= 10) { 588 /* 589 * @TODO KULCAP-828 putFieldError(CamsPropertyConstants.AssetGlobal.ASSET_SHARED_DETAILS, 590 * CamsKeyConstants.AssetSeparate.ERROR_ASSET_SPLIT_MAX_LIMIT); success &= false; 591 */ 592 } 593 594 // new source payments must be greater than the capital asset cost amount 595 KualiDecimal totalSeparateSourceAmount = getAssetGlobalService().getUniqueAssetsTotalAmount(assetGlobal); 596 if (totalSeparateSourceAmount.isGreaterThan(assetGlobal.getTotalCostAmount())) { 597 putFieldError(CamsPropertyConstants.AssetGlobal.ASSET_SHARED_DETAILS, CamsKeyConstants.AssetSeparate.ERROR_INVALID_TOTAL_SEPARATE_SOURCE_AMOUNT, new String[] { assetGlobal.getSeparateSourceCapitalAssetNumber().toString() }); 598 success &= false; 599 } 600 601 // only active capital assets can be separated 602 assetGlobal.refreshReferenceObject(CamsPropertyConstants.AssetGlobal.SEPARATE_SOURCE_CAPITAL_ASSET); 603 if (ObjectUtils.isNotNull(assetGlobal.getSeparateSourceCapitalAsset())) { 604 if (!getAssetService().isCapitalAsset(assetGlobal.getSeparateSourceCapitalAsset())) { 605 if (StringUtils.isNotBlank(assetGlobal.getAcquisitionTypeCode())) { 606 putFieldError(CamsPropertyConstants.AssetGlobal.ACQUISITION_TYPE_CODE, CamsKeyConstants.AssetSeparate.ERROR_NON_CAPITAL_ASSET_SEPARATE_REQUIRED); 607 success &= false; 608 } 609 } 610 } 611 612 // validate required fields within "Asset Unique Information" tab 613 int sharedIndex = 0; 614 for (AssetGlobalDetail addLocationDetail : assetSharedDetails) { 615 int uniqueIndex = 0; 616 for (AssetGlobalDetail assetGlobalUniqueDetail : addLocationDetail.getAssetGlobalUniqueDetails()) { 617 String errorPath = MAINTAINABLE_ERROR_PREFIX + CamsPropertyConstants.AssetGlobal.ASSET_SHARED_DETAILS + "[" + sharedIndex + "]." + CamsPropertyConstants.AssetGlobalDetail.ASSET_GLOBAL_UNIQUE_DETAILS + "[" + uniqueIndex + "]"; 618 GlobalVariables.getMessageMap().addToErrorPath(errorPath); 619 success &= validateCapitalAssetTypeCode(assetGlobalUniqueDetail); 620 success &= validateAssetType(assetGlobalUniqueDetail, sharedIndex, uniqueIndex); 621 success &= validateAssetDescription(assetGlobalUniqueDetail); 622 success &= validateManufacturer(assetGlobalUniqueDetail); 623 success &= validateSeparateSourceAmount(assetGlobalUniqueDetail, document); 624 GlobalVariables.getMessageMap().removeFromErrorPath(errorPath); 625 uniqueIndex++; 626 } 627 sharedIndex++; 628 } 629 630 // total cost must be > 0 631 success &= validateTotalCostAmount(assetGlobal); 632 633 success &= validateAssetTotalCostMatchesPaymentTotalCost(assetGlobal); 634 635 if (getAssetGlobalService().isAssetSeparateByPayment(assetGlobal)) { 636 AssetGlobalRule.validateAssetAlreadySeparated(assetGlobal.getSeparateSourceCapitalAssetNumber()); 637 } 638 } // end ASEP 639 640 success &= validateLocationCollection(assetGlobal, assetSharedDetails); 641 success &= validateTagDuplication(assetSharedDetails); 642 return success; 643 } 644 645 646 /** 647 * Validate all separate source amount is above the capital asset threshold amount. 648 * 649 * @param document 650 * @return 651 */ 652 protected boolean validateSeparateSourceAmountAboveThreshold(MaintenanceDocument document, AssetGlobalDetail assetGlobalUniqueDetail) { 653 boolean success = true; 654 String capitalizationThresholdAmount = this.getCapitalizationThresholdAmount(); 655 KualiDecimal separateAmount = assetGlobalUniqueDetail.getSeparateSourceAmount(); 656 // check for the minimal amount only among all separate source amount. if it's above the threshold, safe... 657 if (separateAmount != null && !getAssetService().isDocumentEnrouting(document) && !validateCapitalAssetAmountAboveThreshhold(document, separateAmount, capitalizationThresholdAmount)) { 658 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.SEPARATE_SOURCE_AMOUNT, CamsKeyConstants.AssetSeparate.ERROR_SEPARATE_ASSET_BELOW_THRESHOLD, new String[] { assetGlobalUniqueDetail.getCapitalAssetNumber().toString(), capitalizationThresholdAmount }); 659 success = false; 660 } 661 return success; 662 } 663 664 /** 665 * check if amount is above threshold for capital assets for normal user. minTotalPaymentByAsset and maxTotalPaymentByAsset are 666 * used to check against threshold. Due to the decimal rounding, the asset total amount could have 1 cent difference with each 667 * other. We need to pick up the right value for different threshold check. 668 * 669 * @param document 670 * @return 671 */ 672 protected boolean validateAssetTotalAmount(MaintenanceDocument document) { 673 boolean success = true; 674 AssetGlobal assetGlobal = (AssetGlobal) document.getNewMaintainableObject().getBusinessObject(); 675 676 KualiDecimal minTotalPaymentByAsset = getAssetGlobalService().totalPaymentByAsset(assetGlobal, false); 677 KualiDecimal maxTotalPaymentByAsset = getAssetGlobalService().totalPaymentByAsset(assetGlobal, true); 678 if (minTotalPaymentByAsset.isGreaterThan(maxTotalPaymentByAsset)) { 679 // swap min and max 680 KualiDecimal totalPayment = minTotalPaymentByAsset; 681 minTotalPaymentByAsset = maxTotalPaymentByAsset; 682 maxTotalPaymentByAsset = totalPayment; 683 } 684 685 // Disallow FO change asset total amount during routing. Asset total amount is derived from asset payments total and the 686 // quantity of assets 687 if (getAssetService().isDocumentEnrouting(document) && (!minTotalPaymentByAsset.equals(assetGlobal.getMinAssetTotalAmount()) || !maxTotalPaymentByAsset.equals(assetGlobal.getMaxAssetTotalAmount()))) { 688 putFieldError(CamsPropertyConstants.AssetGlobal.ASSET_PAYMENT_DETAILS, CamsKeyConstants.AssetGlobal.ERROR_CHANGE_ASSET_TOTAL_AMOUNT_DISALLOW, !minTotalPaymentByAsset.equals(assetGlobal.getMinAssetTotalAmount()) ? new String[] { (String) new CurrencyFormatter().format(assetGlobal.getMinAssetTotalAmount()), (String) new CurrencyFormatter().format(minTotalPaymentByAsset) } : new String[] { (String) new CurrencyFormatter().format(assetGlobal.getMaxAssetTotalAmount()), (String) new CurrencyFormatter().format(maxTotalPaymentByAsset) }); 689 success = false; 690 } 691 692 // run threshold checking before routing 693 if (!getAssetService().isDocumentEnrouting(document)) { 694 String capitalizationThresholdAmount = getCapitalizationThresholdAmount(); 695 if (isCapitalStatus(assetGlobal)) { 696 // check if amount is above threshold for capital asset. 697 if (!validateCapitalAssetAmountAboveThreshhold(document, minTotalPaymentByAsset, capitalizationThresholdAmount)) { 698 putFieldError(CamsPropertyConstants.AssetGlobal.INVENTORY_STATUS_CODE, CamsKeyConstants.AssetGlobal.ERROR_CAPITAL_ASSET_PAYMENT_AMOUNT_MIN, capitalizationThresholdAmount); 699 success = false; 700 } 701 } 702 else { 703 // check if amount is less than threshold for non-capital assets for all users 704 success &= validateNonCapitalAssetAmountBelowThreshold(maxTotalPaymentByAsset, capitalizationThresholdAmount); 705 } 706 707 } 708 return success; 709 } 710 711 /** 712 * Get the capitalization threshold amount from the system parameter setting. 713 * 714 * @return 715 */ 716 protected String getCapitalizationThresholdAmount() { 717 return getParameterService().getParameterValue(AssetGlobal.class, CamsConstants.Parameters.CAPITALIZATION_LIMIT_AMOUNT); 718 } 719 720 /** 721 * Validate Capital Asset Amount above the threshold or below the amount for authorized user only. 722 * 723 * @param document 724 * @param assetAmount 725 * @param capitalizationThresholdAmount 726 * @return 727 */ 728 protected boolean validateCapitalAssetAmountAboveThreshhold(MaintenanceDocument document, KualiDecimal assetAmount, String capitalizationThresholdAmount) { 729 boolean success = true; 730 FinancialSystemMaintenanceDocumentAuthorizerBase documentAuthorizer = (FinancialSystemMaintenanceDocumentAuthorizerBase) KNSServiceLocator.getDocumentHelperService().getDocumentAuthorizer(document); 731 boolean isOverrideAuthorized = documentAuthorizer.isAuthorized(document, CamsConstants.CAM_MODULE_CODE, CamsConstants.PermissionNames.OVERRIDE_CAPITALIZATION_LIMIT_AMOUNT, GlobalVariables.getUserSession().getPerson().getPrincipalId()); 732 733 if (assetAmount.isLessThan(new KualiDecimal(capitalizationThresholdAmount)) && !isOverrideAuthorized) { 734 success = false; 735 } 736 return success; 737 } 738 739 /** 740 * Validate non-capital asset amount below the threshold. 741 * 742 * @param assetAmount 743 * @param capitalizationThresholdAmount 744 * @return 745 */ 746 protected boolean validateNonCapitalAssetAmountBelowThreshold(KualiDecimal assetAmount, String capitalizationThresholdAmount) { 747 boolean success = true; 748 if (assetAmount.isGreaterEqual(new KualiDecimal(capitalizationThresholdAmount))) { 749 putFieldError(CamsPropertyConstants.AssetGlobal.INVENTORY_STATUS_CODE, CamsKeyConstants.AssetGlobal.ERROR_NON_CAPITAL_ASSET_PAYMENT_AMOUNT_MAX, capitalizationThresholdAmount); 750 success &= false; 751 } 752 return success; 753 } 754 755 /** 756 * Validate that the total cost of the source asset is not zero or a negative amount. 757 * 758 * @param assetGlobal 759 * @return boolean 760 */ 761 protected boolean validateTotalCostAmount(AssetGlobal assetGlobal) { 762 boolean success = true; 763 if (!assetGlobal.getTotalCostAmount().isGreaterThan(KualiDecimal.ZERO)) { 764 GlobalVariables.getMessageMap().putErrorForSectionId(CamsConstants.AssetGlobal.SECTION_ID_ASSET_INFORMATION, CamsKeyConstants.AssetSeparate.ERROR_ZERO_OR_NEGATIVE_DOLLAR_AMOUNT); 765 success &= false; 766 } 767 return success; 768 } 769 770 /** 771 * Validates the capital asset type code. This only checks for the existence of some contents, not whether the contents are valid. 772 * 773 * @param uniqueLocationDetails 774 * @return boolean 775 */ 776 protected boolean validateCapitalAssetTypeCode(AssetGlobalDetail uniqueLocationDetails) { 777 boolean success = true; 778 if (StringUtils.isEmpty(uniqueLocationDetails.getCapitalAssetTypeCode())) { 779 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.CAPITAL_ASSET_TYPE_CODE, CamsKeyConstants.AssetSeparate.ERROR_CAPITAL_ASSET_TYPE_CODE_REQUIRED, uniqueLocationDetails.getCapitalAssetTypeCode()); 780 success &= false; 781 } 782 return success; 783 } 784 785 /** 786 * Validates the asset description. 787 * 788 * @param uniqueLocationDetails 789 * @return boolean 790 */ 791 protected boolean validateAssetDescription(AssetGlobalDetail uniqueLocationDetails) { 792 boolean success = true; 793 if (StringUtils.isEmpty(uniqueLocationDetails.getCapitalAssetDescription())) { 794 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.CAPITAL_ASSET_DESCRIPTION, CamsKeyConstants.AssetSeparate.ERROR_ASSET_DESCRIPTION_REQUIRED, uniqueLocationDetails.getCapitalAssetTypeCode()); 795 success &= false; 796 } 797 return success; 798 } 799 800 /** 801 * Validates the manufacturer. 802 * 803 * @param uniqueLocationDetails 804 * @return boolean 805 */ 806 protected boolean validateManufacturer(AssetGlobalDetail uniqueLocationDetails) { 807 boolean success = true; 808 if (StringUtils.isEmpty(uniqueLocationDetails.getManufacturerName())) { 809 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.MANUFACTURER_NAME, CamsKeyConstants.AssetSeparate.ERROR_MANUFACTURER_REQUIRED, uniqueLocationDetails.getCapitalAssetTypeCode()); 810 success &= false; 811 } 812 return success; 813 } 814 815 /** 816 * Validates the separate source amount. 817 * 818 * @param uniqueLocationDetails 819 * @return boolean 820 */ 821 protected boolean validateSeparateSourceAmount(AssetGlobalDetail uniqueLocationDetail, MaintenanceDocument document) { 822 boolean success = true; 823 KualiDecimal separateSourceAmount = uniqueLocationDetail.getSeparateSourceAmount(); 824 if (separateSourceAmount == null || separateSourceAmount.isLessEqual(KualiDecimal.ZERO)) { 825 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.SEPARATE_SOURCE_AMOUNT, CamsKeyConstants.AssetSeparate.ERROR_TOTAL_SEPARATE_SOURCE_AMOUNT_REQUIRED); 826 success &= false; 827 } 828 else { 829 // for capital asset separate, validate the minimal separate source amount above the threshold 830 success &= validateSeparateSourceAmountAboveThreshold(document, uniqueLocationDetail); 831 } 832 return success; 833 } 834 835 protected boolean validateLocationCollection(AssetGlobal assetGlobal, List<AssetGlobalDetail> assetSharedDetails) { 836 boolean success = true; 837 // for each shared location info, validate 838 boolean isCapitalAsset = isCapitalStatus(assetGlobal); 839 int index = 0; 840 for (AssetGlobalDetail assetLocationDetail : assetSharedDetails) { 841 String errorPath = MAINTAINABLE_ERROR_PREFIX + CamsPropertyConstants.AssetGlobal.ASSET_SHARED_DETAILS + "[" + index + "]"; 842 GlobalVariables.getMessageMap().addToErrorPath(errorPath); 843 success &= SpringContext.getBean(AssetLocationService.class).validateLocation(LOCATION_FIELD_MAP, assetLocationDetail, isCapitalAsset, assetGlobal.getCapitalAssetType()); 844 GlobalVariables.getMessageMap().removeFromErrorPath(errorPath); 845 index++; 846 } 847 return success; 848 } 849 850 @Override 851 protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) { 852 AssetGlobal assetGlobal = (AssetGlobal) document.getNewMaintainableObject().getBusinessObject(); 853 boolean success = true; 854 success &= super.processCustomSaveDocumentBusinessRules(document); 855 if (GlobalVariables.getMessageMap().hasErrors()) { 856 return false; 857 } 858 859 String acquisitionTypeCode = assetGlobal.getAcquisitionTypeCode(); 860 String statusCode = assetGlobal.getInventoryStatusCode(); 861 862 // no need to validate specific fields if document is "Asset Separate" 863 if (!getAssetGlobalService().isAssetSeparate(assetGlobal)) { 864 success &= validateAccount(assetGlobal); 865 if (StringUtils.isNotBlank(acquisitionTypeCode) && StringUtils.isNotBlank(statusCode)) { 866 // check if status code and acquisition type code combination is valid 867 success &= SpringContext.getBean(ParameterService.class).getParameterEvaluator(AssetGlobal.class, CamsConstants.Parameters.VALID_ASSET_STATUSES_BY_ACQUISITION_TYPE, CamsConstants.Parameters.INVALID_ASSET_STATUSES_BY_ACQUISITION_TYPE, acquisitionTypeCode, statusCode).evaluateAndAddError(AssetGlobal.class, CamsPropertyConstants.AssetGlobal.INVENTORY_STATUS_CODE, MAINTAINABLE_ERROR_PREFIX + CamsPropertyConstants.AssetGlobal.INVENTORY_STATUS_CODE); 868 } 869 success &= validateAssetType(assetGlobal); 870 if (isCapitalStatus(assetGlobal)) { 871 success &= validateVendorAndManufacturer(assetGlobal); 872 } 873 874 success &= validatePaymentCollection(document, assetGlobal); 875 } 876 else { 877 // append doc type to existing doc header description 878 if (!document.getDocumentHeader().getDocumentDescription().toLowerCase().contains(CamsConstants.AssetSeparate.SEPARATE_AN_ASSET_DESCRIPTION.toLowerCase())) { 879 document.getDocumentHeader().setDocumentDescription(CamsConstants.AssetSeparate.SEPARATE_AN_ASSET_DESCRIPTION + " " + document.getDocumentHeader().getDocumentDescription()); 880 } 881 } 882 883 // System shall only generate GL entries if we have an incomeAssetObjectCode for this acquisitionTypeCode and the statusCode 884 // is for capital assets 885 if ((success && super.processCustomSaveDocumentBusinessRules(document)) && getAssetAcquisitionTypeService().hasIncomeAssetObjectCode(acquisitionTypeCode) && this.isCapitalStatus(assetGlobal)) { 886 if (success &= validateAcquisitionIncomeObjectCode(assetGlobal)) { 887 // create poster 888 AssetGlobalGeneralLedgerPendingEntrySource assetGlobalGlPoster = new AssetGlobalGeneralLedgerPendingEntrySource((FinancialSystemDocumentHeader) document.getDocumentHeader()); 889 // create postables 890 getAssetGlobalService().createGLPostables(assetGlobal, assetGlobalGlPoster); 891 892 if (SpringContext.getBean(GeneralLedgerPendingEntryService.class).generateGeneralLedgerPendingEntries(assetGlobalGlPoster)) { 893 assetGlobal.setGeneralLedgerPendingEntries(assetGlobalGlPoster.getPendingEntries()); 894 } 895 else { 896 assetGlobalGlPoster.getPendingEntries().clear(); 897 } 898 } 899 } 900 901 return success; 902 } 903 904 /** 905 * Locking on separate source asset number 906 * 907 * @param document 908 * @param assetGlobal 909 * @return 910 */ 911 protected boolean setAssetLock(MaintenanceDocument document, AssetGlobal assetGlobal) { 912 List<Long> capitalAssetNumbers = new ArrayList<Long>(); 913 if (assetGlobal.getSeparateSourceCapitalAssetNumber() != null) { 914 capitalAssetNumbers.add(assetGlobal.getSeparateSourceCapitalAssetNumber()); 915 } 916 917 return SpringContext.getBean(CapitalAssetManagementModuleService.class).storeAssetLocks(capitalAssetNumbers, document.getDocumentNumber(), DocumentTypeName.ASSET_SEPARATE, null); 918 } 919 920 /** 921 * Validate offset object code 922 * 923 * @param assetGlobal 924 * @return 925 */ 926 protected boolean validateAcquisitionIncomeObjectCode(AssetGlobal assetGlobal) { 927 boolean valid = true; 928 for (AssetPaymentDetail assetPaymentDetail : assetGlobal.getAssetPaymentDetails()) { 929 // check offset object code existence 930 ObjectCode objectCode = SpringContext.getBean(ObjectCodeService.class).getByPrimaryId(assetPaymentDetail.getPostingYear(), assetPaymentDetail.getChartOfAccountsCode(), assetGlobal.getAcquisitionType().getIncomeAssetObjectCode()); 931 if (ObjectUtils.isNull(objectCode)) { 932 putFieldError(CamsPropertyConstants.AssetGlobal.ACQUISITION_TYPE_CODE, CamsKeyConstants.AssetGlobal.ERROR_INVALID_ACQUISITION_INCOME_OBJECT_CODE, new String[] { assetGlobal.getAcquisitionType().getIncomeAssetObjectCode(), assetPaymentDetail.getPostingYear().toString(), assetPaymentDetail.getChartOfAccountsCode() }); 933 valid = false; 934 } 935 // check Object Code active 936 else if (!objectCode.isActive()) { 937 putFieldError(CamsPropertyConstants.AssetGlobal.ACQUISITION_TYPE_CODE, CamsKeyConstants.GLPosting.ERROR_OBJECT_CODE_FROM_ASSET_OBJECT_CODE_INACTIVE, new String[] { CamsConstants.GLPostingObjectCodeType.INCOME, assetGlobal.getAcquisitionType().getIncomeAssetObjectCode(), assetPaymentDetail.getChartOfAccountsCode() }); 938 valid = false; 939 } 940 } 941 return valid; 942 } 943 944 protected boolean validatePaymentCollection(MaintenanceDocument maintenanceDocument, AssetGlobal assetGlobal) { 945 boolean success = true; 946 int index = 0; 947 for (AssetPaymentDetail assetPaymentDetail : assetGlobal.getAssetPaymentDetails()) { 948 String errorPath = MAINTAINABLE_ERROR_PREFIX + CamsPropertyConstants.AssetGlobal.ASSET_PAYMENT_DETAILS + "[" + index + "]"; 949 GlobalVariables.getMessageMap().addToErrorPath(errorPath); 950 success &= validatePaymentLine(maintenanceDocument, assetGlobal, assetPaymentDetail); 951 GlobalVariables.getMessageMap().removeFromErrorPath(errorPath); 952 index++; 953 } 954 return success; 955 } 956 957 protected boolean validateVendorAndManufacturer(AssetGlobal assetGlobal) { 958 boolean success = true; 959 if (StringUtils.isBlank(assetGlobal.getVendorName())) { 960 putFieldError(CamsPropertyConstants.AssetGlobal.VENDOR_NAME, CamsKeyConstants.AssetGlobal.ERROR_VENDOR_NAME_REQUIRED); 961 success &= false; 962 } 963 if (StringUtils.isBlank(assetGlobal.getManufacturerName())) { 964 putFieldError(CamsPropertyConstants.AssetGlobal.MFR_NAME, CamsKeyConstants.AssetGlobal.ERROR_MFR_NAME_REQUIRED); 965 success &= false; 966 } 967 return success; 968 } 969 970 @Override 971 public boolean processSaveDocument(Document document) { 972 boolean valid = true; 973 MaintenanceDocument maintenanceDocument = (MaintenanceDocument) document; 974 AssetGlobal assetGlobal = (AssetGlobal) maintenanceDocument.getNewMaintainableObject().getBusinessObject(); 975 976 List<AssetGlobalDetail> assetSharedDetails = assetGlobal.getAssetSharedDetails(); 977 int index = 0; 978 for (AssetGlobalDetail assetLocationDetail : assetSharedDetails) { 979 String errorPath = MAINTAINABLE_ERROR_PREFIX + CamsPropertyConstants.AssetGlobal.ASSET_SHARED_DETAILS + "[" + index + "]"; 980 GlobalVariables.getMessageMap().addToErrorPath(errorPath); 981 valid &= checkReferenceExists(assetLocationDetail); 982 GlobalVariables.getMessageMap().removeFromErrorPath(errorPath); 983 984 // checks that all of the asset types entered in the collection of Unique Details actually exist in persistent storage 985 int indexUniqueDetails = 0; 986 for (AssetGlobalDetail assetGlobalUniqueDetails : assetLocationDetail.getAssetGlobalUniqueDetails()) { 987 valid &= validateAssetType(assetGlobalUniqueDetails, index, indexUniqueDetails); 988 indexUniqueDetails++; 989 } 990 index++; 991 } 992 993 994 // Creates locking representation for this global document. The locking is only applicable for assets that are being split. 995 // The assets that are being created do not need to be locked since they don't exist yet. 996 if (valid && getAssetGlobalService().isAssetSeparate(assetGlobal)) { 997 valid &= setAssetLock(maintenanceDocument, assetGlobal); 998 } 999 1000 return valid && super.processSaveDocument(document); 1001 } 1002 1003 protected boolean validateAccount(AssetGlobal assetGlobal) { 1004 boolean success = true; 1005 assetGlobal.refreshReferenceObject(CamsPropertyConstants.AssetGlobal.ORGANIZATION_OWNER_ACCOUNT); 1006 Account organizationOwnerAccount = assetGlobal.getOrganizationOwnerAccount(); 1007 1008 boolean skipAccountAvailiablityCheck; 1009 if (StringUtils.isBlank(assetGlobal.getOrganizationOwnerChartOfAccountsCode()) || StringUtils.isBlank(assetGlobal.getOrganizationOwnerAccountNumber())) { 1010 skipAccountAvailiablityCheck = true; 1011 } 1012 else { 1013 skipAccountAvailiablityCheck = isOrgOwnerAccountFromCab(assetGlobal); 1014 } 1015 1016 // when check if organizationOwnerAccount is existing, use ObjectUtils rather than comparing with 'null' since OJB proxy 1017 // object is used here. 1018 if (!skipAccountAvailiablityCheck && (ObjectUtils.isNull(organizationOwnerAccount) || !organizationOwnerAccount.isActive() || organizationOwnerAccount.isExpired())) { 1019 putFieldError(CamsPropertyConstants.AssetGlobal.ORGANIZATION_OWNER_ACCOUNT_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_OWNER_ACCT_NOT_ACTIVE, new String[] { assetGlobal.getOrganizationOwnerChartOfAccountsCode(), assetGlobal.getOrganizationOwnerAccountNumber() }); 1020 success &= false; 1021 } 1022 return success; 1023 } 1024 1025 1026 /** 1027 * Check if organization owner account is set from CAB. We honor all accounting lines from CAB are valid payments even thougth 1028 * they are expired. 1029 * 1030 * @param assetGlobal 1031 * @return 1032 */ 1033 protected boolean isOrgOwnerAccountFromCab(AssetGlobal assetGlobal) { 1034 String orgOwnerChartCode = assetGlobal.getOrganizationOwnerChartOfAccountsCode(); 1035 String orgOwnerAccountNbr = assetGlobal.getOrganizationOwnerAccountNumber(); 1036 1037 if (StringUtils.isBlank(assetGlobal.getOrganizationOwnerChartOfAccountsCode()) || StringUtils.isBlank(assetGlobal.getOrganizationOwnerAccountNumber())) { 1038 return true; 1039 } 1040 1041 if (assetGlobal.isCapitalAssetBuilderOriginIndicator()) { 1042 // If CAB submits, allow use of inactive accounting line from the payments 1043 for (AssetPaymentDetail assetPaymentDetail : assetGlobal.getAssetPaymentDetails()) { 1044 if (orgOwnerChartCode.equalsIgnoreCase(assetPaymentDetail.getChartOfAccountsCode()) && orgOwnerAccountNbr.equalsIgnoreCase(assetPaymentDetail.getAccountNumber())) { 1045 return true; 1046 } 1047 } 1048 } 1049 1050 return false; 1051 } 1052 1053 /** 1054 * Validate location 1055 * 1056 * @param assetGlobal 1057 * @return boolean 1058 */ 1059 protected boolean validateLocation(AssetGlobal assetGlobal, AssetGlobalDetail assetGlobalDetail) { 1060 boolean success = true; 1061 if (StringUtils.isBlank(assetGlobal.getInventoryStatusCode())) { 1062 putFieldError(CamsPropertyConstants.AssetGlobal.INVENTORY_STATUS_CODE, CamsKeyConstants.AssetGlobal.ERROR_INVENTORY_STATUS_REQUIRED); 1063 success &= false; 1064 } 1065 success = validateAssetType(assetGlobal); 1066 if (success) { 1067 boolean isCapitalAsset = isCapitalStatus(assetGlobal); 1068 success &= SpringContext.getBean(AssetLocationService.class).validateLocation(LOCATION_FIELD_MAP, assetGlobalDetail, isCapitalAsset, assetGlobal.getCapitalAssetType()); 1069 } 1070 else { 1071 putFieldError(CamsPropertyConstants.AssetGlobal.CAPITAL_ASSET_TYPE_CODE, CamsKeyConstants.AssetGlobal.ERROR_ASSET_LOCATION_DEPENDENCY); 1072 } 1073 return success; 1074 } 1075 1076 /** 1077 * Validate asset type at the AssetGlobal level. Only checks that there are contents in the object. 1078 * 1079 * @param assetGlobal 1080 * @return boolean 1081 */ 1082 protected boolean validateAssetType(AssetGlobal assetGlobal) { 1083 boolean success = true; 1084 assetGlobal.refreshReferenceObject(CamsPropertyConstants.AssetGlobal.CAPITAL_ASSET_TYPE); 1085 if (ObjectUtils.isNull(assetGlobal.getCapitalAssetType())) { 1086 putFieldError(CamsPropertyConstants.AssetGlobalDetail.ASSET_UNIQUE_DETAILS, CamsKeyConstants.AssetGlobal.ERROR_ASSET_TYPE_REQUIRED); 1087 success &= false; 1088 } 1089 1090 return success; 1091 } 1092 1093 /** 1094 * Validate asset type in the AssetGlobalUniqueDetails level, and ensures the value is in the list of valid types. 1095 * The incoming indices are for creation of the errorPath for the global variable message map, which will determine 1096 * what text field to mark as having a problem. This was written to be called within a loop. 1097 * 1098 * @param assetGlobalUniqueDetails 1099 * @param sharedIndex the index of the shared details within the AssetGlobal 1100 * @param uniqueIndex the index of the unique details within the shared details 1101 * @return boolean 1102 */ 1103 protected boolean validateAssetType(AssetGlobalDetail assetGlobalUniqueDetails, Integer sharedIndex, Integer uniqueIndex) { 1104 boolean success = true; 1105 int sharedInd = 0; 1106 int uniqueInd = 0; 1107 1108 // In hindsite, maybe this should have been written to perform the loop-within-loop fully contained within this 1109 // method, and not used within the typical double loop structure of processSaveDocument() and 1110 // processCustomRouteDecumentBusinessRules. 1111 1112 // don't change the value of the incoming param! 1113 if (sharedIndex != null) { 1114 sharedInd = sharedIndex; 1115 } 1116 if (uniqueIndex != null) { 1117 uniqueInd = uniqueIndex; 1118 } 1119 1120 if (ObjectUtils.isNull(assetGlobalUniqueDetails)) { 1121 putFieldError(CamsPropertyConstants.AssetGlobalDetail.ASSET_UNIQUE_DETAILS, CamsKeyConstants.AssetGlobal.ERROR_ASSET_LOCATION_DEPENDENCY); 1122 success &= false; 1123 } 1124 1125 // validate asset type 1126 if (StringUtils.isNotBlank(assetGlobalUniqueDetails.getCapitalAssetTypeCode())) { 1127 AssetType assetType = SpringContext.getBean(BusinessObjectService.class).findBySinglePrimaryKey(AssetType.class, assetGlobalUniqueDetails.getCapitalAssetTypeCode()); 1128 if (assetType == null || StringUtils.isBlank(assetType.getCapitalAssetTypeCode())) { 1129 String errorPath = MAINTAINABLE_ERROR_PREFIX + CamsPropertyConstants.AssetGlobal.ASSET_SHARED_DETAILS + "[" + sharedInd + "]." + CamsPropertyConstants.AssetGlobalDetail.ASSET_UNIQUE_DETAILS + "[" + uniqueInd + "]"; 1130 GlobalVariables.getMessageMap().addToErrorPath(errorPath); 1131 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetGlobalDetail.CAPITAL_ASSET_TYPE_CODE, CamsKeyConstants.AssetSeparate.ERROR_CAPITAL_ASSET_TYPE_CODE_INVALID, assetGlobalUniqueDetails.getCapitalAssetTypeCode()); 1132 GlobalVariables.getMessageMap().removeFromErrorPath(errorPath); 1133 success &= false; 1134 } 1135 } 1136 1137 return success; 1138 } 1139 1140 /** 1141 * Give an error if this asset can't be separated due to mismatching amount on asset and AssetPayment records 1142 * 1143 * @param assetGlobal 1144 * @return validation success of failure 1145 */ 1146 public static boolean validateAssetTotalCostMatchesPaymentTotalCost(AssetGlobal assetGlobal) { 1147 PaymentSummaryService paymentSummaryService = SpringContext.getBean(PaymentSummaryService.class); 1148 assetGlobal.refreshReferenceObject(CamsPropertyConstants.AssetGlobal.SEPARATE_SOURCE_CAPITAL_ASSET); 1149 KualiDecimal assetTotalCost = ObjectUtils.isNull(assetGlobal.getSeparateSourceCapitalAsset().getTotalCostAmount()) ? new KualiDecimal(0) : assetGlobal.getSeparateSourceCapitalAsset().getTotalCostAmount(); 1150 KualiDecimal paymentTotalCost = paymentSummaryService.calculatePaymentTotalCost(assetGlobal.getSeparateSourceCapitalAsset()); 1151 if (!paymentTotalCost.equals(assetTotalCost)) { 1152 GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(MAINTAINABLE_ERROR_PREFIX + CamsPropertyConstants.AssetGlobal.SEPARATE_SOURCE_CAPITAL_ASSET_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_SEPARATE_ASSET_TOTAL_COST_NOT_MATCH_PAYMENT_TOTAL_COST); 1153 1154 return false; 1155 } 1156 1157 return true; 1158 } 1159 1160 /** 1161 * Give an error if this asset has already been separated 1162 * 1163 * @param assetGlobal 1164 * @return validation success of failure 1165 */ 1166 public static boolean validateAssetAlreadySeparated(Long separateSourceCapitalAssetNumber) { 1167 AssetService assetService = SpringContext.getBean(AssetService.class); 1168 1169 List<String> documentNumbers = assetService.getDocumentNumbersThatSeparatedThisAsset(separateSourceCapitalAssetNumber); 1170 1171 if (!documentNumbers.isEmpty()) { 1172 GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(MAINTAINABLE_ERROR_PREFIX + CamsPropertyConstants.AssetGlobal.SEPARATE_SOURCE_CAPITAL_ASSET_NUMBER, CamsKeyConstants.AssetGlobal.ERROR_SEPARATE_ASSET_ALREADY_SEPARATED, new String[] { documentNumbers.toString() }); 1173 1174 return false; 1175 } 1176 1177 return true; 1178 } 1179 1180 protected ParameterService getParameterService() { 1181 return SpringContext.getBean(ParameterService.class); 1182 } 1183 1184 protected AssetService getAssetService() { 1185 return SpringContext.getBean(AssetService.class); 1186 } 1187 1188 protected AssetPaymentService getAssetPaymentService() { 1189 return SpringContext.getBean(AssetPaymentService.class); 1190 } 1191 1192 protected AssetAcquisitionTypeService getAssetAcquisitionTypeService() { 1193 return SpringContext.getBean(AssetAcquisitionTypeService.class); 1194 } 1195 1196 protected AssetGlobalService getAssetGlobalService() { 1197 return SpringContext.getBean(AssetGlobalService.class); 1198 } 1199 }