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 static org.kuali.kfs.module.cam.CamsKeyConstants.ERROR_INVALID_ASSET_WARRANTY_NO;
019 import static org.kuali.kfs.module.cam.CamsPropertyConstants.Asset.ASSET_WARRANTY_WARRANTY_NUMBER;
020
021 import java.sql.Timestamp;
022 import java.util.ArrayList;
023 import java.util.Collection;
024 import java.util.Date;
025 import java.util.HashMap;
026 import java.util.HashSet;
027 import java.util.List;
028 import java.util.Map;
029 import java.util.Set;
030
031 import org.apache.commons.lang.StringUtils;
032 import org.kuali.kfs.coa.businessobject.Account;
033 import org.kuali.kfs.integration.cam.CapitalAssetManagementModuleService;
034 import org.kuali.kfs.module.cam.CamsConstants;
035 import org.kuali.kfs.module.cam.CamsKeyConstants;
036 import org.kuali.kfs.module.cam.CamsPropertyConstants;
037 import org.kuali.kfs.module.cam.businessobject.Asset;
038 import org.kuali.kfs.module.cam.businessobject.AssetComponent;
039 import org.kuali.kfs.module.cam.businessobject.AssetFabrication;
040 import org.kuali.kfs.module.cam.businessobject.AssetLocation;
041 import org.kuali.kfs.module.cam.businessobject.AssetRepairHistory;
042 import org.kuali.kfs.module.cam.businessobject.AssetWarranty;
043 import org.kuali.kfs.module.cam.businessobject.defaultvalue.NextAssetNumberFinder;
044 import org.kuali.kfs.module.cam.document.service.AssetComponentService;
045 import org.kuali.kfs.module.cam.document.service.AssetDateService;
046 import org.kuali.kfs.module.cam.document.service.AssetLocationService;
047 import org.kuali.kfs.module.cam.document.service.AssetLocationService.LocationField;
048 import org.kuali.kfs.module.cam.document.service.AssetService;
049 import org.kuali.kfs.module.cam.document.service.EquipmentLoanOrReturnService;
050 import org.kuali.kfs.module.cam.document.service.PaymentSummaryService;
051 import org.kuali.kfs.module.cam.document.service.RetirementInfoService;
052 import org.kuali.kfs.sys.context.SpringContext;
053 import org.kuali.kfs.sys.service.UniversityDateService;
054 import org.kuali.rice.kns.bo.PersistableBusinessObject;
055 import org.kuali.rice.kns.document.MaintenanceDocument;
056 import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
057 import org.kuali.rice.kns.service.DateTimeService;
058 import org.kuali.rice.kns.service.ParameterService;
059 import org.kuali.rice.kns.util.DateUtils;
060 import org.kuali.rice.kns.util.GlobalVariables;
061 import org.kuali.rice.kns.util.KualiDecimal;
062 import org.kuali.rice.kns.util.ObjectUtils;
063 import org.kuali.rice.kns.util.TypedArrayList;
064 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
065
066 /**
067 * AssetRule for Asset edit.
068 */
069 public class AssetRule extends MaintenanceDocumentRuleBase {
070 protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AssetRule.class);
071 protected static final Map<LocationField, String> LOCATION_FIELD_MAP = new HashMap<LocationField, String>();
072 static {
073 LOCATION_FIELD_MAP.put(LocationField.CAMPUS_CODE, CamsPropertyConstants.Asset.CAMPUS_CODE);
074 LOCATION_FIELD_MAP.put(LocationField.BUILDING_CODE, CamsPropertyConstants.Asset.BUILDING_CODE);
075 LOCATION_FIELD_MAP.put(LocationField.ROOM_NUMBER, CamsPropertyConstants.Asset.BUILDING_ROOM_NUMBER);
076 LOCATION_FIELD_MAP.put(LocationField.SUB_ROOM_NUMBER, CamsPropertyConstants.Asset.BUILDING_SUB_ROOM_NUMBER);
077 LOCATION_FIELD_MAP.put(LocationField.CONTACT_NAME, CamsPropertyConstants.Asset.AssetLocation.CONTACT_NAME);
078 LOCATION_FIELD_MAP.put(LocationField.STREET_ADDRESS, CamsPropertyConstants.Asset.AssetLocation.STREET_ADDRESS);
079 LOCATION_FIELD_MAP.put(LocationField.CITY_NAME, CamsPropertyConstants.Asset.AssetLocation.CITY_NAME);
080 LOCATION_FIELD_MAP.put(LocationField.STATE_CODE, CamsPropertyConstants.Asset.AssetLocation.STATE_CODE);
081 LOCATION_FIELD_MAP.put(LocationField.ZIP_CODE, CamsPropertyConstants.Asset.AssetLocation.ZIP_CODE);
082 LOCATION_FIELD_MAP.put(LocationField.COUNTRY_CODE, CamsPropertyConstants.Asset.AssetLocation.COUNTRY_CODE);
083 }
084
085 // protected AgencyService agencyService = SpringContext.getBean(AgencyService.class);
086 protected AssetService assetService = SpringContext.getBean(AssetService.class);
087 protected ParameterService parameterService = SpringContext.getBean(ParameterService.class);
088 protected PaymentSummaryService paymentSummaryService = SpringContext.getBean(PaymentSummaryService.class);
089 protected RetirementInfoService retirementInfoService = SpringContext.getBean(RetirementInfoService.class);
090 protected EquipmentLoanOrReturnService equipmentLoanOrReturnService = SpringContext.getBean(EquipmentLoanOrReturnService.class);
091 protected AssetDateService assetDateService = SpringContext.getBean(AssetDateService.class);
092 protected AssetComponentService assetComponentService = SpringContext.getBean(AssetComponentService.class);
093 protected UniversityDateService universityDateService = SpringContext.getBean(UniversityDateService.class);
094 protected AssetLocationService assetLocationService = SpringContext.getBean(AssetLocationService.class);
095 protected DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class);
096
097 protected Asset newAsset;
098 protected Asset oldAsset;
099 protected boolean isFabrication;
100
101
102 /**
103 * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomSaveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
104 */
105 @Override
106 protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) {
107 initializeAttributes(document);
108 boolean valid = true;
109 if (SpringContext.getBean(AssetService.class).isAssetFabrication(document)) {
110 this.isFabrication = true;
111 valid &= validateAccount();
112 valid &= validateLocation();
113 valid &= validateFabricationDetails();
114 }
115 else {
116 setAssetComponentNumbers(newAsset);
117 paymentSummaryService.calculateAndSetPaymentSummary(oldAsset);
118 paymentSummaryService.calculateAndSetPaymentSummary(newAsset);
119
120 assetService.setSeparateHistory(oldAsset);
121 assetService.setSeparateHistory(newAsset);
122
123 retirementInfoService.setRetirementInfo(oldAsset);
124 retirementInfoService.setRetirementInfo(newAsset);
125
126 equipmentLoanOrReturnService.setEquipmentLoanInfo(oldAsset);
127 equipmentLoanOrReturnService.setEquipmentLoanInfo(newAsset);
128
129 valid &= processAssetValidation(document);
130 valid &= validateWarrantyInformation(newAsset);
131 valid &= validateDepreciationData(newAsset);
132
133 valid &= super.processCustomSaveDocumentBusinessRules(document);
134 if (valid) {
135 assetDateService.checkAndUpdateLastInventoryDate(oldAsset, newAsset);
136 assetDateService.checkAndUpdateDepreciationDate(oldAsset, newAsset);
137 assetDateService.checkAndUpdateFiscalYearAndPeriod(oldAsset, newAsset);
138 }
139
140 valid &= checkAssetLocked(document);
141 }
142 return valid;
143 }
144
145 /**
146 * Check if asset is locked by other document.
147 *
148 * @param document
149 * @param valid
150 * @return
151 */
152 protected boolean checkAssetLocked(MaintenanceDocument document) {
153 Asset asset = (Asset) document.getNewMaintainableObject().getBusinessObject();
154 return !getCapitalAssetManagementModuleService().isAssetLocked(retrieveAssetNumberForLocking(asset), CamsConstants.DocumentTypeName.ASSET_EDIT, document.getDocumentNumber());
155 }
156
157 /**
158 * Retrieve asset numbers need to be locked.
159 *
160 * @return
161 */
162 protected List<Long> retrieveAssetNumberForLocking(Asset asset) {
163 List<Long> capitalAssetNumbers = new ArrayList<Long>();
164 if (asset.getCapitalAssetNumber() != null) {
165 capitalAssetNumbers.add(asset.getCapitalAssetNumber());
166 }
167 return capitalAssetNumbers;
168 }
169
170 /**
171 * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomAddCollectionLineBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument,
172 * java.lang.String, org.kuali.rice.kns.bo.PersistableBusinessObject)
173 */
174 @Override
175 public boolean processCustomAddCollectionLineBusinessRules(MaintenanceDocument documentCopy, String collectionName, PersistableBusinessObject bo) {
176 boolean success = true;
177
178 // get all incidentDates from AssetRepairHistory collection and check for duplicate dates.
179 if (collectionName.equals(CamsConstants.Asset.COLLECTION_ID_ASSET_REPAIR_HISTORY)) {
180
181 Asset asset = (Asset) documentCopy.getNewMaintainableObject().getBusinessObject();
182 Set<Date> incidentDateSet = new HashSet<Date>();
183
184 for (AssetRepairHistory assetRepairHistory : asset.getAssetRepairHistory()) {
185 if (assetRepairHistory.getIncidentDate() != null) {
186 incidentDateSet.add(assetRepairHistory.getIncidentDate());
187 }
188 }
189
190 AssetRepairHistory assetRepairHistoryDetails = (AssetRepairHistory) bo;
191
192 success &= checkDuplicateIncidentDate(assetRepairHistoryDetails, incidentDateSet);
193
194 return success & super.processCustomAddCollectionLineBusinessRules(documentCopy, collectionName, bo);
195 }
196
197 return success;
198 }
199
200 /**
201 * Check for duplicate incident dates within the Repair History section
202 *
203 * @param assetRepairHistory
204 * @param incidentDateSet
205 * @return boolean
206 */
207 protected boolean checkDuplicateIncidentDate(AssetRepairHistory assetRepairHistory, Set<Date> incidentDateSet) {
208 boolean success = true;
209
210 if (!incidentDateSet.add(assetRepairHistory.getIncidentDate())) {
211 GlobalVariables.getMessageMap().putError(CamsPropertyConstants.AssetRepairHistory.INCIDENT_DATE, CamsKeyConstants.AssetRepairHistory.ERROR_DUPLICATE_INCIDENT_DATE);
212 success &= false;
213 }
214
215 return success;
216 }
217
218 /**
219 * Validate fabrication details
220 *
221 * @return boolean
222 */
223 protected boolean validateFabricationDetails() {
224 /**
225 * Please don't remove this validation, forcing required fields from DD file is not possible and will break asset edit
226 * screen, so please leave this validation here.
227 */
228 boolean valid = true;
229 if (newAsset.getFabricationEstimatedTotalAmount() != null && newAsset.getFabricationEstimatedTotalAmount().isNegative()) {
230 putFieldError(CamsPropertyConstants.Asset.FABRICATION_ESTIMATED_TOTAL_AMOUNT, CamsKeyConstants.ERROR_FABRICATION_ESTIMATED_TOTAL_AMOUNT_NEGATIVE);
231 valid &= false;
232 }
233 if (newAsset.getEstimatedFabricationCompletionDate() != null && newAsset.getEstimatedFabricationCompletionDate().before(DateUtils.clearTimeFields(dateTimeService.getCurrentDate()))) {
234 putFieldError(CamsPropertyConstants.Asset.ESTIMATED_FABRICATION_COMPLETION_DATE, CamsKeyConstants.ERROR_ESTIMATED_FABRICATION_COMPLETION_DATE_PAST);
235 valid &= false;
236 }
237 if (newAsset.getFabricationEstimatedRetentionYears() != null && newAsset.getFabricationEstimatedRetentionYears().intValue() < 0) {
238 putFieldError(CamsPropertyConstants.Asset.FABRICATION_ESTIMATED_RETENTION_YEARS, CamsKeyConstants.ERROR_ESTIMATED_FABRICATION_LIFE_LIMIT_NEGATIVE);
239 valid &= false;
240 }
241 return valid;
242 }
243
244 /**
245 * Validate account
246 *
247 * @return boolean
248 */
249 protected boolean validateAccount() {
250 boolean valid = true;
251 Account currentOwnerAccount = newAsset.getOrganizationOwnerAccount();
252 Account previoudOwnerAccount = oldAsset.getOrganizationOwnerAccount();
253
254 // Account is valid?
255 if (ObjectUtils.isNull(currentOwnerAccount) && StringUtils.isNotBlank(newAsset.getOrganizationOwnerAccountNumber())) {
256 putFieldError(CamsPropertyConstants.Asset.ORGANIZATION_OWNER_ACCOUNT_NUMBER, CamsKeyConstants.ORGANIZATION_OWNER_ACCOUNT_INVALID);
257 valid &= false;
258 }
259
260 // check if values changed, if not return
261 if (ObjectUtils.isNotNull(previoudOwnerAccount) && ObjectUtils.isNotNull(currentOwnerAccount) && previoudOwnerAccount.getChartOfAccountsCode().equals(currentOwnerAccount.getChartOfAccountsCode()) && previoudOwnerAccount.getAccountNumber().equals(currentOwnerAccount.getAccountNumber())) {
262 return valid;
263
264 }
265 else if (ObjectUtils.isNotNull(currentOwnerAccount) && (currentOwnerAccount.isExpired() || !currentOwnerAccount.isActive())) {
266 // Account is not active
267 putFieldError(CamsPropertyConstants.Asset.ORGANIZATION_OWNER_ACCOUNT_NUMBER, CamsKeyConstants.ORGANIZATION_OWNER_ACCOUNT_INACTIVE);
268 valid &= false;
269 }
270 return valid;
271 }
272
273 /**
274 * Set asset component numbers
275 *
276 * @param asset
277 */
278 protected void setAssetComponentNumbers(Asset asset) {
279 List<AssetComponent> assetComponents = asset.getAssetComponents();
280 Integer maxNo = null;
281 for (AssetComponent assetComponent : assetComponents) {
282 assetComponent.setCapitalAssetNumber(asset.getCapitalAssetNumber());
283 if (maxNo == null) {
284 maxNo = assetComponentService.getMaxSequenceNumber(assetComponent);
285 }
286 if (assetComponent.getComponentNumber() == null) {
287 assetComponent.setComponentNumber(++maxNo);
288 }
289 }
290 }
291
292 /**
293 * Validates Asset document.
294 *
295 * @param document MaintenanceDocument instance
296 * @return boolean false or true
297 */
298 protected boolean processAssetValidation(MaintenanceDocument document) {
299 boolean valid = true;
300
301 // validate Inventory Status Code.
302 if (!StringUtils.equalsIgnoreCase(oldAsset.getInventoryStatusCode(), newAsset.getInventoryStatusCode())) {
303 valid &= validateInventoryStatusCode(oldAsset.getInventoryStatusCode(), newAsset.getInventoryStatusCode());
304 }
305
306 // validate Organization Owner Account Number
307 if (!StringUtils.equalsIgnoreCase(oldAsset.getOrganizationOwnerAccountNumber(), newAsset.getOrganizationOwnerAccountNumber())) {
308 valid &= validateAccount();
309 }
310
311 // validate Vendor Name.
312 if (!StringUtils.equalsIgnoreCase(oldAsset.getVendorName(), newAsset.getVendorName())) {
313 valid &= validateVendorName();
314 }
315
316 // validate Tag Number.
317 if (!StringUtils.equalsIgnoreCase(oldAsset.getCampusTagNumber(), newAsset.getCampusTagNumber())) {
318 valid &= validateTagNumber();
319 }
320
321 // validate location.
322 valid &= validateLocation();
323
324 // validate In-service Date
325 if (assetService.isInServiceDateChanged(oldAsset, newAsset)) {
326 valid &= validateInServiceDate();
327 }
328 return valid;
329 }
330
331
332 /**
333 * Check if the new In-service Date is a valid University Date
334 *
335 * @return
336 */
337 protected boolean validateInServiceDate() {
338 boolean valid = true;
339 // if asset already starts depreciation, the user can't blank in-service date.
340 if (ObjectUtils.isNull(newAsset.getCapitalAssetInServiceDate()) && assetService.isAssetDepreciationStarted(oldAsset)) {
341 putFieldError(CamsPropertyConstants.Asset.ASSET_DATE_OF_SERVICE, CamsKeyConstants.ERROR_BLANK_IN_SERVICE_DATE_DISALLOWED);
342 valid = false;
343 }
344
345 else if (ObjectUtils.isNotNull(newAsset.getCapitalAssetInServiceDate()) && universityDateService.getFiscalYear(newAsset.getCapitalAssetInServiceDate()) == null) {
346 putFieldError(CamsPropertyConstants.Asset.ASSET_DATE_OF_SERVICE, CamsKeyConstants.ERROR_INVALID_IN_SERVICE_DATE);
347 valid = false;
348 }
349 return valid;
350 }
351
352
353 /**
354 * Check if off campus fields has changed.
355 *
356 * @return
357 */
358 protected boolean isOffCampusLocationChanged() {
359 boolean changed = false;
360 AssetLocation oldLocation = oldAsset.getOffCampusLocation();
361 AssetLocation newLocation = newAsset.getOffCampusLocation();
362
363 if (!StringUtils.equalsIgnoreCase(newLocation.getAssetLocationContactName(), oldLocation.getAssetLocationContactName()) || !StringUtils.equalsIgnoreCase(newLocation.getAssetLocationStreetAddress(), oldLocation.getAssetLocationStreetAddress()) || !StringUtils.equalsIgnoreCase(newLocation.getAssetLocationCityName(), oldLocation.getAssetLocationCityName()) || !StringUtils.equalsIgnoreCase(newLocation.getAssetLocationStateCode(), oldLocation.getAssetLocationStateCode()) || !StringUtils.equalsIgnoreCase(newLocation.getAssetLocationZipCode(), oldLocation.getAssetLocationZipCode()) || !StringUtils.equalsIgnoreCase(newLocation.getAssetLocationCountryCode(), oldLocation.getAssetLocationCountryCode())) {
364 changed = true;
365 }
366 return changed;
367 }
368
369 /**
370 * Validate Inventory Status Code Change
371 */
372 protected boolean validateInventoryStatusCode(String oldInventoryStatusCode, String newInventoryStatusCode) {
373 boolean valid = true;
374 if (assetService.isCapitalAsset(oldAsset) && assetService.isAssetRetired(newAsset)) {
375 // disallow retire capital asset.
376 putFieldError(CamsPropertyConstants.Asset.ASSET_INVENTORY_STATUS, CamsKeyConstants.ERROR_ASSET_RETIRED_CAPITAL);
377 valid = false;
378 }
379 else {
380 // validate inventory status change per system parameter.
381 GlobalVariables.getMessageMap().addToErrorPath(MAINTAINABLE_ERROR_PATH);
382 valid &= parameterService.getParameterEvaluator(Asset.class, CamsConstants.Parameters.VALID_INVENTROY_STATUS_CODE_CHANGE, CamsConstants.Parameters.INVALID_INVENTROY_STATUS_CODE_CHANGE, oldAsset.getInventoryStatusCode(), newAsset.getInventoryStatusCode()).evaluateAndAddError(newAsset.getClass(), CamsPropertyConstants.Asset.ASSET_INVENTORY_STATUS);
383 GlobalVariables.getMessageMap().removeFromErrorPath(MAINTAINABLE_ERROR_PATH);
384 }
385 return valid;
386 }
387
388 protected void initializeAttributes(MaintenanceDocument document) {
389 if (newAsset == null) {
390 newAsset = (Asset) document.getNewMaintainableObject().getBusinessObject();
391 }
392 if (oldAsset == null) {
393 oldAsset = (Asset) document.getOldMaintainableObject().getBusinessObject();
394 }
395 // for fabrication
396 if (oldAsset == null) {
397 oldAsset = newAsset;
398 }
399 }
400
401 /**
402 * If the tag number has not been assigned, the departmental user will be able to update the tag number. The Tag Number shall be
403 * verified that the tag number does not exist on another asset.
404 *
405 * @param asset
406 * @return
407 */
408 protected boolean validateTagNumber() {
409 boolean valid = true;
410 boolean anyFound = false;
411
412 if (!assetService.isTagNumberCheckExclude(newAsset)) {
413
414 Map<String, Object> fieldValues = new HashMap<String, Object>();
415 fieldValues.put(CamsPropertyConstants.Asset.CAMPUS_TAG_NUMBER, newAsset.getCampusTagNumber().toUpperCase());
416
417 Collection<Asset> results = getBoService().findMatching(Asset.class, fieldValues);
418
419 for (Asset asset : results) {
420 if (!asset.getCapitalAssetNumber().equals(newAsset.getCapitalAssetNumber())) {
421 // KFSMI-6149 - do not invalidate if the asset from the database is retired
422 if (StringUtils.isBlank(asset.getRetirementReasonCode())) {
423 putFieldError(CamsPropertyConstants.Asset.CAMPUS_TAG_NUMBER, CamsKeyConstants.AssetLocationGlobal.ERROR_DUPLICATE_TAG_NUMBER_FOUND, new String[] { newAsset.getCampusTagNumber(), asset.getCapitalAssetNumber().toString(), newAsset.getCapitalAssetNumber().toString() });
424 valid &= false;
425 LOG.info("The asset tag number [" + newAsset.getCampusTagNumber().toUpperCase() + "] is a duplicate of asset number [" + asset.getCapitalAssetNumber().toString() + "]'s tag number");
426 } else {
427 LOG.info("Although the asset tag number [" + newAsset.getCampusTagNumber().toUpperCase() + "] is a duplicate of asset number [" + asset.getCapitalAssetNumber().toString() + "]'s tag number, the old asset has already been retired");
428 }
429 }
430 }
431 }
432
433 return valid;
434 }
435
436 /**
437 * The Vendor Name is required for capital equipment and not required for non-capital assets.
438 *
439 * @param asset
440 * @return
441 */
442 protected boolean validateVendorName() {
443 boolean valid = true;
444
445 if (assetService.isCapitalAsset(newAsset) && StringUtils.isBlank(newAsset.getVendorName())) {
446 putFieldError(CamsPropertyConstants.Asset.VENDOR_NAME, CamsKeyConstants.ERROR_CAPITAL_ASSET_VENDOR_NAME_REQUIRED);
447 valid &= false;
448
449 }
450 return valid;
451 }
452
453
454 /**
455 * Validate Asset Location fields
456 *
457 * @param asset
458 * @return
459 */
460 protected boolean validateLocation() {
461 GlobalVariables.getMessageMap().addToErrorPath("document.newMaintainableObject");
462 boolean isCapitalAsset = assetService.isCapitalAsset(newAsset);
463 boolean valid = assetLocationService.validateLocation(LOCATION_FIELD_MAP, newAsset, isCapitalAsset, newAsset.getCapitalAssetType());
464 GlobalVariables.getMessageMap().removeFromErrorPath("document.newMaintainableObject");
465
466 if (valid && (this.isFabrication || isOffCampusLocationChanged())) {
467 assetLocationService.updateOffCampusLocation(newAsset);
468 }
469 return valid;
470 }
471
472 /**
473 * Validate warranty information if user enters value
474 *
475 * @param asset Asset
476 * @return validation result
477 */
478 protected boolean validateWarrantyInformation(Asset asset) {
479 AssetWarranty warranty = asset.getAssetWarranty();
480 if (warranty != null) {
481 if (!StringUtils.isEmpty(warranty.getWarrantyContactName()) || !StringUtils.isEmpty(warranty.getWarrantyPhoneNumber()) || !StringUtils.isEmpty(warranty.getWarrantyText()) || warranty.getWarrantyBeginningDate() != null || warranty.getWarrantyEndingDate() != null) {
482 if (StringUtils.isEmpty(warranty.getWarrantyNumber())) {
483 // warranty number is mandatory when any other related info is known
484 putFieldError(ASSET_WARRANTY_WARRANTY_NUMBER, ERROR_INVALID_ASSET_WARRANTY_NO);
485 return false;
486 }
487 }
488 }
489 return true;
490 }
491
492 /**
493 * validates depreciation data
494 *
495 * @param asset
496 * @return boolean
497 */
498 protected boolean validateDepreciationData(Asset asset) {
499 if (asset.getSalvageAmount() == null) {
500 asset.setSalvageAmount(KualiDecimal.ZERO);
501 }
502
503 if (asset.getBaseAmount() == null) {
504 asset.setBaseAmount(KualiDecimal.ZERO);
505 }
506
507 // If the salvage amount is greater than the base amount, then data is invalid
508 if (asset.getSalvageAmount().compareTo(asset.getBaseAmount()) > 0) {
509 putFieldError(CamsPropertyConstants.Asset.SALVAGE_AMOUNT, CamsKeyConstants.Asset.ERROR_INVALID_SALVAGE_AMOUNT);
510 return false;
511 }
512 else {
513 return true;
514 }
515 }
516
517 @Override
518 protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
519 boolean valid = super.processCustomRouteDocumentBusinessRules(document);
520 initializeAttributes(document);
521 if (SpringContext.getBean(AssetService.class).isAssetFabrication(document) && newAsset.getCapitalAssetNumber() == null) {
522 newAsset.setCapitalAssetNumber(NextAssetNumberFinder.getLongValue());
523 oldAsset.setCapitalAssetNumber(newAsset.getCapitalAssetNumber());
524 newAsset.setLastInventoryDate(new Timestamp(SpringContext.getBean(DateTimeService.class).getCurrentSqlDate().getTime()));
525 oldAsset.setLastInventoryDate(new Timestamp(SpringContext.getBean(DateTimeService.class).getCurrentSqlDate().getTime()));
526 }
527
528 // check for change
529 valid &= checkAcquisitionTypeCodeChange();
530 valid &= checkConditionCodeChange();
531 valid &= checkAssetDepreciationMethodChange();
532 valid &= checkAssetStatusCodeChange();
533 valid &= checkAssetTypeCodeChange();
534 valid &= checkFinancialObjectSubtypeCodeChange();
535 valid &= validateAccount();
536
537 KualiWorkflowDocument workflowDoc = document.getDocumentHeader().getWorkflowDocument();
538 // adding asset locks for asset edit only
539 if (newAsset instanceof Asset && !(newAsset instanceof AssetFabrication) && !GlobalVariables.getMessageMap().hasErrors() && (workflowDoc.stateIsInitiated() || workflowDoc.stateIsSaved())) {
540 valid &= setAssetLock(document);
541 }
542 return valid;
543 }
544
545 /**
546 * Locking asset number
547 *
548 * @param document
549 * @return
550 */
551 protected boolean setAssetLock(MaintenanceDocument document) {
552 Asset asset = (Asset) document.getNewMaintainableObject().getBusinessObject();
553 return this.getCapitalAssetManagementModuleService().storeAssetLocks(retrieveAssetNumberForLocking(asset), document.getDocumentNumber(), CamsConstants.DocumentTypeName.ASSET_EDIT, null);
554 }
555
556 protected CapitalAssetManagementModuleService getCapitalAssetManagementModuleService() {
557 return SpringContext.getBean(CapitalAssetManagementModuleService.class);
558 }
559
560 /**
561 * Convenience method to append the path prefix
562 */
563 public TypedArrayList putError(String propertyName, String errorKey, String... errorParameters) {
564 return GlobalVariables.getMessageMap().putError(CamsConstants.DOCUMENT_PATH + "." + propertyName, errorKey, errorParameters);
565 }
566
567 /**
568 * Check if the Acquisition Type Code is valid or is inactive.
569 *
570 * @param oldAcquisitionTypeCode
571 * @param newAcquisitionTypeCode
572 * @return boolean
573 */
574 protected boolean checkAcquisitionTypeCodeChange() {
575 if (ObjectUtils.isNull(newAsset.getAcquisitionType())) {
576 putFieldError(CamsPropertyConstants.Asset.ACQUISITION_TYPE_CODE, CamsKeyConstants.Asset.ERROR_ACQUISITION_TYPE_CODE_INVALID);
577 return false;
578 }
579 else if (!StringUtils.equalsIgnoreCase(newAsset.getAcquisitionTypeCode(), oldAsset.getAcquisitionTypeCode())) {
580 newAsset.refreshReferenceObject(CamsPropertyConstants.Asset.REF_ACQUISITION_TYPE);
581 if (ObjectUtils.isNotNull(newAsset.getAcquisitionType())) {
582 if (!newAsset.getAcquisitionType().isActive()) {
583 putFieldError(CamsPropertyConstants.Asset.ACQUISITION_TYPE_CODE, CamsKeyConstants.Asset.ERROR_ACQUISITION_TYPE_CODE_INACTIVE);
584 return false;
585 }
586 }
587 }
588 return true;
589 }
590
591 /**
592 * Check if the Asset Condition is valid or is inactive.
593 *
594 * @param oldConditionCode
595 * @param newConditionCode
596 * @return boolean
597 */
598 protected boolean checkConditionCodeChange() {
599 if (ObjectUtils.isNull(newAsset.getCondition())) {
600 putFieldError(CamsPropertyConstants.Asset.CONDITION_CODE, CamsKeyConstants.Asset.ERROR_ASSET_CONDITION_INVALID);
601 return false;
602 }
603 else if (!StringUtils.equalsIgnoreCase(newAsset.getConditionCode(), oldAsset.getConditionCode())) {
604 newAsset.refreshReferenceObject(CamsPropertyConstants.Asset.REF_ASSET_CONDITION);
605 if (ObjectUtils.isNotNull(newAsset.getCondition())) {
606 if (!newAsset.getCondition().isActive()) {
607 putFieldError(CamsPropertyConstants.Asset.CONDITION_CODE, CamsKeyConstants.Asset.ERROR_ASSET_CONDITION_INACTIVE);
608 return false;
609 }
610 }
611 }
612 return true;
613 }
614
615 /**
616 * Check if the Asset Depreciation Method is valid or is inactive.
617 *
618 * @param oldAssetDepreciationMethod
619 * @param newAssetDepreciationMethod
620 * @return boolean
621 */
622 protected boolean checkAssetDepreciationMethodChange() {
623 if (ObjectUtils.isNull(newAsset.getAssetPrimaryDepreciationMethod())) {
624 putFieldError(CamsPropertyConstants.Asset.PRIMARY_DEPRECIATION_METHOD, CamsKeyConstants.Asset.ERROR_DEPRECATION_METHOD_CODE_INVALID);
625 return false;
626 }
627 else if (!StringUtils.equalsIgnoreCase(newAsset.getPrimaryDepreciationMethodCode(), oldAsset.getPrimaryDepreciationMethodCode())) {
628 newAsset.refreshReferenceObject(CamsPropertyConstants.Asset.REF_ASSET_DEPRECATION_METHOD);
629 if (ObjectUtils.isNotNull(newAsset.getAssetPrimaryDepreciationMethod())) {
630 if (!newAsset.getAssetPrimaryDepreciationMethod().isActive()) {
631 putFieldError(CamsPropertyConstants.Asset.PRIMARY_DEPRECIATION_METHOD, CamsKeyConstants.Asset.ERROR_DEPRECATION_METHOD_CODE_INACTIVE);
632 return false;
633 }
634 }
635 }
636 return true;
637 }
638
639 /**
640 * Check if the Asset Status Code is valid or is inactive.
641 *
642 * @param oldAssetStatus
643 * @param newAssetStatus
644 * @return boolean
645 */
646 protected boolean checkAssetStatusCodeChange() {
647 if (ObjectUtils.isNull(newAsset.getInventoryStatus())) {
648 putFieldError(CamsPropertyConstants.Asset.ASSET_INVENTORY_STATUS, CamsKeyConstants.Asset.ERROR_ASSET_STATUS_INVALID);
649 return false;
650 }
651 else if (!StringUtils.equalsIgnoreCase(newAsset.getInventoryStatusCode(), oldAsset.getInventoryStatusCode())) {
652 newAsset.refreshReferenceObject(CamsPropertyConstants.Asset.REF_ASSET_STATUS);
653 if (ObjectUtils.isNotNull(newAsset.getInventoryStatus())) {
654 if (!newAsset.getInventoryStatus().isActive()) {
655 putFieldError(CamsPropertyConstants.Asset.ASSET_INVENTORY_STATUS, CamsKeyConstants.Asset.ERROR_ASSET_STATUS_INACTIVE);
656 return false;
657 }
658 }
659 }
660 return true;
661 }
662
663 /**
664 * Check if the Asset Type Code is valid or is inactive.
665 *
666 * @param oldAssetType
667 * @param newAssetType
668 * @return boolean
669 */
670 protected boolean checkAssetTypeCodeChange() {
671 if (ObjectUtils.isNull(newAsset.getCapitalAssetType())) {
672 putFieldError(CamsPropertyConstants.Asset.CAPITAL_ASSET_TYPE_CODE, CamsKeyConstants.Asset.ERROR_TYPE_CODE_INVALID);
673 return false;
674 }
675 else if (!StringUtils.equalsIgnoreCase(newAsset.getCapitalAssetTypeCode(), oldAsset.getCapitalAssetTypeCode())) {
676 newAsset.refreshReferenceObject(CamsPropertyConstants.Asset.REF_ASSET_TYPE);
677 if (ObjectUtils.isNotNull(newAsset.getCapitalAssetType())) {
678 if (!newAsset.getCapitalAssetType().isActive()) {
679 putFieldError(CamsPropertyConstants.AssetType.CAPITAL_ASSET_TYPE_CODE, CamsKeyConstants.Asset.ERROR_TYPE_CODE_INACTIVE);
680 return false;
681 }
682 }
683 }
684 return true;
685 }
686
687 /**
688 * Check if the Financial Object Sub-Type Code is valid or is inactive.
689 *
690 * @param oldObjectSubType
691 * @param newObjectSubType
692 * @return boolean
693 */
694 protected boolean checkFinancialObjectSubtypeCodeChange() {
695 if (ObjectUtils.isNotNull(newAsset.getFinancialObjectSubType()) || StringUtils.isNotBlank(newAsset.getFinancialObjectSubTypeCode())) {
696 newAsset.refreshReferenceObject(CamsPropertyConstants.Asset.REF_OBJECT_SUB_TYPE);
697 if (ObjectUtils.isNull(newAsset.getFinancialObjectSubType())) {
698 putFieldError(CamsPropertyConstants.Asset.FINANCIAL_OBJECT_SUB_TYP_CODE, CamsKeyConstants.Asset.ERROR_FINANCIAL_OBJECT_SUBTYPE_CODE_INVALID);
699 return false;
700 }
701 else if (!newAsset.getFinancialObjectSubType().isActive()) {
702 putFieldError(CamsPropertyConstants.Asset.FINANCIAL_OBJECT_SUB_TYP_CODE, CamsKeyConstants.Asset.ERROR_FINANCIAL_OBJECT_SUBTYPE_CODE_INACTIVE);
703 return false;
704 }
705 }
706 return true;
707 }
708 }