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.service.impl;
017    
018    import java.util.ArrayList;
019    import java.util.Arrays;
020    import java.util.Collection;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Map;
025    
026    import org.apache.commons.lang.StringUtils;
027    import org.kuali.kfs.module.cam.CamsConstants;
028    import org.kuali.kfs.module.cam.CamsPropertyConstants;
029    import org.kuali.kfs.module.cam.businessobject.Asset;
030    import org.kuali.kfs.module.cam.businessobject.AssetGlobal;
031    import org.kuali.kfs.module.cam.businessobject.AssetGlobalDetail;
032    import org.kuali.kfs.module.cam.businessobject.AssetLocation;
033    import org.kuali.kfs.module.cam.businessobject.AssetPayment;
034    import org.kuali.kfs.module.cam.businessobject.AssetType;
035    import org.kuali.kfs.module.cam.document.service.AssetService;
036    import org.kuali.kfs.module.cam.document.service.PaymentSummaryService;
037    import org.kuali.kfs.sys.KFSPropertyConstants;
038    import org.kuali.kfs.sys.KFSConstants.DocumentStatusCodes;
039    import org.kuali.kfs.sys.businessobject.UniversityDate;
040    import org.kuali.kfs.sys.context.SpringContext;
041    import org.kuali.kfs.sys.service.UniversityDateService;
042    import org.kuali.rice.kew.exception.WorkflowException;
043    import org.kuali.rice.kns.document.Document;
044    import org.kuali.rice.kns.document.MaintenanceDocument;
045    import org.kuali.rice.kns.exception.ValidationException;
046    import org.kuali.rice.kns.service.BusinessObjectService;
047    import org.kuali.rice.kns.service.ParameterService;
048    import org.kuali.rice.kns.util.ObjectUtils;
049    import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
050    
051    public class AssetServiceImpl implements AssetService {
052        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AssetServiceImpl.class);
053    
054        private ParameterService parameterService;
055        private PaymentSummaryService paymentSummaryService;
056        private BusinessObjectService businessObjectService;
057    
058        public ParameterService getParameterService() {
059            return parameterService;
060        }
061    
062        public void setParameterService(ParameterService parameterService) {
063            this.parameterService = parameterService;
064        }
065    
066        public boolean isAssetMovableCheckByAsset(Asset asset) {
067            asset.refreshReferenceObject(CamsPropertyConstants.Asset.CAPITAL_ASSET_TYPE);
068            return asset.getCapitalAssetType().isMovingIndicator();
069        }
070    
071    
072        /**
073         * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetDepreciationStarted(org.kuali.kfs.module.cam.businessobject.Asset)
074         */
075        public boolean isAssetDepreciationStarted(Asset asset) {
076            // check non-persistent field accumulatedDepreciation first since it's the sum of
077            // assetPayment.accumulatedPrimaryDepreciationAmount. If it's not set yet, we'll check assetPayment one by one.
078            if (ObjectUtils.isNotNull(asset.getAccumulatedDepreciation()) && asset.getAccumulatedDepreciation().isPositive()) {
079                return true;
080            }
081            else {
082                for (AssetPayment assetPayment : asset.getAssetPayments()) {
083                    if (ObjectUtils.isNotNull(assetPayment.getAccumulatedPrimaryDepreciationAmount()) && assetPayment.getAccumulatedPrimaryDepreciationAmount().isPositive()) {
084                        return true;
085                    }
086                }
087            }
088            return false;
089        }
090    
091        public boolean isCapitalAsset(Asset asset) {
092            return parameterService.getParameterValues(Asset.class, CamsConstants.Parameters.CAPITAL_ASSET_STATUS_CODES).contains(asset.getInventoryStatusCode());
093        }
094    
095        public boolean isAssetRetired(Asset asset) {
096            return parameterService.getParameterValues(Asset.class, CamsConstants.Parameters.RETIRED_STATUS_CODES).contains(asset.getInventoryStatusCode());
097        }
098    
099        public boolean isInServiceDateChanged(Asset oldAsset, Asset newAsset) {
100            return !(ObjectUtils.isNull(oldAsset.getCapitalAssetInServiceDate()) ? ObjectUtils.isNull(newAsset.getCapitalAssetInServiceDate()) : oldAsset.getCapitalAssetInServiceDate().equals(newAsset.getCapitalAssetInServiceDate()));
101        }
102    
103        /**
104         * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetFabrication(org.kuali.rice.kns.document.MaintenanceDocument)
105         */
106        public boolean isAssetFabrication(MaintenanceDocument maintenanceDocument) {
107            return maintenanceDocument.getNewMaintainableObject().getBusinessObject() instanceof Asset && maintenanceDocument.isNew();
108        }
109    
110        /**
111         * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetLoaned(org.kuali.kfs.module.cam.businessobject.Asset)
112         */
113        public boolean isAssetLoaned(Asset asset) {
114            return ObjectUtils.isNotNull(asset.getExpectedReturnDate()) && ObjectUtils.isNull(asset.getLoanReturnDate());
115        }
116    
117        /**
118         * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetTaggedInPriorFiscalYear(org.kuali.kfs.module.cam.businessobject.Asset)
119         */
120        public boolean isAssetTaggedInPriorFiscalYear(Asset asset) {
121            UniversityDateService universityDateService = SpringContext.getBean(UniversityDateService.class);
122    
123            return StringUtils.isNotBlank(asset.getCampusTagNumber()) && ObjectUtils.isNotNull(asset.getFinancialDocumentPostingYear()) && !universityDateService.getCurrentFiscalYear().equals(asset.getFinancialDocumentPostingYear());
124        }
125    
126        /**
127         * @see org.kuali.kfs.module.cam.document.service.AssetService#isTagNumberCheckExclude(org.kuali.kfs.module.cam.businessobject.Asset)
128         */
129        public boolean isTagNumberCheckExclude(Asset asset) {
130            String status = asset.getInventoryStatusCode();
131    
132            return StringUtils.equalsIgnoreCase(status, CamsConstants.InventoryStatusCode.CAPITAL_ASSET_RETIRED) || StringUtils.equalsIgnoreCase(status, CamsConstants.InventoryStatusCode.NON_CAPITAL_ASSET_RETIRED) || StringUtils.equalsIgnoreCase(asset.getCampusTagNumber(), CamsConstants.Asset.NON_TAGGABLE_ASSET);
133        }
134    
135        /**
136         * @see org.kuali.kfs.module.cam.document.service.AssetService#isOffCampusLocationEntered(org.kuali.kfs.module.cam.businessobject.Asset)
137         */
138        public boolean isOffCampusLocationEntered(Asset asset) {
139            AssetLocation offCampus = asset.getOffCampusLocation();
140            return StringUtils.isNotBlank(offCampus.getAssetLocationContactName()) || StringUtils.isNotBlank(offCampus.getAssetLocationStreetAddress()) || StringUtils.isNotBlank(offCampus.getAssetLocationCityName()) || StringUtils.isNotBlank(offCampus.getAssetLocationStateCode()) || StringUtils.isNotBlank(offCampus.getAssetLocationZipCode()) || StringUtils.isNotBlank(offCampus.getAssetLocationCountryCode());
141        }
142    
143        /**
144         * @see org.kuali.kfs.module.cam.document.service.AssetService#isFinancialObjectSubTypeCodeChanged(org.kuali.kfs.module.cam.businessobject.Asset,
145         *      org.kuali.kfs.module.cam.businessobject.Asset)
146         */
147        public boolean isFinancialObjectSubTypeCodeChanged(Asset oldAsset, Asset newAsset) {
148            return !StringUtils.equalsIgnoreCase(oldAsset.getFinancialObjectSubTypeCode(), newAsset.getFinancialObjectSubTypeCode());
149        }
150    
151        /**
152         * @see org.kuali.kfs.module.cam.document.service.AssetService#isAssetTypeCodeChanged(org.kuali.kfs.module.cam.businessobject.Asset,
153         *      org.kuali.kfs.module.cam.businessobject.Asset)
154         */
155        public boolean isAssetTypeCodeChanged(Asset oldAsset, Asset newAsset) {
156            return !StringUtils.equalsIgnoreCase(oldAsset.getCapitalAssetTypeCode(), newAsset.getCapitalAssetTypeCode());
157        }
158    
159        public boolean isAssetDepreciableLifeLimitZero(Asset asset) {
160            asset.refreshReferenceObject(CamsPropertyConstants.Asset.CAPITAL_ASSET_TYPE);
161            AssetType capitalAssetType = asset.getCapitalAssetType();
162            if (ObjectUtils.isNotNull(capitalAssetType)) {
163                return Integer.valueOf(0).equals(capitalAssetType.getDepreciableLifeLimit());
164            }
165            return false;
166        }
167    
168        /**
169         * @see org.kuali.kfs.module.cam.document.service.AssetService#isCapitalAssetNumberDuplicate(java.lang.Long, java.lang.Long)
170         */
171        public boolean isCapitalAssetNumberDuplicate(Long capitalAssetNumber1, Long capitalAssetNumber2) {
172            if (capitalAssetNumber1 != null && capitalAssetNumber2 != null && capitalAssetNumber1.compareTo(capitalAssetNumber2) == 0) {
173                return true;
174            }
175            return false;
176        }
177    
178    
179        /**
180         * This method calls the service codes to calculate the summary fields for each asset
181         * 
182         * @param asset
183         */
184        public void setAssetSummaryFields(Asset asset) {
185            if (ObjectUtils.isNotNull(asset)) {
186                asset.setFederalContribution(paymentSummaryService.calculateFederalContribution(asset));
187                asset.setAccumulatedDepreciation(paymentSummaryService.calculatePrimaryAccumulatedDepreciation(asset));
188                asset.setBookValue(paymentSummaryService.calculatePrimaryBookValue(asset));
189            }
190        }
191    
192        public PaymentSummaryService getPaymentSummaryService() {
193            return paymentSummaryService;
194        }
195    
196        public void setPaymentSummaryService(PaymentSummaryService paymentSummaryService) {
197            this.paymentSummaryService = paymentSummaryService;
198        }
199    
200        /**
201         * @see org.kuali.kfs.module.cam.document.service.AssetService#isMovableFinancialObjectSubtypeCode(java.lang.String)
202         */
203        public boolean isAssetMovableCheckByPayment(String financialObjectSubTypeCode) {
204            if (parameterService.getParameterValues(Asset.class, CamsConstants.Parameters.MOVABLE_EQUIPMENT_OBJECT_SUB_TYPES).contains(financialObjectSubTypeCode)) {
205                return true;
206            }
207            else if (parameterService.getParameterValues(Asset.class, CamsConstants.Parameters.NON_MOVABLE_EQUIPMENT_OBJECT_SUB_TYPES).contains(financialObjectSubTypeCode)) {
208                return false;
209            }
210            else {
211                throw new ValidationException("Cound not determine movable or non-movable for this object sub-type code " + financialObjectSubTypeCode);
212            }
213        }
214    
215        public List<Asset> findActiveAssetsMatchingTagNumber(String campusTagNumber) {
216            List<Asset> activeMatches = new ArrayList<Asset>();
217            // find all assets matching this tag number
218            Map<String, String> params = new HashMap<String, String>();
219            params.put(CamsPropertyConstants.Asset.CAMPUS_TAG_NUMBER, campusTagNumber);
220            Collection<Asset> tagMatches = SpringContext.getBean(BusinessObjectService.class).findMatching(Asset.class, params);
221            if (tagMatches != null && !tagMatches.isEmpty()) {
222                for (Asset asset : tagMatches) {
223                    // if found matching, check if status is not retired
224                    if (!isAssetRetired(asset)) {
225                        activeMatches.add(asset);
226                    }
227                }
228            }
229            return activeMatches;
230        }
231    
232    
233        /**
234         * @see org.kuali.kfs.module.cam.document.service.AssetService#findAssetsMatchingTagNumber(java.lang.String)
235         */
236        public Collection<Asset> findAssetsMatchingTagNumber(String campusTagNumber) {
237            // find all assets matching this tag number
238            Map<String, String> params = new HashMap<String, String>();
239            params.put(CamsPropertyConstants.Asset.CAMPUS_TAG_NUMBER, campusTagNumber);
240            Collection<Asset> tagMatches = SpringContext.getBean(BusinessObjectService.class).findMatching(Asset.class, params);
241    
242            return tagMatches;
243        }
244    
245        /**
246         * @see org.kuali.kfs.module.cam.document.service.AssetService#isObjectSubTypeCompatible(java.util.List)
247         */
248        public boolean isObjectSubTypeCompatible(List<String> financialObjectSubTypeCode) {
249            if (financialObjectSubTypeCode == null || financialObjectSubTypeCode.size() <= 1) {
250                return true;
251            }
252    
253            List<String> subTypes = parameterService.getParameterValues(Asset.class, CamsConstants.Parameters.OBJECT_SUB_TYPE_GROUPS);
254            String firstObjectSubType = (String) financialObjectSubTypeCode.get(0);
255            List<String> validObjectSubTypes = new ArrayList<String>();
256    
257            // Get the set for compatible object sub type code by the first financial object sub type code
258            for (String subType : subTypes) {
259                if (subType.contains(firstObjectSubType)) {
260                    validObjectSubTypes = Arrays.asList(StringUtils.split(subType, ","));
261                    break;
262                }
263            }
264    
265            if (validObjectSubTypes.isEmpty()) {
266                validObjectSubTypes.add(firstObjectSubType);
267            }
268    
269            // Check in the whole list if all object sub type code are compatible.
270            for (String subTypeCode : financialObjectSubTypeCode) {
271                if (!validObjectSubTypes.contains(subTypeCode)) {
272                    return false;
273                }
274            }
275    
276            return true;
277        }
278    
279        /**
280         * @see org.kuali.kfs.module.cam.document.service.AssetService#setSeparateHistory(org.kuali.kfs.module.cam.businessobject.Asset)
281         */
282        public void setSeparateHistory(Asset asset) {
283            // Find the asset this was separated from. It should only be one, error if more
284            Map<String, String> paramsAssetGlobalDetail = new HashMap<String, String>();
285            paramsAssetGlobalDetail.put(CamsPropertyConstants.AssetGlobalDetail.CAPITAL_ASSET_NUMBER, asset.getCapitalAssetNumber().toString());
286            Collection<AssetGlobalDetail> assetGlobalDetails = SpringContext.getBean(BusinessObjectService.class).findMatching(AssetGlobalDetail.class, paramsAssetGlobalDetail);
287    
288            if (assetGlobalDetails.size() > 1) {
289                throw new IllegalStateException("Asset #" + asset.getCapitalAssetNumber().toString() + " was created from more then one asset document.");
290            }
291            else if (assetGlobalDetails.size() == 1) {
292                // Find the document associated to that
293                Map<String, String> paramsAssetGlobal = new HashMap<String, String>();
294                paramsAssetGlobal.put(CamsPropertyConstants.AssetGlobal.DOCUMENT_NUMBER, assetGlobalDetails.iterator().next().getDocumentNumber());
295                AssetGlobal assetGlobal = (AssetGlobal) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(AssetGlobal.class, paramsAssetGlobal);
296    
297                // Only set it if it is in status approved
298                if (DocumentStatusCodes.APPROVED.equals((assetGlobal.getDocumentHeader().getFinancialDocumentStatusCode()))) {
299                    asset.setSeparateHistory(assetGlobal);
300                }
301            }
302    
303            // Else no history, just return
304        }
305    
306        /**
307         * @see org.kuali.kfs.module.cam.document.service.AssetService#getDocumentNumberThatSeparatedThisAsset(java.lang.Long)
308         */
309        public List<String> getDocumentNumbersThatSeparatedThisAsset(Long capitalAssetNumber) {
310            Map<String, String> paramsAssetGlobal = new HashMap<String, String>();
311            paramsAssetGlobal.put(CamsPropertyConstants.AssetGlobal.SEPARATE_SOURCE_CAPITAL_ASSET_NUMBER, capitalAssetNumber.toString());
312            Collection<AssetGlobal> assetGlobals = SpringContext.getBean(BusinessObjectService.class).findMatching(AssetGlobal.class, paramsAssetGlobal);
313    
314            List<String> separateDocumentNumbers = new ArrayList<String>();
315            for (Iterator<AssetGlobal> assetGlobalIter = assetGlobals.iterator(); assetGlobalIter.hasNext();) {
316                AssetGlobal assetGlobal = assetGlobalIter.next();
317    
318                if (DocumentStatusCodes.APPROVED.equals(assetGlobal.getDocumentHeader().getFinancialDocumentStatusCode())) {
319                    separateDocumentNumbers.add(assetGlobal.getDocumentNumber());
320                }
321            }
322    
323            return separateDocumentNumbers;
324        }
325    
326        /**
327         * sets the posting year and posting month based on the asset creation date
328         * 
329         * @param asset
330         * @return none
331         */
332        public void setFiscalPeriod(Asset asset) {
333            if (asset.getCreateDate() == null)
334                return;
335    
336            Map<String, Object> primaryKeys = new HashMap<String, Object>();
337            primaryKeys.put(KFSPropertyConstants.UNIVERSITY_DATE, asset.getCreateDate());
338            UniversityDate universityDate = (UniversityDate) businessObjectService.findByPrimaryKey(UniversityDate.class, primaryKeys);
339            if (universityDate != null) {
340                asset.setFinancialDocumentPostingYear(universityDate.getUniversityFiscalYear());
341                asset.setFinancialDocumentPostingPeriodCode(universityDate.getUniversityFiscalAccountingPeriod());
342            }
343        }
344    
345        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
346            this.businessObjectService = businessObjectService;
347        }
348    
349    
350        /**
351         * @see org.kuali.kfs.module.cam.document.service.AssetService#getCurrentRouteLevels(org.kuali.rice.kns.workflow.service.KualiWorkflowDocument)
352         */
353        public List<String> getCurrentRouteLevels(KualiWorkflowDocument workflowDocument) {
354            try {
355                return Arrays.asList(workflowDocument.getNodeNames());
356            }
357            catch (WorkflowException e) {
358                throw new RuntimeException(e);
359            }
360        }
361    
362        /**
363         * @see org.kuali.kfs.module.cam.document.service.AssetService#isMaintenanceDocumentEnroute(org.kuali.rice.kns.document.MaintenanceDocument)
364         */
365        public boolean isDocumentEnrouting(Document document) {
366            return document.getDocumentHeader().getWorkflowDocument().stateIsEnroute();
367        }
368    
369    }