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.endow.web.struts;
017    
018    import java.io.ByteArrayOutputStream;
019    import java.io.IOException;
020    import java.util.ArrayList;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Map;
025    import java.util.zip.ZipEntry;
026    import java.util.zip.ZipOutputStream;
027    
028    import javax.servlet.http.HttpServletRequest;
029    import javax.servlet.http.HttpServletResponse;
030    
031    import org.apache.commons.lang.StringUtils;
032    import org.apache.struts.action.ActionForm;
033    import org.apache.struts.action.ActionForward;
034    import org.apache.struts.action.ActionMapping;
035    import org.kuali.kfs.module.endow.EndowConstants;
036    import org.kuali.kfs.module.endow.report.service.AssetStatementReportService;
037    import org.kuali.kfs.module.endow.report.util.AssetStatementReportDataHolder;
038    import org.kuali.kfs.module.endow.report.util.AssetStatementReportPrint;
039    import org.kuali.kfs.module.endow.report.util.EndowmentReportHeaderDataHolder;
040    import org.kuali.kfs.sys.KFSConstants;
041    import org.kuali.kfs.sys.context.SpringContext;
042    import org.kuali.rice.kns.util.WebUtils;
043    
044    public class AssetStatementAction extends EndowmentReportBaseAction {
045    
046        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AssetStatementAction.class);
047        
048        private final String ENDOWMENT_REPORT_NAME = "Endowment Asset Statement";
049        private final String NON_ENDOWED_REPORT_NAME = "Non-Endowed Asset Statement";
050        private final String REPORT_FILE_NAME = "AssetStatementReport.pdf";
051        
052        private final String RESPONSE_CONTENT_TYPE = "application/pdf";
053        private final String ZIP_FILENAME = "AssetStatementReport.zip";
054            
055        private final String ENDOWMENT_DETAIL_FILENAME = "AssetStatementReport_EndowmentDetail.pdf";
056        private final String ENDOWMENT_TOTAL_FILENAME = "AssetStatementReport_EndowmentTotal.pdf";
057        private final String NON_ENDOWED_DETAIL_FILENAME = "AssetStatementReport_NonEndowedDetail.pdf";
058        private final String NON_ENDOWED_TOTAL_FILENAME = "AssetStatementReport_NonEndowedTotal.pdf";
059        
060        public AssetStatementAction() {
061            super();
062        }
063    
064        /**
065         * Directs to the start page
066         * 
067         * @param mapping
068         * @param form
069         * @param request
070         * @param response
071         * @return
072         * @throws Exception
073         */
074        public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
075            return mapping.findForward(KFSConstants.MAPPING_BASIC);
076        }
077    
078        /**
079         * Clears the form when the "clear" button is pressed
080         * 
081         * @param mapping
082         * @param form
083         * @param request
084         * @param response
085         * @return
086         * @throws Exception
087         */
088        public ActionForward clear(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
089            AssetStatementForm transactionStatementForm = (AssetStatementForm) form;
090            transactionStatementForm.clear();
091            return mapping.findForward(KFSConstants.MAPPING_BASIC);
092        }
093    
094        /**
095         * Cancels the current page and goes to the start page
096         * 
097         * @param mapping
098         * @param form
099         * @param request
100         * @param response
101         * @return
102         * @throws Exception
103         */
104        public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
105            return mapping.findForward(KFSConstants.MAPPING_BASIC);
106        }
107    
108        /**
109         * Generates Transaction Statement in the PDF form
110         * 
111         * @param mapping
112         * @param form
113         * @param request
114         * @param response
115         * @return
116         * @throws Exception
117         */
118        public ActionForward print(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
119            
120            // get all the value strings from the form
121            AssetStatementForm assetStatementForm = (AssetStatementForm) form;
122            String kemids = assetStatementForm.getKemid();
123            String benefittingOrganziationCampuses = assetStatementForm.getBenefittingOrganziationCampus();
124            String benefittingOrganziationCharts = assetStatementForm.getBenefittingOrganziationChart();
125            String benefittingOrganziations = assetStatementForm.getBenefittingOrganziation();
126            String typeCodes = assetStatementForm.getTypeCode();
127            String purposeCodes = assetStatementForm.getPurposeCode();
128            String combineGroupCodes = assetStatementForm.getCombineGroupCode();
129            String monthEndDate = assetStatementForm.getMonthEndDate();
130            String endowmentOption = assetStatementForm.getEndowmentOption();
131            String reportOption = assetStatementForm.getReportOption();
132            String listKemidsInHeader = assetStatementForm.getListKemidsInHeader();
133            String closedIndicator = assetStatementForm.getClosedIndicator();
134            String printFileOption =  assetStatementForm.getPrintFileOption();   
135            String message = assetStatementForm.getMessage();
136    
137            List<AssetStatementReportDataHolder> endowmentAssetStatementReportDataHolders = null;
138            List<AssetStatementReportDataHolder> nonEndowedAssetStatementReportDataHolders = null;
139            
140            /*
141             * Creates the report data based on the selected criteria.
142             * The criteria are selected as follows.
143             * 1. Kemid and the other criteria cannot be selected at the same time.
144             * 2. If none of them are selected, all kemids will be selected.
145             * 3. The other criteria other than kemid are "AND" combined.
146             * 4. All the criteria in the text input can be multiple by the use of wild card or the separator ('&' for kemid, ',' for the others) 
147             */
148    
149            AssetStatementReportService assetStatementReportService = SpringContext.getBean(AssetStatementReportService.class);
150            
151            if (StringUtils.isNotBlank(kemids)) {
152                
153                if (( StringUtils.isNotBlank(benefittingOrganziationCampuses) 
154                    || StringUtils.isNotBlank(benefittingOrganziationCharts)
155                    || StringUtils.isNotBlank(benefittingOrganziations)
156                    || StringUtils.isNotBlank(typeCodes)
157                    || StringUtils.isNotBlank(purposeCodes) 
158                    || StringUtils.isNotBlank(combineGroupCodes) )) {
159                
160                    // kemid and the other criteria cannot be selected at the same time 
161                    assetStatementForm.setMessage(ERROR_REPORT_KEMID_WITH_OTHER_CRITERIA);
162                    return mapping.findForward(KFSConstants.MAPPING_BASIC);
163                    
164                } else {
165                    // by kemid only
166                    List<String> kemidList = parseValueString(kemids, KEMID_SEPERATOR);                
167                    if (KFSConstants.ParameterValues.YES.equalsIgnoreCase(endowmentOption)) {
168                        endowmentAssetStatementReportDataHolders = assetStatementReportService.getAssetStatementReportsByKemidByIds(kemidList, monthEndDate, endowmentOption, reportOption, closedIndicator);
169                    } 
170                    else if (KFSConstants.ParameterValues.NO.equalsIgnoreCase(endowmentOption)) {
171                        nonEndowedAssetStatementReportDataHolders = assetStatementReportService.getAssetStatementReportsByKemidByIds(kemidList, monthEndDate, endowmentOption, reportOption, closedIndicator);
172                    } 
173                    else {
174                        endowmentAssetStatementReportDataHolders = assetStatementReportService.getAssetStatementReportsByKemidByIds(kemidList, monthEndDate, KFSConstants.ParameterValues.YES, reportOption, closedIndicator);
175                        nonEndowedAssetStatementReportDataHolders = assetStatementReportService.getAssetStatementReportsByKemidByIds(kemidList, monthEndDate, KFSConstants.ParameterValues.NO, reportOption, closedIndicator);
176                    }
177                }
178            } 
179            else {
180                if (( StringUtils.isBlank(benefittingOrganziationCampuses) 
181                        && StringUtils.isBlank(benefittingOrganziationCharts)
182                        && StringUtils.isBlank(benefittingOrganziations)
183                        && StringUtils.isBlank(typeCodes)
184                        && StringUtils.isBlank(purposeCodes) 
185                        && StringUtils.isBlank(combineGroupCodes) )) {
186    
187                    // for all kemids
188                    if (KFSConstants.ParameterValues.YES.equalsIgnoreCase(endowmentOption)) {
189                        endowmentAssetStatementReportDataHolders =  assetStatementReportService.getAssetStatementReportForAllKemids(monthEndDate, endowmentOption, reportOption, closedIndicator);
190                    } else if (KFSConstants.ParameterValues.NO.equalsIgnoreCase(endowmentOption)) {
191                        nonEndowedAssetStatementReportDataHolders = assetStatementReportService.getAssetStatementReportForAllKemids(monthEndDate, endowmentOption, reportOption, closedIndicator);
192                    } else {
193                        endowmentAssetStatementReportDataHolders =  assetStatementReportService.getAssetStatementReportForAllKemids(monthEndDate, KFSConstants.ParameterValues.YES, reportOption, closedIndicator);
194                        nonEndowedAssetStatementReportDataHolders = assetStatementReportService.getAssetStatementReportForAllKemids(monthEndDate, KFSConstants.ParameterValues.NO, reportOption, closedIndicator);
195                    }
196                    
197                } 
198                else {
199                    // by other criteria
200                    if (EndowConstants.EndowmentReport.BOTH.equalsIgnoreCase(endowmentOption)) {
201                        endowmentAssetStatementReportDataHolders =  assetStatementReportService.getAssetStatementReportsByOtherCriteria(
202                                parseValueString(benefittingOrganziationCampuses, OTHER_CRITERIA_SEPERATOR), 
203                                parseValueString(benefittingOrganziationCharts, OTHER_CRITERIA_SEPERATOR), 
204                                parseValueString(benefittingOrganziations, OTHER_CRITERIA_SEPERATOR), 
205                                parseValueString(typeCodes, OTHER_CRITERIA_SEPERATOR), 
206                                parseValueString(purposeCodes, OTHER_CRITERIA_SEPERATOR), 
207                                parseValueString(combineGroupCodes, OTHER_CRITERIA_SEPERATOR), 
208                                monthEndDate,
209                                KFSConstants.ParameterValues.YES,
210                                reportOption,
211                                closedIndicator);
212                        
213                        nonEndowedAssetStatementReportDataHolders = assetStatementReportService.getAssetStatementReportsByOtherCriteria(
214                                parseValueString(benefittingOrganziationCampuses, OTHER_CRITERIA_SEPERATOR), 
215                                parseValueString(benefittingOrganziationCharts, OTHER_CRITERIA_SEPERATOR), 
216                                parseValueString(benefittingOrganziations, OTHER_CRITERIA_SEPERATOR), 
217                                parseValueString(typeCodes, OTHER_CRITERIA_SEPERATOR), 
218                                parseValueString(purposeCodes, OTHER_CRITERIA_SEPERATOR), 
219                                parseValueString(combineGroupCodes, OTHER_CRITERIA_SEPERATOR), 
220                                monthEndDate,
221                                KFSConstants.ParameterValues.NO,
222                                reportOption,
223                                closedIndicator);
224                    } 
225                    else if (KFSConstants.ParameterValues.YES.equalsIgnoreCase(endowmentOption)) {
226                        // either endowment or non-endowed
227                        endowmentAssetStatementReportDataHolders =  assetStatementReportService.getAssetStatementReportsByOtherCriteria(
228                                parseValueString(benefittingOrganziationCampuses, OTHER_CRITERIA_SEPERATOR), 
229                                parseValueString(benefittingOrganziationCharts, OTHER_CRITERIA_SEPERATOR), 
230                                parseValueString(benefittingOrganziations, OTHER_CRITERIA_SEPERATOR), 
231                                parseValueString(typeCodes, OTHER_CRITERIA_SEPERATOR), 
232                                parseValueString(purposeCodes, OTHER_CRITERIA_SEPERATOR), 
233                                parseValueString(combineGroupCodes, OTHER_CRITERIA_SEPERATOR), 
234                                monthEndDate,
235                                endowmentOption,
236                                reportOption, 
237                                closedIndicator);
238                    }
239                    else if (KFSConstants.ParameterValues.NO.equalsIgnoreCase(endowmentOption)) {
240                        // either endowment or non-endowed
241                        nonEndowedAssetStatementReportDataHolders =  assetStatementReportService.getAssetStatementReportsByOtherCriteria(
242                                parseValueString(benefittingOrganziationCampuses, OTHER_CRITERIA_SEPERATOR), 
243                                parseValueString(benefittingOrganziationCharts, OTHER_CRITERIA_SEPERATOR), 
244                                parseValueString(benefittingOrganziations, OTHER_CRITERIA_SEPERATOR), 
245                                parseValueString(typeCodes, OTHER_CRITERIA_SEPERATOR), 
246                                parseValueString(purposeCodes, OTHER_CRITERIA_SEPERATOR), 
247                                parseValueString(combineGroupCodes, OTHER_CRITERIA_SEPERATOR), 
248                                monthEndDate,
249                                endowmentOption,
250                                reportOption, 
251                                closedIndicator);
252                    }          
253                }
254            }
255                
256            // Check to see if there are something to print
257            if ((endowmentAssetStatementReportDataHolders != null && !endowmentAssetStatementReportDataHolders.isEmpty()) || 
258                 (nonEndowedAssetStatementReportDataHolders != null && !nonEndowedAssetStatementReportDataHolders.isEmpty())) {
259                EndowmentReportHeaderDataHolder reportHeaderDataHolderForEndowment = null;
260                EndowmentReportHeaderDataHolder reportHeaderDataHolderForNonEndowed = null;
261                
262                if (endowmentAssetStatementReportDataHolders != null && !endowmentAssetStatementReportDataHolders.isEmpty()) {
263        
264                    // prepare the header sheet data          
265                    reportHeaderDataHolderForEndowment = assetStatementReportService.createReportHeaderSheetData(
266                            getKemidsSelected(endowmentAssetStatementReportDataHolders),
267                            parseValueString(benefittingOrganziationCampuses, OTHER_CRITERIA_SEPERATOR),
268                            parseValueString(benefittingOrganziationCharts, OTHER_CRITERIA_SEPERATOR),
269                            parseValueString(benefittingOrganziations, OTHER_CRITERIA_SEPERATOR),
270                            parseValueString(typeCodes, OTHER_CRITERIA_SEPERATOR),
271                            parseValueString(purposeCodes, OTHER_CRITERIA_SEPERATOR),
272                            parseValueString(combineGroupCodes, OTHER_CRITERIA_SEPERATOR),
273                            ENDOWMENT_REPORT_NAME,
274                            endowmentOption,
275                            reportOption);
276                }
277                if (nonEndowedAssetStatementReportDataHolders != null && !nonEndowedAssetStatementReportDataHolders.isEmpty()) {
278        
279                    // prepare the header sheet data          
280                    reportHeaderDataHolderForNonEndowed = assetStatementReportService.createReportHeaderSheetData(
281                            getKemidsSelected(nonEndowedAssetStatementReportDataHolders),
282                            parseValueString(benefittingOrganziationCampuses, OTHER_CRITERIA_SEPERATOR),
283                            parseValueString(benefittingOrganziationCharts, OTHER_CRITERIA_SEPERATOR),
284                            parseValueString(benefittingOrganziations, OTHER_CRITERIA_SEPERATOR),
285                            parseValueString(typeCodes, OTHER_CRITERIA_SEPERATOR),
286                            parseValueString(purposeCodes, OTHER_CRITERIA_SEPERATOR),
287                            parseValueString(combineGroupCodes, OTHER_CRITERIA_SEPERATOR),
288                            NON_ENDOWED_REPORT_NAME,
289                            endowmentOption,
290                            reportOption);
291                }
292                
293                // generate the report in PDF
294                AssetStatementReportPrint assetStatementReportPrint = new AssetStatementReportPrint();
295    
296                if (printFileOption.equalsIgnoreCase(KFSConstants.ParameterValues.YES)) {
297                    // consolidate all reports into one
298                    ByteArrayOutputStream pdfStream = assetStatementReportPrint.printAssetStatementReport(reportHeaderDataHolderForEndowment, reportHeaderDataHolderForNonEndowed, endowmentAssetStatementReportDataHolders, nonEndowedAssetStatementReportDataHolders, endowmentOption, reportOption, listKemidsInHeader);
299                    if (pdfStream != null) {
300                        WebUtils.saveMimeOutputStreamAsFile(response, RESPONSE_CONTENT_TYPE, pdfStream, REPORT_FILE_NAME);
301                    }
302                } 
303                else {
304                    // generate separate files
305                    Map<String, ByteArrayOutputStream> pdfStreamMap = new HashMap<String, ByteArrayOutputStream>();
306                    ByteArrayOutputStream pdfStream = null;
307                    
308                    if (endowmentAssetStatementReportDataHolders != null && !endowmentAssetStatementReportDataHolders.isEmpty()) {
309                        if (reportOption.equalsIgnoreCase(EndowConstants.EndowmentReport.DETAIL)) {                        
310                            pdfStream = assetStatementReportPrint.generateEndowmentDetailReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, listKemidsInHeader);
311                            if (pdfStream != null) {
312                                pdfStreamMap.put(ENDOWMENT_DETAIL_FILENAME, pdfStream);
313                            }
314                        } else if (reportOption.equalsIgnoreCase(EndowConstants.EndowmentReport.TOTAL)) {
315                            pdfStream = assetStatementReportPrint.generateEndowmentTotalReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, listKemidsInHeader);
316                            if (pdfStream != null) {
317                                pdfStreamMap.put(ENDOWMENT_TOTAL_FILENAME, pdfStream);
318                            }
319                        } else {
320                            pdfStream = assetStatementReportPrint.generateEndowmentDetailReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, listKemidsInHeader);
321                            if (pdfStream != null) {
322                                pdfStreamMap.put(ENDOWMENT_DETAIL_FILENAME, pdfStream);
323                            }
324                            pdfStream = assetStatementReportPrint.generateEndowmentTotalReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, listKemidsInHeader);
325                            if (pdfStream != null) {
326                                pdfStreamMap.put(ENDOWMENT_TOTAL_FILENAME, pdfStream);
327                            }
328                        }                    
329                    }
330                    if (nonEndowedAssetStatementReportDataHolders != null && !nonEndowedAssetStatementReportDataHolders.isEmpty()) {
331                        if (reportOption.equalsIgnoreCase(EndowConstants.EndowmentReport.DETAIL)) {
332                            pdfStream = assetStatementReportPrint.generateNonEndowedDetailReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, listKemidsInHeader);
333                            if (pdfStream != null) {
334                                pdfStreamMap.put(NON_ENDOWED_DETAIL_FILENAME, pdfStream);
335                            }
336                        } else if (reportOption.equalsIgnoreCase(EndowConstants.EndowmentReport.TOTAL)) {
337                            pdfStream = assetStatementReportPrint.generateNonEndowedTotalReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, listKemidsInHeader);
338                            if (pdfStream != null) {
339                                pdfStreamMap.put(NON_ENDOWED_TOTAL_FILENAME, pdfStream);
340                            }
341                        } else {
342                            pdfStream = assetStatementReportPrint.generateNonEndowedDetailReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, listKemidsInHeader);
343                            if (pdfStream != null) {
344                                pdfStreamMap.put(NON_ENDOWED_DETAIL_FILENAME, pdfStream);
345                            }
346                            pdfStream = assetStatementReportPrint.generateNonEndowedTotalReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, listKemidsInHeader);
347                            if (pdfStream != null) {
348                                pdfStreamMap.put(NON_ENDOWED_TOTAL_FILENAME, pdfStream);
349                            }
350                        } 
351                    }
352                    
353                    // zip and send them 
354                    if (!pdfStreamMap.isEmpty()) {
355                        saveMimeZipOutputStreamAsFile(response, RESPONSE_CONTENT_TYPE, pdfStreamMap, ZIP_FILENAME);
356                    }
357                }
358                
359                return null;
360            }       
361            
362            // No report was generated
363            if (StringUtils.isBlank(kemids)) { 
364                assetStatementForm.setMessage("No data was found to generate report.");
365            } else {
366                assetStatementForm.setMessage("No data was found to generate report for " + kemids + ".");
367            }
368            
369            return mapping.findForward(KFSConstants.MAPPING_BASIC);        
370        }
371        
372        /**
373         * Zip and output files that are not of type text/plain or text/html.
374         * 
375         * @param response
376         * @param contentType
377         * @param byteArrayOutputStreams
378         * @param fileNames
379         * @param zipFileName
380         * @throws IOException
381         */
382        public static void saveMimeZipOutputStreamAsFile(HttpServletResponse response, String contentType, Map<String, ByteArrayOutputStream> outputStreamMap, String zipFileName) throws IOException {
383        
384            response.setContentType(contentType);
385            response.setHeader("Content-disposition", "attachment; filename=" + zipFileName);
386            response.setHeader("Expires", "0");
387            response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
388            response.setHeader("Pragma", "public");
389        
390            ZipOutputStream zout = new ZipOutputStream(response.getOutputStream());
391            int totalSize = 0;
392            Iterator<String> fileNames = outputStreamMap.keySet().iterator();
393            while (fileNames.hasNext()) {
394                String fileName = fileNames.next();
395                ByteArrayOutputStream pdfStream = outputStreamMap.get(fileName);
396                totalSize += pdfStream.size();
397                zout.putNextEntry(new ZipEntry(fileName));
398                zout.write(pdfStream.toByteArray());
399                zout.closeEntry();
400            }
401            response.setContentLength(totalSize);
402            zout.flush();
403            zout.close();        
404        }
405        
406        /**
407         * Retrieves all the kemids used for the report 
408         * 
409         * @param transactionStatementReportDataHolder
410         * @return
411         */
412        protected List<String> getKemidsSelected(List<AssetStatementReportDataHolder> transactionStatementReportDataHolder) {
413            
414            List<String> kemids = new ArrayList<String>();
415            for (AssetStatementReportDataHolder dataHolder : transactionStatementReportDataHolder) {
416                kemids.add(dataHolder.getKemid());
417            }
418            
419            return kemids;        
420        }
421    }