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.HashMap;
019    import java.util.List;
020    import java.util.Map;
021    
022    import org.apache.commons.lang.StringUtils;
023    import org.kuali.kfs.module.cam.CamsConstants;
024    import org.kuali.kfs.module.cam.CamsKeyConstants;
025    import org.kuali.kfs.module.cam.CamsPropertyConstants.AssetTransferDocument;
026    import org.kuali.kfs.module.cam.businessobject.Asset;
027    import org.kuali.kfs.module.cam.businessobject.AssetLocation;
028    import org.kuali.kfs.module.cam.businessobject.AssetType;
029    import org.kuali.kfs.module.cam.document.service.AssetLocationService;
030    import org.kuali.kfs.sys.KFSConstants;
031    import org.kuali.kfs.sys.KFSPropertyConstants;
032    import org.kuali.kfs.sys.context.SpringContext;
033    import org.kuali.rice.kns.bo.BusinessObject;
034    import org.kuali.rice.kns.bo.State;
035    import org.kuali.rice.kns.datadictionary.DataDictionaryEntryBase;
036    import org.kuali.rice.kns.document.DocumentBase;
037    import org.kuali.rice.kns.service.BusinessObjectService;
038    import org.kuali.rice.kns.service.DataDictionaryService;
039    import org.kuali.rice.kns.service.StateService;
040    import org.kuali.rice.kns.util.GlobalVariables;
041    import org.kuali.rice.kns.util.ObjectUtils;
042    
043    public class AssetLocationServiceImpl implements AssetLocationService {
044        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AssetLocationService.class);
045    
046        private BusinessObjectService businessObjectService;
047        private DataDictionaryService DataDictionaryService;
048    
049        /**
050         * @see org.kuali.kfs.module.cam.document.service.AssetLocationService#setOffCampusLocation(org.kuali.kfs.module.cam.businessobject.Asset)
051         */
052        public void setOffCampusLocation(Asset asset) {
053            List<AssetLocation> assetLocations = asset.getAssetLocations();
054            AssetLocation offCampusLocation = null;
055    
056            for (AssetLocation location : assetLocations) {
057                if (CamsConstants.AssetLocationTypeCode.OFF_CAMPUS.equalsIgnoreCase(location.getAssetLocationTypeCode())) {
058                    // We need a new instance for asset location. Otherwise, if we copy it from the assetLocations collection, it could
059                    // have newBO and oldBO pointing to the same AssetLocation instance which is bad.
060                    offCampusLocation = new AssetLocation(location);
061                    break;
062                }
063            }
064    
065            if (ObjectUtils.isNull(offCampusLocation)) {
066                offCampusLocation = new AssetLocation(asset.getCapitalAssetNumber());
067                offCampusLocation.setAssetLocationTypeCode(CamsConstants.AssetLocationTypeCode.OFF_CAMPUS);
068            }
069            asset.setOffCampusLocation(offCampusLocation);
070        }
071    
072        /**
073         * update existing offCampusLocation
074         * 
075         * @see org.kuali.kfs.module.cam.document.service.AssetLocationService#updateOffCampusLocation(org.kuali.kfs.module.cam.businessobject.Asset)
076         */
077        public void updateOffCampusLocation(Asset asset) {
078            AssetLocation offLocation = asset.getOffCampusLocation();
079            boolean isOffCampusEmpty = isOffCampusLocationEmpty(offLocation);
080            AssetLocation removableOffCampusLocation = null;
081    
082            for (AssetLocation location : asset.getAssetLocations()) {
083                if (CamsConstants.AssetLocationTypeCode.OFF_CAMPUS.equalsIgnoreCase(location.getAssetLocationTypeCode())) {
084                    if (isOffCampusEmpty) {
085                        removableOffCampusLocation = location;
086                    }
087                    else {
088                        location.setAssetLocationCityName(offLocation.getAssetLocationCityName());
089                        location.setAssetLocationContactIdentifier(offLocation.getAssetLocationContactIdentifier());
090                        location.setAssetLocationContactName(offLocation.getAssetLocationContactName());
091                        location.setAssetLocationCountryCode(offLocation.getAssetLocationCountryCode());
092                        location.setAssetLocationInstitutionName(offLocation.getAssetLocationInstitutionName());
093                        location.setAssetLocationPhoneNumber(offLocation.getAssetLocationPhoneNumber());
094                        location.setAssetLocationStateCode(offLocation.getAssetLocationStateCode());
095                        location.setAssetLocationStreetAddress(offLocation.getAssetLocationStreetAddress());
096                        location.setAssetLocationZipCode(offLocation.getAssetLocationZipCode());
097                        return;
098                    }
099                }
100            }
101    
102            if (removableOffCampusLocation != null) {
103                asset.getAssetLocations().remove(removableOffCampusLocation);
104            }
105            else if (!isOffCampusEmpty) { // add the check for off-campus empty  
106                // new offCampusLocation, add it into assetLocation List
107                asset.getAssetLocations().add(offLocation); 
108            }
109    
110        }
111    
112        /**
113         * @see org.kuali.kfs.module.cam.document.service.AssetLocationService#isOffCampusLocationExists(org.kuali.kfs.module.cam.businessobject.AssetLocation)
114         */
115        public boolean isOffCampusLocationExists(AssetLocation offCampusLocation) {
116            if (ObjectUtils.isNotNull(offCampusLocation)) {
117                if (CamsConstants.AssetLocationTypeCode.OFF_CAMPUS.equalsIgnoreCase(offCampusLocation.getAssetLocationTypeCode())) {
118                    return true;
119                }
120            }
121            return false;
122        }
123    
124        /**
125         * @see org.kuali.kfs.module.cam.document.service.AssetLocationService#isOffCampusLocationEmpty(org.kuali.kfs.module.cam.businessobject.AssetLocation)
126         */
127        public boolean isOffCampusLocationEmpty(AssetLocation offCampusLocation) {
128            if (ObjectUtils.isNotNull(offCampusLocation)) {
129                if (StringUtils.isNotBlank(offCampusLocation.getAssetLocationCityName()) || StringUtils.isNotBlank(offCampusLocation.getAssetLocationContactIdentifier()) || StringUtils.isNotBlank(offCampusLocation.getAssetLocationContactName()) || StringUtils.isNotBlank(offCampusLocation.getAssetLocationCountryCode()) || StringUtils.isNotBlank(offCampusLocation.getAssetLocationInstitutionName()) || StringUtils.isNotBlank(offCampusLocation.getAssetLocationPhoneNumber()) || StringUtils.isNotBlank(offCampusLocation.getAssetLocationStateCode()) || StringUtils.isNotBlank(offCampusLocation.getAssetLocationStreetAddress()) || StringUtils.isNotBlank(offCampusLocation.getAssetLocationZipCode())) {
130                    return false;
131                }
132            }
133            return true;
134        }
135    
136        /**
137         * @see org.kuali.kfs.module.cam.document.service.AssetLocationService#validateLocation(java.lang.Object,
138         *      org.kuali.kfs.module.cam.businessobject.Asset, java.util.Map)
139         */
140        public boolean validateLocation(Map<LocationField, String> fieldMap, BusinessObject businessObject, boolean isCapital, AssetType assetType) {
141            String campusCode = readPropertyValue(businessObject, fieldMap, LocationField.CAMPUS_CODE);
142            String buildingCode = readPropertyValue(businessObject, fieldMap, LocationField.BUILDING_CODE);
143            String roomNumber = readPropertyValue(businessObject, fieldMap, LocationField.ROOM_NUMBER);
144            String subRoomNumber = readPropertyValue(businessObject, fieldMap, LocationField.SUB_ROOM_NUMBER);
145            String contactName = readPropertyValue(businessObject, fieldMap, LocationField.CONTACT_NAME);
146            String streetAddress = readPropertyValue(businessObject, fieldMap, LocationField.STREET_ADDRESS);
147            String cityName = readPropertyValue(businessObject, fieldMap, LocationField.CITY_NAME);
148            String stateCode = readPropertyValue(businessObject, fieldMap, LocationField.STATE_CODE);
149            String zipCode = readPropertyValue(businessObject, fieldMap, LocationField.ZIP_CODE);
150            String countryCode = readPropertyValue(businessObject, fieldMap, LocationField.COUNTRY_CODE);
151    
152            // businessObject parameter could be BusinessObjectEntry or TransactionalDocumentEntry
153            DataDictionaryService ddService = this.getDataDictionaryService();
154            DataDictionaryEntryBase ddEntry = null;
155            if (DocumentBase.class.isAssignableFrom(businessObject.getClass())) {
156                String docTypeName = ddService.getDocumentTypeNameByClass(businessObject.getClass());
157                ddEntry = ddService.getDataDictionary().getDocumentEntry(docTypeName);
158            }
159            else {
160                ddEntry = this.getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(businessObject.getClass().getName());
161            }
162    
163            boolean onCampus = StringUtils.isNotBlank(buildingCode) || StringUtils.isNotBlank(roomNumber) || StringUtils.isNotBlank(subRoomNumber);
164            boolean offCampus = StringUtils.isNotBlank(contactName) || StringUtils.isNotBlank(streetAddress) || StringUtils.isNotBlank(cityName) || StringUtils.isNotBlank(stateCode) || StringUtils.isNotBlank(zipCode) || StringUtils.isNotBlank(countryCode);
165    
166            boolean valid = true;
167            if (onCampus && offCampus) {
168                putError(fieldMap, LocationField.BUILDING_CODE, CamsKeyConstants.AssetLocation.ERROR_CHOOSE_LOCATION_INFO);
169                valid &= false;
170            }
171            else {
172                if (isCapital) {
173                    valid &= validateCapitalAssetLocation(assetType, fieldMap, campusCode, buildingCode, roomNumber, subRoomNumber, contactName, streetAddress, cityName, stateCode, zipCode, countryCode, onCampus, offCampus, ddEntry);
174                }
175                else {
176                    valid &= validateNonCapitalAssetLocation(fieldMap, contactName, streetAddress, cityName, stateCode, zipCode, countryCode, onCampus, offCampus);
177                }
178            }
179            return valid;
180        }
181    
182    
183        protected boolean validateCapitalAssetLocation(AssetType assetType, Map<LocationField, String> fieldMap, String campusCode, String buildingCode, String roomNumber, String subRoomNumber, String contactName, String streetAddress, String cityName, String stateCode, String zipCode, String countryCode, boolean onCampus, boolean offCampus, DataDictionaryEntryBase businessObjectEntry) {
184            boolean valid = true;
185            if (ObjectUtils.isNull(assetType)) {
186                GlobalVariables.getMessageMap().putErrorForSectionId(CamsConstants.LOCATION_INFORMATION_SECTION_ID, CamsKeyConstants.AssetLocation.ERROR_CHOOSE_ASSET_TYPE);
187                valid &= false;
188            }
189            else {
190                String label;
191                if (assetType.isRequiredBuildingIndicator() && offCampus) {
192                    // off campus information not allowed
193                    if (StringUtils.isNotBlank(contactName)) {
194                        label = businessObjectEntry.getAttributeDefinition(fieldMap.get(LocationField.CONTACT_NAME)).getLabel();
195                        putError(fieldMap, LocationField.CONTACT_NAME, CamsKeyConstants.AssetLocation.ERROR_LOCATION_NOT_PERMITTED_ASSET_TYPE, new String[] { label, assetType.getCapitalAssetTypeDescription() });
196                        valid &= false;
197                    }
198                    if (StringUtils.isNotBlank(streetAddress)) {
199                        label = businessObjectEntry.getAttributeDefinition(fieldMap.get(LocationField.STREET_ADDRESS)).getLabel();
200                        putError(fieldMap, LocationField.STREET_ADDRESS, CamsKeyConstants.AssetLocation.ERROR_LOCATION_NOT_PERMITTED_ASSET_TYPE, new String[] { label, assetType.getCapitalAssetTypeDescription() });
201                        valid &= false;
202                    }
203    
204                    if (StringUtils.isNotBlank(cityName)) {
205                        label = businessObjectEntry.getAttributeDefinition(fieldMap.get(LocationField.CITY_NAME)).getLabel();
206                        putError(fieldMap, LocationField.CITY_NAME, CamsKeyConstants.AssetLocation.ERROR_LOCATION_NOT_PERMITTED_ASSET_TYPE, new String[] { label, assetType.getCapitalAssetTypeDescription() });
207                        valid &= false;
208                    }
209    
210                    if (StringUtils.isNotBlank(stateCode)) {
211                        label = businessObjectEntry.getAttributeDefinition(fieldMap.get(LocationField.STATE_CODE)).getLabel();
212                        putError(fieldMap, LocationField.STATE_CODE, CamsKeyConstants.AssetLocation.ERROR_LOCATION_NOT_PERMITTED_ASSET_TYPE, new String[] { label, assetType.getCapitalAssetTypeDescription() });
213                        valid &= false;
214                    }
215    
216                    if (StringUtils.isNotBlank(zipCode)) {
217                        label = businessObjectEntry.getAttributeDefinition(fieldMap.get(LocationField.ZIP_CODE)).getLabel();
218                        putError(fieldMap, LocationField.ZIP_CODE, CamsKeyConstants.AssetLocation.ERROR_LOCATION_NOT_PERMITTED_ASSET_TYPE, new String[] { label, assetType.getCapitalAssetTypeDescription() });
219                        valid &= false;
220                    }
221    
222                    if (StringUtils.isNotBlank(countryCode)) {
223                        label = businessObjectEntry.getAttributeDefinition(fieldMap.get(LocationField.COUNTRY_CODE)).getLabel();
224                        putError(fieldMap, LocationField.COUNTRY_CODE, CamsKeyConstants.AssetLocation.ERROR_LOCATION_NOT_PERMITTED_ASSET_TYPE, new String[] { label, assetType.getCapitalAssetTypeDescription() });
225                        valid &= false;
226                    }
227                }
228                else if (!assetType.isMovingIndicator() && !assetType.isRequiredBuildingIndicator() && onCampus) {
229                    // land information cannot have on-campus
230                    if (StringUtils.isNotBlank(buildingCode)) {
231                        label = businessObjectEntry.getAttributeDefinition(fieldMap.get(LocationField.BUILDING_CODE)).getLabel();
232                        putError(fieldMap, LocationField.BUILDING_CODE, CamsKeyConstants.AssetLocation.ERROR_LOCATION_NOT_PERMITTED_ASSET_TYPE, new String[] { label, assetType.getCapitalAssetTypeDescription() });
233                        valid &= false;
234                    }
235    
236                    if (StringUtils.isNotBlank(roomNumber)) {
237                        label = businessObjectEntry.getAttributeDefinition(fieldMap.get(LocationField.ROOM_NUMBER)).getLabel();
238                        putError(fieldMap, LocationField.ROOM_NUMBER, CamsKeyConstants.AssetLocation.ERROR_LOCATION_NOT_PERMITTED_ASSET_TYPE, new String[] { label, assetType.getCapitalAssetTypeDescription() });
239                        valid &= false;
240                    }
241    
242                    if (StringUtils.isNotBlank(subRoomNumber)) {
243                        label = businessObjectEntry.getAttributeDefinition(fieldMap.get(LocationField.SUB_ROOM_NUMBER)).getLabel();
244                        putError(fieldMap, LocationField.SUB_ROOM_NUMBER, CamsKeyConstants.AssetLocation.ERROR_LOCATION_NOT_PERMITTED_ASSET_TYPE, new String[] { label, assetType.getCapitalAssetTypeDescription() });
245                        valid &= false;
246                    }
247                }
248                else if (onCampus) {
249                    valid = validateOnCampusLocation(fieldMap, assetType, campusCode, buildingCode, roomNumber, subRoomNumber);
250                }
251                else if (offCampus) {
252                    valid = validateOffCampusLocation(fieldMap, contactName, streetAddress, cityName, stateCode, zipCode, countryCode);
253                }
254                else if (assetType.isMovingIndicator() || assetType.isRequiredBuildingIndicator()) {
255                    putError(fieldMap, LocationField.BUILDING_CODE, CamsKeyConstants.AssetLocation.ERROR_LOCATION_INFO_REQUIRED);
256                    valid &= false;
257                }
258            }
259            return valid;
260        }
261    
262        protected boolean validateNonCapitalAssetLocation(Map<LocationField, String> fieldMap, String contactName, String streetAddress, String cityName, String stateCode, String zipCode, String countryCode, boolean onCampus, boolean offCampus) {
263            boolean valid = true;
264            if (offCampus) {
265                valid = validateOffCampusLocation(fieldMap, contactName, streetAddress, cityName, stateCode, zipCode, countryCode);
266            }
267            return valid;
268        }
269    
270    
271        /**
272         * Convenience method to append the path prefix
273         */
274        protected void putError(Map<LocationField, String> fieldMap, LocationField field, String errorKey, String... errorParameters) {
275            GlobalVariables.getMessageMap().putError(fieldMap.get(field), errorKey, errorParameters);
276        }
277    
278        protected boolean validateOnCampusLocation(Map<LocationField, String> fieldMap, AssetType assetType, String campusCode, String buildingCode, String buildingRoomNumber, String subRoomNumber) {
279            boolean valid = true;
280            if (assetType.isMovingIndicator()) {
281                if (StringUtils.isBlank(buildingCode)) {
282                    putError(fieldMap, LocationField.BUILDING_CODE, CamsKeyConstants.AssetLocation.ERROR_ONCAMPUS_BUILDING_CODE_REQUIRED, assetType.getCapitalAssetTypeDescription());
283                    valid &= false;
284                }
285                if (StringUtils.isBlank(buildingRoomNumber)) {
286                    putError(fieldMap, LocationField.ROOM_NUMBER, CamsKeyConstants.AssetLocation.ERROR_ONCAMPUS_BUILDING_ROOM_NUMBER_REQUIRED, assetType.getCapitalAssetTypeDescription());
287                    valid &= false;
288                }
289            }
290            if (assetType.isRequiredBuildingIndicator()) {
291                if (StringUtils.isBlank(buildingCode)) {
292                    putError(fieldMap, LocationField.BUILDING_CODE, CamsKeyConstants.AssetLocation.ERROR_ONCAMPUS_BUILDING_CODE_REQUIRED, assetType.getCapitalAssetTypeDescription());
293                    valid &= false;
294                }
295                if (StringUtils.isNotBlank(buildingRoomNumber)) {
296                    putError(fieldMap, LocationField.ROOM_NUMBER, CamsKeyConstants.AssetLocation.ERROR_ONCAMPUS_BUILDING_ROOM_NUMBER_NOT_PERMITTED, assetType.getCapitalAssetTypeDescription());
297                    valid &= false;
298                }
299                if (StringUtils.isNotBlank(subRoomNumber)) {
300                    putError(fieldMap, LocationField.SUB_ROOM_NUMBER, CamsKeyConstants.AssetLocation.ERROR_ONCAMPUS_SUB_ROOM_NUMBER_NOT_PERMITTED, assetType.getCapitalAssetTypeDescription());
301                    valid &= false;
302                }
303            }
304            return valid;
305        }
306    
307        protected boolean validateOffCampusLocation(Map<LocationField, String> fieldMap, String contactName, String streetAddress, String cityName, String stateCode, String zipCode, String countryCode) {
308            boolean valid = true;
309            boolean isCountryUS = false;
310            if (isBlank(fieldMap, LocationField.COUNTRY_CODE, countryCode)) {
311                putError(fieldMap, LocationField.COUNTRY_CODE, CamsKeyConstants.AssetLocation.ERROR_OFFCAMPUS_COUNTRY_REQUIRED);
312                valid &= false;
313            }
314            else {
315                isCountryUS = countryCode.equals(KFSConstants.COUNTRY_CODE_UNITED_STATES);
316            }
317    
318            if (isBlank(fieldMap, LocationField.CONTACT_NAME, contactName)) {
319                putError(fieldMap, LocationField.CONTACT_NAME, CamsKeyConstants.AssetLocation.ERROR_OFFCAMPUS_CONTACT_REQUIRED);
320                valid &= false;
321            }
322    
323            if (isBlank(fieldMap, LocationField.STREET_ADDRESS, streetAddress)) {
324                putError(fieldMap, LocationField.STREET_ADDRESS, CamsKeyConstants.AssetLocation.ERROR_OFFCAMPUS_ADDRESS_REQUIRED);
325                valid &= false;
326            }
327            if (isBlank(fieldMap, LocationField.CITY_NAME, cityName)) {
328                putError(fieldMap, LocationField.CITY_NAME, CamsKeyConstants.AssetLocation.ERROR_OFFCAMPUS_CITY_REQUIRED);
329                valid &= false;
330            }
331    
332    
333            if (isCountryUS) {
334                if (isBlank(fieldMap, LocationField.STATE_CODE, stateCode)) {
335                    putError(fieldMap, LocationField.STATE_CODE, CamsKeyConstants.AssetLocation.ERROR_OFFCAMPUS_STATE_REQUIRED);
336                    valid &= false;
337                }
338                if (isBlank(fieldMap, LocationField.ZIP_CODE, zipCode)) {
339                    putError(fieldMap, LocationField.ZIP_CODE, CamsKeyConstants.AssetLocation.ERROR_OFFCAMPUS_ZIP_REQUIRED);
340                    valid &= false;
341                }
342                if (!isBlank(fieldMap, LocationField.STATE_CODE, stateCode)) {
343                    Map assetLocationMap = new HashMap();
344                    assetLocationMap.put(KFSPropertyConstants.POSTAL_STATE_CODE, stateCode);
345                    State locationState = SpringContext.getBean(StateService.class).getByPrimaryId(stateCode);
346                    if (ObjectUtils.isNull(locationState)) {
347                        putError(fieldMap, LocationField.STATE_CODE, CamsKeyConstants.AssetLocation.ERROR_INVALID_OFF_CAMPUS_STATE, stateCode);
348                        valid &= false;
349                    }
350                }
351            }
352    
353            return valid;
354        }
355    
356        protected boolean isBlank(Map<LocationField, String> fieldMap, LocationField field, String countryCode) {
357            return fieldMap.get(field) != null && StringUtils.isBlank(countryCode);
358        }
359    
360        protected String readPropertyValue(BusinessObject currObject, Map<LocationField, String> fieldMap, LocationField field) {
361            String stringValue = null;
362            try {
363                String propertyName = fieldMap.get(field);
364                if (propertyName != null) {
365                    stringValue = (String) ObjectUtils.getNestedValue(currObject, propertyName);
366                }
367            }
368            catch (Exception e) {
369                throw new RuntimeException(e);
370            }
371            return stringValue;
372        }
373    
374        public BusinessObjectService getBusinessObjectService() {
375            return businessObjectService;
376        }
377    
378        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
379            this.businessObjectService = businessObjectService;
380        }
381    
382        public DataDictionaryService getDataDictionaryService() {
383            return DataDictionaryService;
384        }
385    
386        public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
387            DataDictionaryService = dataDictionaryService;
388        }
389    
390    }