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.bc.businessobject.lookup;
017    
018    import java.util.ArrayList;
019    import java.util.List;
020    import java.util.Map;
021    
022    import org.apache.commons.lang.StringUtils;
023    import org.kuali.kfs.module.bc.BCConstants;
024    import org.kuali.kfs.module.bc.BCKeyConstants;
025    import org.kuali.kfs.module.bc.BCPropertyConstants;
026    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionFundingLock;
027    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionHeader;
028    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionLockSummary;
029    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionPosition;
030    import org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding;
031    import org.kuali.kfs.module.bc.document.service.LockService;
032    import org.kuali.kfs.sys.KFSConstants;
033    import org.kuali.kfs.sys.context.SpringContext;
034    import org.kuali.rice.kim.bo.Person;
035    import org.kuali.rice.kim.service.PersonService;
036    import org.kuali.rice.kns.authorization.BusinessObjectRestrictions;
037    import org.kuali.rice.kns.bo.BusinessObject;
038    import org.kuali.rice.kns.lookup.CollectionIncomplete;
039    import org.kuali.rice.kns.lookup.HtmlData;
040    import org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl;
041    import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
042    import org.kuali.rice.kns.lookup.HtmlData.InputHtmlData;
043    import org.kuali.rice.kns.service.KualiConfigurationService;
044    import org.kuali.rice.kns.util.GlobalVariables;
045    import org.kuali.rice.kns.util.KNSConstants;
046    import org.kuali.rice.kns.web.struts.form.LookupForm;
047    
048    /**
049     * Implements custom search routine to find the current budget locks and build up the result List. Set an unlock URL for each lock.
050     */
051    public class LockMonitorLookupableHelperServiceImpl extends KualiLookupableHelperServiceImpl {
052        private KualiConfigurationService kualiConfigurationService;
053        private PersonService<Person> personService;
054        
055        /**
056         * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#getSearchResults(java.util.Map)
057         */
058        @Override
059        public List<? extends BusinessObject> getSearchResults(Map<String, String> fieldValues) {
060            setBackLocation(fieldValues.get(KFSConstants.BACK_LOCATION));
061            setDocFormKey(fieldValues.get(KFSConstants.DOC_FORM_KEY));
062            setReferencesToRefresh(fieldValues.get(KFSConstants.REFERENCES_TO_REFRESH));
063    
064            List<BudgetConstructionLockSummary> results = new ArrayList<BudgetConstructionLockSummary>();
065         
066            // get universal identifier from network id
067            String lockUserID = fieldValues.get(BCPropertyConstants.LOCK_USER_ID);
068            String lockUnivId = getUniversalIdFromNetworkID(lockUserID);
069    
070            getAccountLocks(results, lockUnivId);
071            getTransactionLocks(results, lockUnivId);
072            getOrphanFundingLocks(results, lockUnivId);
073            getPositionFundingLocks(results, lockUnivId);
074            getOrphanPositionLocks(results, lockUnivId);
075    
076            return new CollectionIncomplete(results, new Long(0));
077        }
078    
079        /**
080         * Calls lock service to retrieve all current account locks and builds a lock summary object for each returned lock.
081         * 
082         * @param results - result list to add lock summaries
083         */
084        protected void getAccountLocks(List<BudgetConstructionLockSummary> results, String lockUnivId) {
085            List<BudgetConstructionHeader> accountLocks = SpringContext.getBean(LockService.class).getAllAccountLocks(lockUnivId);
086            for (BudgetConstructionHeader header : accountLocks) {
087                BudgetConstructionLockSummary lockSummary = new BudgetConstructionLockSummary();
088                lockSummary.setLockType(BCConstants.LockTypes.ACCOUNT_LOCK);
089                lockSummary.setLockUserId(header.getBudgetLockUser().getPrincipalName());
090    
091                lockSummary.setDocumentNumber(header.getDocumentNumber());
092                lockSummary.setUniversityFiscalYear(header.getUniversityFiscalYear());
093                lockSummary.setChartOfAccountsCode(header.getChartOfAccountsCode());
094                lockSummary.setAccountNumber(header.getAccountNumber());
095                lockSummary.setSubAccountNumber(header.getSubAccountNumber());
096    
097                results.add(lockSummary);
098            }
099        }
100    
101        /**
102         * Calls lock service to retrieve all current transaction locks and builds a lock summary object for each returned lock.
103         * 
104         * @param results - result list to add lock summaries
105         */
106        protected void getTransactionLocks(List<BudgetConstructionLockSummary> results, String lockUnivId) {
107            List<BudgetConstructionHeader> transLocks = SpringContext.getBean(LockService.class).getAllTransactionLocks(lockUnivId);
108            for (BudgetConstructionHeader header : transLocks) {
109                BudgetConstructionLockSummary lockSummary = new BudgetConstructionLockSummary();
110                lockSummary.setLockType(BCConstants.LockTypes.TRANSACTION_LOCK);
111                lockSummary.setLockUserId(header.getBudgetTransactionLockUser().getPrincipalName());
112    
113                lockSummary.setDocumentNumber(header.getDocumentNumber());
114                lockSummary.setUniversityFiscalYear(header.getUniversityFiscalYear());
115                lockSummary.setChartOfAccountsCode(header.getChartOfAccountsCode());
116                lockSummary.setAccountNumber(header.getAccountNumber());
117                lockSummary.setSubAccountNumber(header.getSubAccountNumber());
118    
119                results.add(lockSummary);
120            }
121        }
122    
123        /**
124         * Calls lock service to retrieve all funding locks that do not have a corresponding position locks and builds a lock summary
125         * object for each returned lock.
126         * 
127         * @param results - result list to add lock summaries
128         */
129        protected void getOrphanFundingLocks(List<BudgetConstructionLockSummary> results, String lockUnivId) {
130            List<BudgetConstructionFundingLock> fundingLocks = SpringContext.getBean(LockService.class).getOrphanedFundingLocks(lockUnivId);
131            for (BudgetConstructionFundingLock fundingLock : fundingLocks) {
132                BudgetConstructionLockSummary lockSummary = new BudgetConstructionLockSummary();
133                lockSummary.setLockType(BCConstants.LockTypes.FUNDING_LOCK);
134                lockSummary.setLockUserId(fundingLock.getAppointmentFundingLockUser().getPrincipalName());
135    
136                lockSummary.setUniversityFiscalYear(fundingLock.getUniversityFiscalYear());
137                lockSummary.setChartOfAccountsCode(fundingLock.getChartOfAccountsCode());
138                lockSummary.setAccountNumber(fundingLock.getAccountNumber());
139                lockSummary.setSubAccountNumber(fundingLock.getSubAccountNumber());
140    
141                results.add(lockSummary);
142            }
143        }
144    
145        /**
146         * Calls lock service to retrieve all current position/funding locks and builds a lock summary object for each returned lock.
147         * 
148         * @param results - result list to add lock summaries
149         */
150        protected void getPositionFundingLocks(List<BudgetConstructionLockSummary> results, String lockUnivId) {
151            List<PendingBudgetConstructionAppointmentFunding> positionFundingLocks = SpringContext.getBean(LockService.class).getAllPositionFundingLocks(lockUnivId);
152            for (PendingBudgetConstructionAppointmentFunding appointmentFunding : positionFundingLocks) {
153                BudgetConstructionLockSummary lockSummary = new BudgetConstructionLockSummary();
154                lockSummary.setLockType(BCConstants.LockTypes.POSITION_FUNDING_LOCK);
155                lockSummary.setLockUserId(appointmentFunding.getBudgetConstructionPosition().getPositionLockUser().getPrincipalName());
156    
157                lockSummary.setUniversityFiscalYear(appointmentFunding.getUniversityFiscalYear());
158                lockSummary.setChartOfAccountsCode(appointmentFunding.getChartOfAccountsCode());
159                lockSummary.setAccountNumber(appointmentFunding.getAccountNumber());
160                lockSummary.setSubAccountNumber(appointmentFunding.getSubAccountNumber());
161    
162                lockSummary.setPositionNumber(appointmentFunding.getBudgetConstructionPosition().getPositionNumber());
163                lockSummary.setPositionDescription(appointmentFunding.getBudgetConstructionPosition().getPositionDescription());
164    
165                results.add(lockSummary);
166            }
167        }
168    
169        /**
170         * Calls lock service to retrieve all current position locks without a corresponding funding lock and builds a lock summary
171         * object for each returned lock.
172         * 
173         * @param results - result list to add lock summaries
174         */
175        protected void getOrphanPositionLocks(List<BudgetConstructionLockSummary> results, String lockUnivId) {
176            List<BudgetConstructionPosition> positionLocks = SpringContext.getBean(LockService.class).getOrphanedPositionLocks(lockUnivId);
177            for (BudgetConstructionPosition position : positionLocks) {
178                BudgetConstructionLockSummary lockSummary = new BudgetConstructionLockSummary();
179                lockSummary.setLockType(BCConstants.LockTypes.POSITION_LOCK);
180                lockSummary.setLockUserId(position.getPositionLockUser().getPrincipalName());
181    
182                lockSummary.setUniversityFiscalYear(position.getUniversityFiscalYear());
183                lockSummary.setPositionNumber(position.getPositionNumber());
184                lockSummary.setPositionDescription(position.getPositionDescription());
185    
186                results.add(lockSummary);
187            }
188        }
189    
190        /**
191         * Builds unlink action for each type of lock.
192         * 
193         * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#getCustomActionUrls(org.kuali.rice.kns.bo.BusinessObject, java.util.List)
194         */
195        @Override
196        public List<HtmlData> getCustomActionUrls(BusinessObject businessObject, List pkNames) {
197            BudgetConstructionLockSummary lockSummary = (BudgetConstructionLockSummary) businessObject;
198    
199            String imageDirectory = kualiConfigurationService.getPropertyString(KFSConstants.EXTERNALIZABLE_IMAGES_URL_KEY);
200            String lockFields = lockSummary.getUniversityFiscalYear() + BCConstants.LOCK_STRING_DELIMITER + lockSummary.getChartOfAccountsCode() + BCConstants.LOCK_STRING_DELIMITER + lockSummary.getAccountNumber() + BCConstants.LOCK_STRING_DELIMITER + lockSummary.getSubAccountNumber() + BCConstants.LOCK_STRING_DELIMITER + lockSummary.getPositionNumber() + BCConstants.LOCK_STRING_DELIMITER;
201            lockFields = StringUtils.replace(lockFields, "null", "");
202            
203            String name = KFSConstants.DISPATCH_REQUEST_PARAMETER + "." + BCConstants.TEMP_LIST_UNLOCK_METHOD + ".";
204            name += 
205                KFSConstants.METHOD_TO_CALL_PARM1_LEFT_DEL + StringUtils.replace(lockSummary.getLockType()," ","_") + 
206                KFSConstants.METHOD_TO_CALL_PARM1_RIGHT_DEL;
207            name += KFSConstants.METHOD_TO_CALL_PARM9_LEFT_DEL + lockFields + KFSConstants.METHOD_TO_CALL_PARM9_RIGHT_DEL;
208            name += 
209                KFSConstants.METHOD_TO_CALL_PARM3_LEFT_DEL + lockSummary.getLockUserId() + 
210                KFSConstants.METHOD_TO_CALL_PARM3_RIGHT_DEL;
211            String src = imageDirectory + BCConstants.UNLOCK_BUTTON_NAME;
212            String inputType = "image";
213            String styleClass = "tinybutton";
214            String border= "0";
215            
216            List<HtmlData> htmlDataList = new ArrayList<HtmlData>();
217            InputHtmlData inputHtmlData = new InputHtmlData(name, inputType, src);
218            inputHtmlData.setStyleClass(styleClass);
219            inputHtmlData.setBorder(border);
220            htmlDataList.add(inputHtmlData);
221            return htmlDataList;
222        }
223        
224        /**
225         * Uses org.kuali.rice.kim.service.PersonService to retrieve user object associated with the given network id (if not blank) and then
226         * returns universal id. Add error to GlobalVariables if the user was not found.
227         * 
228         * @param networkID - network id for the user to find
229         * @return universal id for the user or null if not found or the network id was blank
230         */
231        protected String getUniversalIdFromNetworkID(String networkID) {
232            String universalId = null;
233            if (StringUtils.isNotBlank(networkID)) {
234                Person user = getPersonService().getPersonByPrincipalName(networkID);
235                if (user != null) {
236                    universalId = user.getPrincipalId();
237                } else {
238                    GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, BCKeyConstants.ERROR_LOCK_INVALID_USER, networkID);
239                }
240            }
241            
242            return universalId;
243        }
244    
245        /**
246         * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#getReturnUrl(org.kuali.rice.kns.bo.BusinessObject, java.util.Map, java.lang.String)
247         */
248        @Override
249        public HtmlData getReturnUrl(BusinessObject businessObject, LookupForm lookupForm, List pkNames, BusinessObjectRestrictions businessObjectRestrictions) {
250            return getEmptyAnchorHtmlData();
251        }
252    
253        /**
254         * Overridden to prevent a validation exception from thrown when the search method is called to refresh the
255         * results after an error is encountered.
256         * 
257         * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#validateSearchParameters(java.util.Map)
258         */
259        @Override
260        public void validateSearchParameters(Map fieldValues) {
261        }
262    
263        /**
264         * Since this lookupable is called by the budget lookup action, the context will be KFS, not Rice. So the generated inquiries
265         * will not have the Rice context (kr/) and be invalid. This override adds the Rice context to the inquiry Url to working
266         * around the issue.
267         * 
268         * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#getInquiryUrl(org.kuali.rice.kns.bo.BusinessObject,
269         *      java.lang.String)
270         */
271        @Override
272        public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
273            AnchorHtmlData inquiryUrl = (AnchorHtmlData)super.getInquiryUrl(bo, propertyName);
274            inquiryUrl.setHref(StringUtils.replace(inquiryUrl.getHref(), KNSConstants.INQUIRY_ACTION, KFSConstants.INQUIRY_ACTION));
275    
276            return inquiryUrl;
277        }
278    
279        /**
280         * Sets the kualiConfigurationService attribute value.
281         * 
282         * @param kualiConfigurationService The kualiConfigurationService to set.
283         */
284        public void setKualiConfigurationService(KualiConfigurationService kualiConfigurationService) {
285            this.kualiConfigurationService = kualiConfigurationService;
286        }
287    
288        /**
289         * @return Returns the personService.
290         */
291        protected PersonService<Person> getPersonService() {
292            if(personService==null)
293                personService = SpringContext.getBean(PersonService.class);
294            return personService;
295        }
296    
297    }