001/*
002 * Copyright 2006 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 */
016package org.kuali.ole.gl.web.struts;
017
018import java.io.IOException;
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.HashMap;
022import java.util.Iterator;
023import java.util.List;
024import java.util.Map;
025
026import javax.servlet.ServletException;
027import javax.servlet.http.HttpServletRequest;
028import javax.servlet.http.HttpServletResponse;
029
030import org.apache.commons.lang.StringUtils;
031import org.apache.struts.action.ActionForm;
032import org.apache.struts.action.ActionForward;
033import org.apache.struts.action.ActionMapping;
034import org.kuali.ole.coa.businessobject.Account;
035import org.kuali.ole.coa.businessobject.Chart;
036import org.kuali.ole.coa.businessobject.ObjectCode;
037import org.kuali.ole.gl.Constant;
038import org.kuali.ole.gl.ObjectHelper;
039import org.kuali.ole.gl.businessobject.AccountBalance;
040import org.kuali.ole.gl.businessobject.lookup.AccountBalanceByConsolidationLookupableHelperServiceImpl;
041import org.kuali.ole.sys.OLEConstants;
042import org.kuali.ole.sys.OLEKeyConstants;
043import org.kuali.ole.sys.OLEPropertyConstants;
044import org.kuali.ole.sys.context.SpringContext;
045import org.kuali.rice.core.api.config.property.ConfigurationService;
046import org.kuali.rice.kns.lookup.Lookupable;
047import org.kuali.rice.kns.service.DataDictionaryService;
048import org.kuali.rice.kns.web.struts.action.KualiAction;
049import org.kuali.rice.kns.web.struts.form.LookupForm;
050import org.kuali.rice.kns.web.ui.Field;
051import org.kuali.rice.kns.web.ui.ResultRow;
052import org.kuali.rice.kns.web.ui.Row;
053import org.kuali.rice.krad.lookup.CollectionIncomplete;
054import org.kuali.rice.krad.service.BusinessObjectService;
055import org.kuali.rice.krad.util.GlobalVariables;
056import org.kuali.rice.krad.util.KRADConstants;
057
058/**
059 * This class handles Actions for lookup flow
060 */
061
062public class BalanceInquiryAction extends KualiAction {
063    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BalanceInquiryAction.class);
064
065    private static final String TOTALS_TABLE_KEY = "totalsTable";
066
067    private ConfigurationService kualiConfigurationService;
068    protected DataDictionaryService dataDictionaryService;
069    private String[] totalTitles;
070
071    public BalanceInquiryAction() {
072        super();
073        kualiConfigurationService = SpringContext.getBean(ConfigurationService.class);
074        dataDictionaryService = SpringContext.getBean(DataDictionaryService.class);
075    }
076
077    /**
078     * Sets up total titles
079     */
080    private void setTotalTitles() {
081        totalTitles = new String[7];
082
083        totalTitles[0] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.INCOME);
084        totalTitles[1] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.INCOME_FROM_TRANSFERS);
085        totalTitles[2] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.INCOME_TOTAL);
086        totalTitles[3] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.EXPENSE);
087        totalTitles[4] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.EXPENSE_FROM_TRANSFERS);
088        totalTitles[5] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.EXPENSE_TOTAL);
089        totalTitles[6] = kualiConfigurationService.getPropertyValueAsString(OLEKeyConstants.AccountBalanceService.TOTAL);
090
091    }
092
093    /**
094     * Returns an array of total titles
095     * 
096     * @return array of total titles
097     */
098    private String[] getTotalTitles() {
099        if (null == totalTitles) {
100            setTotalTitles();
101        }
102
103        return totalTitles;
104    }
105
106    public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
107        return mapping.findForward(OLEConstants.MAPPING_BASIC);
108    }
109
110    /**
111     * Search - sets the values of the data entered on the form on the jsp into a map and then searches for the results.
112     * 
113     * @param mapping
114     * @param form
115     * @param request
116     * @param response
117     * @return
118     * @throws Exception
119     * 
120     * KRAD Conversion: Lookupable performs customization of the results if 
121     * account balance by consolidation. The result rows are added to a collection 
122     * based on field's actual size if truncated is > 7.
123     * 
124     * Fields are in data dictionary for bo Balance.
125     */
126    public boolean validateChartCode(String chartCode) {
127        Map searchMap = new HashMap();
128        searchMap.put(OLEConstants.CHART_CODE, chartCode);
129        Chart chart = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(Chart.class, searchMap);
130        if (chart != null) {
131            return true;
132        }
133        return false;
134    }
135
136    public boolean validateAccountNumber(String accountNumber) {
137        Map searchMap = new HashMap();
138        searchMap.put(OLEConstants.ACCOUNT_NUMBER, accountNumber);
139        Account account = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(Account.class, searchMap);
140        if (account != null) {
141            return true;
142        }
143        return false;
144    }
145
146    public boolean validateObjectCode(String objectCode) {
147        Map searchMap = new HashMap();
148        searchMap.put(OLEConstants.FINANCIAL_OBJECT_CODE_PROPERTY_NAME, objectCode);
149        ObjectCode code = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(ObjectCode.class, searchMap);
150        if (code != null) {
151            return true;
152        }
153        return false;
154    }
155
156    public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
157        BalanceInquiryForm lookupForm = (BalanceInquiryForm) form;
158
159        // check consolidation option and sub-account number
160        Map fieldValues = lookupForm.getFields();
161        String accountNumber = null;
162        String chartCode = null;
163        String objectCode = null;
164        if (fieldValues.get(OLEConstants.ACCOUNT_NUMBER) != null) {
165            accountNumber = fieldValues.get(OLEConstants.ACCOUNT_NUMBER).toString();
166        }
167        if (fieldValues.get(OLEConstants.CHART_CODE) != null) {
168            chartCode = fieldValues.get(OLEConstants.CHART_CODE).toString();
169        }
170        if (fieldValues.get(OLEConstants.OBJECT_CODE) != null) {
171            objectCode = fieldValues.get(OLEConstants.OBJECT_CODE).toString();
172        }
173        if (chartCode != null && !StringUtils.isEmpty(chartCode) && !validateChartCode(chartCode)) {
174            GlobalVariables.getMessageMap().putError(OLEConstants.DOCUMENT_ERRORS, OLEKeyConstants.ERROR_CUSTOM, new String[]{OLEConstants.CHART_CODE_NOT_FOUND});
175        }
176        if (accountNumber != null && !StringUtils.isEmpty(accountNumber) && !validateAccountNumber(accountNumber)) {
177            GlobalVariables.getMessageMap().putError(OLEConstants.DOCUMENT_ERRORS, OLEKeyConstants.ERROR_CUSTOM, new String[]{OLEConstants.ACC_NO_NOT_FOUND});
178        }
179        if (objectCode != null && !StringUtils.isEmpty(objectCode) && !validateObjectCode(objectCode)) {
180            GlobalVariables.getMessageMap().putError(OLEConstants.DOCUMENT_ERRORS, OLEKeyConstants.ERROR_CUSTOM, new String[]{OLEConstants.OBJ_CODE_NOT_FOUND});
181        }
182        String consolidationOption = (String) fieldValues.get(Constant.CONSOLIDATION_OPTION);
183        String subAccountNumber = (String) fieldValues.get(Constant.SUB_ACCOUNT_OPTION);
184        if (Constant.EXCLUDE_SUBACCOUNTS.equals(consolidationOption) && !subAccountNumber.equals("")){
185            GlobalVariables.getMessageMap().putError(OLEPropertyConstants.SUB_ACCOUNT_NUMBER, OLEKeyConstants.ERROR_BALANCE_CONSOLIDATION_EXCLUDE_SUBACCOUNT);
186        }
187        
188        Lookupable lookupable = lookupForm.getLookupable();
189
190        if (lookupable == null) {
191            LOG.error("Lookupable is null.");
192            throw new RuntimeException("Lookupable is null.");
193        }
194
195        Collection displayList = new ArrayList();
196        List<ResultRow> resultTable = new ArrayList<ResultRow>();
197
198        lookupable.validateSearchParameters(lookupForm.getFields());
199
200        try {
201            displayList = lookupable.performLookup(lookupForm, resultTable, true);
202
203            Object[] resultTableAsArray = resultTable.toArray();
204
205            CollectionIncomplete incompleteDisplayList = (CollectionIncomplete) displayList;
206            Long totalSize = ((CollectionIncomplete) displayList).getActualSizeIfTruncated();
207
208            request.setAttribute(OLEConstants.REQUEST_SEARCH_RESULTS_SIZE, totalSize);
209
210            // TODO: use inheritance instead of this if statement
211            if (lookupable.getLookupableHelperService() instanceof AccountBalanceByConsolidationLookupableHelperServiceImpl) {
212
213                Collection totalsTable = new ArrayList();
214
215                int listIndex = 0;
216                int arrayIndex = 0;
217                int listSize = incompleteDisplayList.size();
218
219                for (; listIndex < listSize;) {
220
221                    AccountBalance balance = (AccountBalance) incompleteDisplayList.get(listIndex);
222
223                    boolean ok = ObjectHelper.isOneOf(balance.getTitle(), getTotalTitles());
224                    if (ok) {
225
226                        if (totalSize > 7) {
227                            totalsTable.add(resultTableAsArray[arrayIndex]);
228                        }
229                        resultTable.remove(resultTableAsArray[arrayIndex]);
230
231                        incompleteDisplayList.remove(balance);
232                        // account for the removal of the balance which resizes the list
233                        listIndex--;
234                        listSize--;
235
236                    }
237
238                    listIndex++;
239                    arrayIndex++;
240
241                }
242
243                request.setAttribute(OLEConstants.REQUEST_SEARCH_RESULTS, resultTable);
244
245                request.setAttribute(TOTALS_TABLE_KEY, totalsTable);
246                GlobalVariables.getUserSession().addObject(TOTALS_TABLE_KEY, totalsTable);
247
248            }
249            else {
250
251                request.setAttribute(OLEConstants.REQUEST_SEARCH_RESULTS, resultTable);
252
253            }
254
255            if (request.getParameter(OLEConstants.SEARCH_LIST_REQUEST_KEY) != null) {
256                GlobalVariables.getUserSession().removeObject(request.getParameter(OLEConstants.SEARCH_LIST_REQUEST_KEY));
257            }
258
259            request.setAttribute(OLEConstants.SEARCH_LIST_REQUEST_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(resultTable));
260
261        }
262        catch (NumberFormatException e) {
263            GlobalVariables.getMessageMap().putError(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, OLEKeyConstants.ERROR_CUSTOM, new String[] { "Fiscal Year must be a four-digit number" });
264        }
265        catch (Exception e) {
266            GlobalVariables.getMessageMap().putError(OLEConstants.DOCUMENT_ERRORS, OLEKeyConstants.ERROR_CUSTOM, new String[] { "Please report the server error." });
267            LOG.error("Application Errors", e);
268        }
269        return mapping.findForward(OLEConstants.MAPPING_BASIC);
270    }
271
272    /**
273     * Refresh - is called when one quickFinder returns to the previous one. Sets all the values and performs the new search.
274     * 
275     * @see org.kuali.rice.kns.web.struts.action.KualiAction#refresh(org.apache.struts.action.ActionMapping,
276     *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
277     *      
278     * KRAD Conversion: Lookupable performs customization of the fields and check for additional fields.
279     *  
280     * Fields are in data dictionary for bo Balance.
281     */
282    @Override
283    public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
284        LookupForm lookupForm = (LookupForm) form;
285        Lookupable lookupable = lookupForm.getLookupable();
286        if (lookupable == null) {
287            LOG.error("Lookupable is null.");
288            throw new RuntimeException("Lookupable is null.");
289        }
290
291        Map fieldValues = new HashMap();
292        Map values = lookupForm.getFields();
293
294        for (Iterator iter = lookupable.getRows().iterator(); iter.hasNext();) {
295            Row row = (Row) iter.next();
296
297            for (Iterator iterator = row.getFields().iterator(); iterator.hasNext();) {
298                Field field = (Field) iterator.next();
299
300                if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
301                    if (request.getParameter(field.getPropertyName()) != null) {
302                        field.setPropertyValue(request.getParameter(field.getPropertyName()));
303                    }
304                    else if (values.get(field.getPropertyName()) != null) {
305                        field.setPropertyValue(values.get(field.getPropertyName()));
306                    }
307                }
308                fieldValues.put(field.getPropertyName(), field.getPropertyValue());
309            }
310        }
311        fieldValues.put(OLEConstants.DOC_FORM_KEY, lookupForm.getFormKey());
312        fieldValues.put(OLEConstants.BACK_LOCATION, lookupForm.getBackLocation());
313
314        if (lookupable.checkForAdditionalFields(fieldValues)) {
315            for (Iterator iter = lookupable.getRows().iterator(); iter.hasNext();) {
316                Row row = (Row) iter.next();
317                for (Iterator iterator = row.getFields().iterator(); iterator.hasNext();) {
318                    Field field = (Field) iterator.next();
319                    if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
320                        if (request.getParameter(field.getPropertyName()) != null) {
321                            field.setPropertyValue(request.getParameter(field.getPropertyName()));
322                            fieldValues.put(field.getPropertyName(), request.getParameter(field.getPropertyName()));
323                        }
324                        else if (values.get(field.getPropertyName()) != null) {
325                            field.setPropertyValue(values.get(field.getPropertyName()));
326                        }
327                    }
328                }
329            }
330        }
331
332        return mapping.findForward(OLEConstants.MAPPING_BASIC);
333    }
334
335    /**
336     * Returns as if return with no value was selected.
337     * 
338     * @param mapping
339     * @param form
340     * @param request
341     * @param response
342     * @return
343     * @throws Exception
344     */
345    public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
346        LookupForm lookupForm = (LookupForm) form;
347
348        String backUrl = lookupForm.getBackLocation() + "?methodToCall=refresh&docFormKey=" + lookupForm.getFormKey();
349        return new ActionForward(backUrl, true);
350    }
351
352
353    /**
354     * Clears the values of all the fields on the jsp.
355     * 
356     * @param mapping
357     * @param form
358     * @param request
359     * @param response
360     * @return
361     * @throws IOException
362     * @throws ServletException
363     * 
364     * KRAD Conversion: Lookupable performs setting/clearing of the field values. 
365     * 
366     * Fields are in data dictionary for bo Balance.
367     */
368    public ActionForward clearValues(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
369        LookupForm lookupForm = (LookupForm) form;
370        Lookupable lookupable = lookupForm.getLookupable();
371        if (lookupable == null) {
372            LOG.error("Lookupable is null.");
373            throw new RuntimeException("Lookupable is null.");
374        }
375
376        for (Iterator iter = lookupable.getRows().iterator(); iter.hasNext();) {
377            Row row = (Row) iter.next();
378            for (Iterator iterator = row.getFields().iterator(); iterator.hasNext();) {
379                Field field = (Field) iterator.next();
380                if (!field.getFieldType().equals(Field.RADIO)) {
381                    field.setPropertyValue(field.getDefaultValue());
382                }
383            }
384        }
385
386        return mapping.findForward(OLEConstants.MAPPING_BASIC);
387    }
388
389    /**
390     * View results from balance inquiry action
391     * 
392     * @param mapping
393     * @param form
394     * @param request
395     * @param response
396     * @return
397     * @throws Exception
398     */
399    public ActionForward viewResults(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
400        request.setAttribute(OLEConstants.SEARCH_LIST_REQUEST_KEY, request.getParameter(OLEConstants.SEARCH_LIST_REQUEST_KEY));
401        request.setAttribute(OLEConstants.REQUEST_SEARCH_RESULTS, GlobalVariables.getUserSession().retrieveObject(request.getParameter(OLEConstants.SEARCH_LIST_REQUEST_KEY)));
402        request.setAttribute(OLEConstants.REQUEST_SEARCH_RESULTS_SIZE, request.getParameter(OLEConstants.REQUEST_SEARCH_RESULTS_SIZE));
403
404        // TODO: use inheritance instead of this if statement
405        if (((BalanceInquiryForm) form).getLookupable().getLookupableHelperService() instanceof AccountBalanceByConsolidationLookupableHelperServiceImpl) {
406            Object totalsTable = GlobalVariables.getUserSession().retrieveObject(TOTALS_TABLE_KEY);
407            request.setAttribute(TOTALS_TABLE_KEY, totalsTable);
408        }
409
410        return mapping.findForward(OLEConstants.MAPPING_BASIC);
411    }
412
413    public void setConfigurationService(ConfigurationService kcs) {
414        kualiConfigurationService = kcs;
415    }
416
417    @Override
418    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
419        request.setAttribute(KRADConstants.PARAM_MAINTENANCE_VIEW_MODE, KRADConstants.PARAM_MAINTENANCE_VIEW_MODE_LOOKUP);
420        org.kuali.rice.kns.datadictionary.BusinessObjectEntry boe = (org.kuali.rice.kns.datadictionary.BusinessObjectEntry) dataDictionaryService.getDataDictionary().getBusinessObjectEntry(((LookupForm) form).getBusinessObjectClassName());
421        int numCols = boe.getLookupDefinition().getNumOfColumns();
422        if (numCols <= 0) {
423            numCols = KRADConstants.DEFAULT_NUM_OF_COLUMNS; // by default, always show one column.
424        }
425        ((LookupForm) form).setNumColumns(numCols);
426        return super.execute(mapping, form, request, response);
427    }
428}