View Javadoc
1   /*
2    * Copyright 2007 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.gl.web.struts;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Properties;
24  
25  import javax.servlet.http.HttpServletRequest;
26  import javax.servlet.http.HttpServletResponse;
27  
28  import org.apache.commons.lang.StringUtils;
29  import org.apache.struts.action.ActionForm;
30  import org.apache.struts.action.ActionForward;
31  import org.apache.struts.action.ActionMapping;
32  import org.kuali.ole.gl.GeneralLedgerConstants;
33  import org.kuali.ole.gl.ObjectHelper;
34  import org.kuali.ole.gl.businessobject.AccountBalance;
35  import org.kuali.ole.gl.businessobject.lookup.AccountBalanceByConsolidationLookupableHelperServiceImpl;
36  import org.kuali.ole.sys.OLEConstants;
37  import org.kuali.ole.sys.OLEKeyConstants;
38  import org.kuali.ole.sys.OLEPropertyConstants;
39  import org.kuali.ole.sys.context.SpringContext;
40  import org.kuali.rice.core.api.config.property.ConfigurationService;
41  import org.kuali.rice.kns.lookup.LookupResultsService;
42  import org.kuali.rice.kns.lookup.Lookupable;
43  import org.kuali.rice.kns.web.struts.action.KualiMultipleValueLookupAction;
44  import org.kuali.rice.kns.web.struts.form.MultipleValueLookupForm;
45  import org.kuali.rice.kns.web.ui.Column;
46  import org.kuali.rice.kns.web.ui.ResultRow;
47  import org.kuali.rice.krad.lookup.CollectionIncomplete;
48  import org.kuali.rice.krad.service.SequenceAccessorService;
49  import org.kuali.rice.krad.util.GlobalVariables;
50  import org.kuali.rice.krad.util.KRADConstants;
51  import org.kuali.rice.krad.util.UrlFactory;
52  
53  /**
54   * Balance inquiries are pretty much just lookups already, but are not used in the traditional sense. In most cases, balance
55   * inquiries only show the end-user data, and allow the end-user to drill-down into inquiries. A traditional lookup allows the user
56   * to return data to a form. This class is for balance inquiries implemented in the sense of a traditional lookup for forms that
57   * pull data out of inquiries.<br/> <br/> One example of this is the
58   * <code>{@link org.kuali.ole.module.ld.document.SalaryExpenseTransferDocument}</code> which creates source lines from a labor
59   * ledger balance inquiry screen.<br/> <br/> This is a <code>{@link KualiMultipleValueLookupAction}</code> which required some
60   * customization because requirements were not possible with displaytag.
61   *
62   * @see org.kuali.ole.module.ld.document.SalaryExpenseTransferDocument
63   * @see org.kuali.ole.module.ld.document.web.struts.SalaryExpenseTransferAction;
64   * @see org.kuali.ole.module.ld.document.web.struts.SalaryExpenseTransferForm;
65   */
66  public class BalanceInquiryLookupAction extends KualiMultipleValueLookupAction {
67      private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory.getLog(BalanceInquiryLookupAction.class);
68  
69      private static final String TOTALS_TABLE_KEY = "totalsTable";
70  
71      /**
72       * If there is no app param defined for the # rows/page, then this value will be used for the default
73       *
74       * @see KualiMultipleValueLookupAction#getMaxRowsPerPage(MultipleValueLookupForm)
75       */
76      public static final int DEFAULT_MAX_ROWS_PER_PAGE = 50;
77  
78      private ConfigurationService kualiConfigurationService;
79      private String[] totalTitles;
80  
81      public BalanceInquiryLookupAction() {
82          super();
83          kualiConfigurationService = SpringContext.getBean(ConfigurationService.class);
84      }
85  
86      private void setTotalTitles() {
87          totalTitles = new String[7];
88  
89          totalTitles[0] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.INCOME);
90          totalTitles[1] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.INCOME_FROM_TRANSFERS);
91          totalTitles[2] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.INCOME_TOTAL);
92          totalTitles[3] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.EXPENSE);
93          totalTitles[4] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.EXPENSE_FROM_TRANSFERS);
94          totalTitles[5] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.EXPENSE_TOTAL);
95          totalTitles[6] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.TOTAL);
96  
97      }
98  
99      private String[] getTotalTitles() {
100         if (null == totalTitles) {
101             setTotalTitles();
102         }
103 
104         return totalTitles;
105     }
106 
107     /**
108      * search - sets the values of the data entered on the form on the jsp into a map and then searches for the results.
109      *
110      * KRAD Conversion: Lookupable performs customization of the results if
111      * balance inquiry. The result rows are added to a collection
112      * based on field's actual size if truncated is > 7.
113      *
114      * Fields are in data dictionary for bo Balance.
115      */
116     @Override
117     public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
118         BalanceInquiryLookupForm lookupForm = (BalanceInquiryLookupForm) form;
119         Lookupable lookupable = lookupForm.getLookupable();
120 
121         if (lookupable == null) {
122             LOG.error("Lookupable is null.");
123             throw new RuntimeException("Lookupable is null.");
124         }
125 
126         Collection displayList = new ArrayList();
127         CollectionIncomplete incompleteDisplayList;
128         List<ResultRow> resultTable = new ArrayList<ResultRow>();
129         Long totalSize;
130         boolean bounded = true;
131 
132         lookupable.validateSearchParameters(lookupForm.getFields());
133 
134         displayList = performMultipleValueLookup(lookupForm, resultTable, getMaxRowsPerPage(lookupForm), bounded);
135         incompleteDisplayList = (CollectionIncomplete) displayList;
136         totalSize = incompleteDisplayList.getActualSizeIfTruncated();
137 
138         if (lookupable.isSearchUsingOnlyPrimaryKeyValues()) {
139             lookupForm.setSearchUsingOnlyPrimaryKeyValues(true);
140             lookupForm.setPrimaryKeyFieldLabels(lookupable.getPrimaryKeyFieldLabels());
141         }
142         else {
143             lookupForm.setSearchUsingOnlyPrimaryKeyValues(false);
144             lookupForm.setPrimaryKeyFieldLabels(OLEConstants.EMPTY_STRING);
145         }
146 
147 
148         // TODO: use inheritance instead of this if statement
149         if (lookupable.getLookupableHelperService() instanceof AccountBalanceByConsolidationLookupableHelperServiceImpl) {
150             Object[] resultTableAsArray = resultTable.toArray();
151             Collection totalsTable = new ArrayList();
152 
153             int arrayIndex = 0;
154 
155             try {
156                 for (int listIndex = 0; listIndex < incompleteDisplayList.size(); listIndex++) {
157                     AccountBalance balance = (AccountBalance) incompleteDisplayList.get(listIndex);
158                     boolean ok = ObjectHelper.isOneOf(balance.getTitle(), getTotalTitles());
159                     if (ok) {
160                         if (totalSize > 7) {
161                             totalsTable.add(resultTableAsArray[arrayIndex]);
162                         }
163                         resultTable.remove(resultTableAsArray[arrayIndex]);
164                         incompleteDisplayList.remove(balance);
165                     }
166                     arrayIndex++;
167                 }
168 
169                 request.setAttribute(TOTALS_TABLE_KEY, totalsTable);
170                 GlobalVariables.getUserSession().addObject(TOTALS_TABLE_KEY, totalsTable);
171             }
172             catch (NumberFormatException e) {
173                 GlobalVariables.getMessageMap().putError(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, OLEKeyConstants.ERROR_CUSTOM, new String[] { "Fiscal Year must be a four-digit number" });
174             }
175             catch (Exception e) {
176                 GlobalVariables.getMessageMap().putError(OLEConstants.DOCUMENT_ERRORS, OLEKeyConstants.ERROR_CUSTOM, new String[] { "Please report the server error." });
177                 LOG.error("Application Errors", e);
178             }
179         }
180 
181         request.setAttribute(OLEConstants.REQUEST_SEARCH_RESULTS_SIZE, totalSize);
182         request.setAttribute(OLEConstants.REQUEST_SEARCH_RESULTS, resultTable);
183         lookupForm.setResultsActualSize((int) totalSize.longValue());
184         lookupForm.setResultsLimitedSize(resultTable.size());
185 
186         if (lookupForm.isSegmented()) {
187             LOG.debug("I'm segmented");
188             request.setAttribute(GeneralLedgerConstants.LookupableBeanKeys.SEGMENTED_LOOKUP_FLAG_NAME, Boolean.TRUE);
189         }
190 
191         if (request.getParameter(OLEConstants.SEARCH_LIST_REQUEST_KEY) != null) {
192             GlobalVariables.getUserSession().removeObject(request.getParameter(OLEConstants.SEARCH_LIST_REQUEST_KEY));
193             request.setAttribute(OLEConstants.SEARCH_LIST_REQUEST_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(resultTable));
194         }
195 
196         return mapping.findForward(OLEConstants.MAPPING_BASIC);
197     }
198 
199     /**
200      * This method returns none of the selected results and redirects back to the lookup caller.
201      *
202      * @param mapping
203      * @param form must be an instance of MultipleValueLookupForm
204      * @param request
205      * @param response
206      * @return
207      * @throws Exception
208      */
209     @Override
210     public ActionForward prepareToReturnNone(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
211         MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
212         prepareToReturnNone(multipleValueLookupForm);
213 
214         // build the parameters for the refresh url
215         Properties parameters = new Properties();
216         parameters.put(OLEConstants.DOC_FORM_KEY, multipleValueLookupForm.getFormKey());
217         parameters.put(OLEConstants.DISPATCH_REQUEST_PARAMETER, OLEConstants.RETURN_METHOD_TO_CALL);
218         parameters.put(OLEConstants.REFRESH_CALLER, OLEConstants.MULTIPLE_VALUE);
219         parameters.put(OLEConstants.ANCHOR, multipleValueLookupForm.getLookupAnchor());
220 
221         String backUrl = UrlFactory.parameterizeUrl(multipleValueLookupForm.getBackLocation(), parameters);
222         return new ActionForward(backUrl, true);
223     }
224 
225     /**
226      * This method does the processing necessary to return selected results and sends a redirect back to the lookup caller
227      *
228      * @param mapping
229      * @param form must be an instance of MultipleValueLookupForm
230      * @param request
231      * @param response
232      * @return
233      * @throws Exception
234      */
235     @Override
236     public ActionForward prepareToReturnSelectedResults(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
237         MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
238         if (StringUtils.isBlank(multipleValueLookupForm.getLookupResultsSequenceNumber())) {
239             // no search was executed
240             return prepareToReturnNone(mapping, form, request, response);
241         }
242 
243         prepareToReturnSelectedResultBOs(multipleValueLookupForm);
244 
245         // build the parameters for the refresh url
246         Properties parameters = new Properties();
247         parameters.put(OLEConstants.LOOKUP_RESULTS_BO_CLASS_NAME, multipleValueLookupForm.getBusinessObjectClassName());
248         parameters.put(OLEConstants.LOOKUP_RESULTS_SEQUENCE_NUMBER, multipleValueLookupForm.getLookupResultsSequenceNumber());
249         parameters.put(OLEConstants.DOC_FORM_KEY, multipleValueLookupForm.getFormKey());
250         parameters.put(OLEConstants.DISPATCH_REQUEST_PARAMETER, OLEConstants.RETURN_METHOD_TO_CALL);
251         parameters.put(OLEConstants.REFRESH_CALLER, OLEConstants.MULTIPLE_VALUE);
252         parameters.put(OLEConstants.ANCHOR, multipleValueLookupForm.getLookupAnchor());
253         String backUrl = UrlFactory.parameterizeUrl(multipleValueLookupForm.getBackLocation(), parameters);
254         return new ActionForward(backUrl, true);
255     }
256 
257     /**
258      * @see org.kuali.rice.kns.web.struts.action.KualiMultipleValueLookupAction#sort(org.apache.struts.action.ActionMapping,
259      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
260      */
261     @Override
262     public ActionForward sort(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
263         request.setAttribute(GeneralLedgerConstants.LookupableBeanKeys.SEGMENTED_LOOKUP_FLAG_NAME, Boolean.TRUE);
264         return super.sort(mapping, form, request, response);
265     }
266 
267     /**
268      * @see org.kuali.rice.kns.web.struts.action.KualiMultipleValueLookupAction#selectAll(org.apache.struts.action.ActionMapping,
269      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
270      */
271     @Override
272     public ActionForward selectAll(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
273         request.setAttribute(GeneralLedgerConstants.LookupableBeanKeys.SEGMENTED_LOOKUP_FLAG_NAME, Boolean.TRUE);
274         return super.selectAll(mapping, form, request, response);
275     }
276 
277     /**
278      * @see org.kuali.rice.kns.web.struts.action.KualiMultipleValueLookupAction#unselectAll(org.apache.struts.action.ActionMapping,
279      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
280      */
281     @Override
282     public ActionForward unselectAll(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
283         request.setAttribute(GeneralLedgerConstants.LookupableBeanKeys.SEGMENTED_LOOKUP_FLAG_NAME, Boolean.TRUE);
284         return super.unselectAll(mapping, form, request, response);
285     }
286 
287     /**
288      * @see org.kuali.rice.kns.web.struts.action.KualiMultipleValueLookupAction#switchToPage(org.apache.struts.action.ActionMapping,
289      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
290      */
291     @Override
292     public ActionForward switchToPage(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
293         request.setAttribute(GeneralLedgerConstants.LookupableBeanKeys.SEGMENTED_LOOKUP_FLAG_NAME, Boolean.TRUE);
294         return super.switchToPage(mapping, form, request, response);
295     }
296 
297     /**
298      * This method performs the lookup and returns a collection of lookup items. Also initializes values in the form that will allow
299      * the multiple value lookup page to render
300      *
301      * @param multipleValueLookupForm
302      * @param resultTable a list of result rows (used to generate what's shown in the UI). This list will be modified by this method
303      * @param maxRowsPerPage
304      * @param bounded whether the results will be bounded
305      * @return the list of result BOs, possibly bounded by size
306      *
307      * KRAD Conversion: Lookupable performs customization of the results if
308      * balance inquiry. The multiple value results are sorted.
309      *
310      * Fields are in data dictionary for bo Balance.
311      */
312     @Override
313     protected Collection performMultipleValueLookup(MultipleValueLookupForm multipleValueLookupForm, List<ResultRow> resultTable, int maxRowsPerPage, boolean bounded) {
314         Lookupable lookupable = multipleValueLookupForm.getLookupable();
315         Collection displayList = lookupable.performLookup(multipleValueLookupForm, resultTable, bounded);
316 
317         List defaultSortColumns = lookupable.getDefaultSortColumns();
318         if (defaultSortColumns != null && !defaultSortColumns.isEmpty() && resultTable != null && !resultTable.isEmpty()) {
319             // there's a default sort order, just find the first sort column, and we can't go wrong
320             String firstSortColumn = (String) defaultSortColumns.get(0);
321 
322             // go thru the first result row to find the index of the column (more efficient than calling lookupable.getColumns since
323             // we don't have to recreate column list)
324             int firstSortColumnIdx = -1;
325             List<Column> columnsForFirstResultRow = resultTable.get(0).getColumns();
326             for (int i = 0; i < columnsForFirstResultRow.size(); i++) {
327                 if (StringUtils.equals(firstSortColumn, columnsForFirstResultRow.get(i).getPropertyName())) {
328                     firstSortColumnIdx = i;
329                     break;
330                 }
331             }
332             multipleValueLookupForm.setColumnToSortIndex(firstSortColumnIdx);
333         }
334         else {
335             // don't know how results were sorted, so we just say -1
336             multipleValueLookupForm.setColumnToSortIndex(-1);
337         }
338 
339         // we just performed the lookup, so we're on the first page (indexed from 0)
340         multipleValueLookupForm.jumpToFirstPage(resultTable.size(), maxRowsPerPage);
341 
342         SequenceAccessorService sequenceAccessorService = SpringContext.getBean(SequenceAccessorService.class);
343         String lookupResultsSequenceNumber = String.valueOf(sequenceAccessorService.getNextAvailableSequenceNumber(KRADConstants.LOOKUP_RESULTS_SEQUENCE));
344         multipleValueLookupForm.setLookupResultsSequenceNumber(lookupResultsSequenceNumber);
345         try {
346             LookupResultsService lookupResultsService = SpringContext.getBean(LookupResultsService.class);
347             lookupResultsService.persistResultsTable(lookupResultsSequenceNumber, resultTable, GlobalVariables.getUserSession().getPerson().getPrincipalId());
348         }
349         catch (Exception e) {
350             LOG.error("error occured trying to persist multiple lookup results", e);
351             throw new RuntimeException("error occured trying to persist multiple lookup results");
352         }
353 
354         // since new search, nothing's checked
355         multipleValueLookupForm.setCompositeObjectIdMap(new HashMap<String, String>());
356 
357         return displayList;
358     }
359 
360     /**
361      * @see org.kuali.rice.kns.web.struts.action.KualiMultipleValueLookupAction#selectAll(org.kuali.rice.kns.web.struts.form.MultipleValueLookupForm,
362      *      int)
363      *
364      * KRAD Conversion: Lookupable performs customization of the results.
365      *
366      * Fields are in data dictionary for bo Balance.
367      */
368     @Override
369     protected List<ResultRow> selectAll(MultipleValueLookupForm multipleValueLookupForm, int maxRowsPerPage) {
370         List<ResultRow> resultTable = null;
371         try {
372             LookupResultsService lookupResultsService = SpringContext.getBean(LookupResultsService.class);
373             String lookupResultsSequenceNumber = multipleValueLookupForm.getLookupResultsSequenceNumber();
374 
375             resultTable = lookupResultsService.retrieveResultsTable(lookupResultsSequenceNumber, GlobalVariables.getUserSession().getPerson().getPrincipalId());
376         }
377         catch (Exception e) {
378             LOG.error("error occured trying to export multiple lookup results", e);
379             throw new RuntimeException("error occured trying to export multiple lookup results");
380         }
381 
382         Map<String, String> selectedObjectIds = this.getSelectedObjectIds(multipleValueLookupForm, resultTable);
383 
384         multipleValueLookupForm.jumpToPage(multipleValueLookupForm.getViewedPageNumber(), resultTable.size(), maxRowsPerPage);
385         multipleValueLookupForm.setColumnToSortIndex(Integer.parseInt(multipleValueLookupForm.getPreviouslySortedColumnIndex()));
386         multipleValueLookupForm.setCompositeObjectIdMap(selectedObjectIds);
387 
388         return resultTable;
389     }
390 
391     /**
392      * put all enties into select object map. This implmentation only deals with the money amount objects.
393      *
394      * @param multipleValueLookupForm the given struts form
395      * @param resultTable the given result table that holds all data being presented
396      * @return the map containing all entries available for selection
397      *
398      * KRAD Conversion: Performs customization of the results. Prepares
399      *
400      * There is no use of data dictionary for fields.
401      */
402     private Map<String, String> getSelectedObjectIds(MultipleValueLookupForm multipleValueLookupForm, List<ResultRow> resultTable) {
403         String businessObjectClassName = multipleValueLookupForm.getBusinessObjectClassName();
404         // SegmentedBusinessObject segmentedBusinessObject;
405         // try {
406         // segmentedBusinessObject = (SegmentedBusinessObject)
407         // Class.forName(multipleValueLookupForm.getBusinessObjectClassName()).newInstance();
408         // }
409         // catch (Exception e) {
410         throw new RuntimeException("Fail to create an object of " + businessObjectClassName);// + e);
411         // }
412 
413         // Map<String, String> selectedObjectIds = new HashMap<String, String>();
414         // Collection<String> segmentedPropertyNames = segmentedBusinessObject.getSegmentedPropertyNames();
415         // for (ResultRow row : resultTable) {
416         // for (Column column : row.getColumns()) {
417         // String propertyName = column.getPropertyName();
418         // if (segmentedPropertyNames.contains(propertyName)) {
419         // String propertyValue = StringUtils.replace(column.getPropertyValue(), ",", "");
420         // KualiDecimal amount = new KualiDecimal(propertyValue);
421         //
422         // if (amount.isNonZero()) {
423         // String objectId = row.getObjectId() + "." + propertyName + "." + KRADUtils.convertDecimalIntoInteger(amount);
424         // selectedObjectIds.put(objectId, objectId);
425         // }
426         // }
427         // }
428         // }
429         //
430         // return selectedObjectIds;
431     }
432 }
433