View Javadoc
1   /*
2    * Copyright 2006 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  
17  package org.kuali.ole.gl.document;
18  
19  import java.text.DateFormat;
20  import java.text.SimpleDateFormat;
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.Collections;
24  import java.util.Date;
25  import java.util.Iterator;
26  import java.util.LinkedHashMap;
27  import java.util.List;
28  
29  import org.kuali.ole.gl.GeneralLedgerConstants;
30  import org.kuali.ole.gl.batch.CorrectionProcessScrubberStep;
31  import org.kuali.ole.gl.businessobject.CorrectionChangeGroup;
32  import org.kuali.ole.gl.document.service.CorrectionDocumentService;
33  import org.kuali.ole.gl.service.OriginEntryGroupService;
34  import org.kuali.ole.sys.OLEConstants;
35  import org.kuali.ole.sys.OLEPropertyConstants;
36  import org.kuali.ole.sys.batch.BatchSpringContext;
37  import org.kuali.ole.sys.batch.Step;
38  import org.kuali.ole.sys.context.ProxyUtils;
39  import org.kuali.ole.sys.context.SpringContext;
40  import org.kuali.ole.sys.document.AmountTotaling;
41  import org.kuali.ole.sys.document.FinancialSystemTransactionalDocumentBase;
42  import org.kuali.rice.core.api.datetime.DateTimeService;
43  import org.kuali.rice.core.api.util.type.KualiDecimal;
44  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
45  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
46  import org.kuali.rice.krad.util.ObjectUtils;
47  
48  /**
49   * The General Ledger Correction Document, a document that allows editing and processing of origin entry groups and the origin
50   * entries within them.
51   */
52  public class GeneralLedgerCorrectionProcessDocument extends FinancialSystemTransactionalDocumentBase implements AmountTotaling {
53      protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(GeneralLedgerCorrectionProcessDocument.class);
54  
55      protected String correctionTypeCode; // CorrectionDocumentService.CORRECTION_TYPE_MANUAL or
56      protected boolean correctionSelection; // false if all input rows should be in the output, true if only selected rows should be
57      // in the output
58      protected boolean correctionFileDelete; // false if the file should be processed by scrubber, true if the file should not be
59      // processed by scrubber
60      protected Integer correctionRowCount; // Row count in output group
61      protected KualiDecimal correctionDebitTotalAmount; // Debit amount total in output group
62      protected KualiDecimal correctionCreditTotalAmount; // Credit amount total in output group
63      protected KualiDecimal correctionBudgetTotalAmount; // Budget amount total in output group
64      protected String correctionInputFileName; // input file name
65      protected String correctionOutputFileName; // output file name
66      protected String correctionScriptText; // Not used
67      protected Integer correctionChangeGroupNextLineNumber;
68  
69      protected List<CorrectionChangeGroup> correctionChangeGroup;
70  
71         public GeneralLedgerCorrectionProcessDocument() {
72          super();
73          correctionChangeGroupNextLineNumber = new Integer(0);
74  
75          correctionChangeGroup = new ArrayList<CorrectionChangeGroup>();
76      }
77  
78      /**
79       * Returns a Map representation of the primary key of this document
80       * 
81       * @return a Map that represents the database key of this document
82       * @see org.kuali.rice.krad.bo.BusinessObjectBase#toStringMapper()
83       */
84      
85      protected LinkedHashMap toStringMapper_RICE20_REFACTORME() {
86          LinkedHashMap m = new LinkedHashMap();
87          m.put(OLEPropertyConstants.DOCUMENT_NUMBER, this.documentNumber);
88          return m;
89      }
90  
91      /**
92       * Returns the editing method to use on the origin entries in the document, either "Manual Edit," "Using Criteria," "Remove
93       * Group from Processing," or "Not Available"
94       * 
95       * @return the String representation of the method this document is using
96       */
97      public String getMethod() {
98          if (CorrectionDocumentService.CORRECTION_TYPE_MANUAL.equals(correctionTypeCode)) {
99              return "Manual Edit";
100         }
101         else if (CorrectionDocumentService.CORRECTION_TYPE_CRITERIA.equals(correctionTypeCode)) {
102             return "Using Criteria";
103         }
104         else if (CorrectionDocumentService.CORRECTION_TYPE_REMOVE_GROUP_FROM_PROCESSING.equals(correctionTypeCode)) {
105             return "Remove Group from Processing";
106         }
107         else {
108             return OLEConstants.NOT_AVAILABLE_STRING;
109         }
110     }
111 
112     /**
113      * Returns the source of the origin entries this document uses: either an uploaded file of origin entries or the database
114      * 
115      * @return a String with the name of the system in use
116      */
117     public String getSystem() {
118         if (correctionInputFileName != null) {
119             return "File Upload";
120         }
121         else {
122             return "Database";
123         }
124     }
125 
126     /**
127      * This method...
128      * 
129      * @param ccg
130      */
131     public void addCorrectionChangeGroup(CorrectionChangeGroup ccg) {
132         ccg.setDocumentNumber(documentNumber);
133         ccg.setCorrectionChangeGroupLineNumber(correctionChangeGroupNextLineNumber++);
134         correctionChangeGroup.add(ccg);
135     }
136 
137     /**
138      * This method...
139      * 
140      * @param changeNumber
141      */
142     public void removeCorrectionChangeGroup(int changeNumber) {
143         for (Iterator iter = correctionChangeGroup.iterator(); iter.hasNext();) {
144             CorrectionChangeGroup element = (CorrectionChangeGroup) iter.next();
145             if (changeNumber == element.getCorrectionChangeGroupLineNumber().intValue()) {
146                 iter.remove();
147             }
148         }
149     }
150 
151     /**
152      * This method...
153      * 
154      * @param groupNumber
155      * @return
156      */
157     public CorrectionChangeGroup getCorrectionChangeGroupItem(int groupNumber) {
158         for (Iterator iter = correctionChangeGroup.iterator(); iter.hasNext();) {
159             CorrectionChangeGroup element = (CorrectionChangeGroup) iter.next();
160             if (groupNumber == element.getCorrectionChangeGroupLineNumber().intValue()) {
161                 return element;
162             }
163         }
164 
165         CorrectionChangeGroup ccg = new CorrectionChangeGroup(documentNumber, groupNumber);
166         correctionChangeGroup.add(ccg);
167 
168         return ccg;
169     }
170     
171     
172     public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) {
173         super.doRouteStatusChange(statusChangeEvent);
174         if (getDocumentHeader().getWorkflowDocument().isProcessed()) {
175             if (LOG.isDebugEnabled()) {
176                 LOG.debug("GLCP Route status Change: " + statusChangeEvent);
177             }
178             CorrectionDocumentService correctionDocumentService = SpringContext.getBean(CorrectionDocumentService.class);
179             OriginEntryGroupService originEntryGroupService = SpringContext.getBean(OriginEntryGroupService.class);
180 
181             String docId = getDocumentHeader().getDocumentNumber();
182             GeneralLedgerCorrectionProcessDocument doc = correctionDocumentService.findByCorrectionDocumentHeaderId(docId);
183             
184             String correctionType = doc.getCorrectionTypeCode();
185             if (CorrectionDocumentService.CORRECTION_TYPE_REMOVE_GROUP_FROM_PROCESSING.equals(correctionType)) {
186 
187                 String dataFileName = doc.getCorrectionInputFileName();
188                 String doneFileName = dataFileName.replace(GeneralLedgerConstants.BatchFileSystem.EXTENSION, GeneralLedgerConstants.BatchFileSystem.DONE_FILE_EXTENSION);
189                 originEntryGroupService.deleteFile(doneFileName);
190 
191             }
192             else if (CorrectionDocumentService.CORRECTION_TYPE_MANUAL.equals(correctionType) 
193                     || CorrectionDocumentService.CORRECTION_TYPE_CRITERIA.equals(correctionType)) {
194                 // KFSMI-5760 - apparently, this node can be executed more than once, which results in multiple
195                 // files being created.  We need to check for the existence of a file with the proper
196                 // name pattern and abort the rest of this if found
197                 synchronized ( CorrectionDocumentService.class ) {
198                     if ( !checkForExistingOutputDocument( doc.getDocumentNumber() ) ) {
199                         // save the output file to originEntry directory when correctionFileDelete is false
200                         DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class);
201                         Date today = dateTimeService.getCurrentDate();
202     
203                         // generate output file and set file name
204                         String outputFileName = "";
205                         if (!correctionFileDelete) {
206                             outputFileName = correctionDocumentService.createOutputFileForProcessing(doc.getDocumentNumber(), today);
207                         }
208                         doc.setCorrectionOutputFileName(outputFileName);
209                         Step step = BatchSpringContext.getStep(CorrectionProcessScrubberStep.STEP_NAME);
210                         CorrectionProcessScrubberStep correctionStep = (CorrectionProcessScrubberStep) ProxyUtils.getTargetIfProxied(step);
211                         correctionStep.setDocumentId(docId);
212         
213                         try {
214                             step.execute(getClass().getName(), dateTimeService.getCurrentDate());
215                         }
216                         catch (Exception e) {
217                             LOG.error("GLCP scrubber encountered error:", e);
218                             throw new RuntimeException("GLCP scrubber encountered error:", e);
219                         }
220         
221                         correctionStep = (CorrectionProcessScrubberStep) ProxyUtils.getTargetIfProxied(step);
222                         correctionStep.setDocumentId(null);
223         
224                         correctionDocumentService.generateCorrectionReport(this);
225                         correctionDocumentService.aggregateCorrectionDocumentReports(this);
226                     } else {
227                         LOG.warn( "Attempt to re-process final GLCP operations for document: " + doc.getDocumentNumber() + "  File with that document number already exists." );
228                     }
229                 }
230             }
231             else {
232                 LOG.error("GLCP doc " + doc.getDocumentNumber() + " has an unknown correction type code: " + correctionType);
233             }
234         }
235     }
236 
237     /**
238      * Returns true if an existing document like "glcp_output.docNum" is found.
239      */
240     protected boolean checkForExistingOutputDocument( String documentNumber ) {
241         CorrectionDocumentService correctionDocumentService = SpringContext.getBean(CorrectionDocumentService.class);
242         String[] filenamesFound = correctionDocumentService.findExistingCorrectionOutputFilesForDocument(documentNumber);
243         if ( LOG.isInfoEnabled() ) {
244             LOG.info( "Scanned for output files for document: " + documentNumber );
245             LOG.info( "Files Found: " + Arrays.toString(filenamesFound));
246         }
247         return filenamesFound != null && filenamesFound.length > 0;
248     }
249     
250 
251     /**
252      * Waits for the event of the route level changing to "Approve" and at that point, saving all the entries as origin entries in a
253      * newly created origin entry group, then scrubbing those entries
254      * 
255      * @param cahnge a representation of the route level changed that just occurred
256      * @see org.kuali.rice.krad.document.DocumentBase#handleRouteLevelChange(org.kuali.rice.kew.clientapp.vo.DocumentRouteLevelChangeDTO)
257      */
258     @Override
259     public void doRouteLevelChange(DocumentRouteLevelChange change) {
260         super.doRouteLevelChange(change);
261     }
262 
263     /**
264      * Returns the total dollar amount associated with this document
265      * 
266      * @return if credit total is zero, debit total, otherwise credit total
267      */
268     public KualiDecimal getTotalDollarAmount() {
269         return getCorrectionCreditTotalAmount().add(getCorrectionDebitTotalAmount());
270     }
271 
272     /**
273      * Sets this document's document number, but also sets the document number on all children objects
274      * 
275      * @param documentNumber the document number for this document
276      * @see org.kuali.rice.krad.document.DocumentBase#setDocumentNumber(java.lang.String)
277      */
278     @Override
279     public void setDocumentNumber(String documentNumber) {
280         super.setDocumentNumber(documentNumber);
281 
282         for (Iterator iter = correctionChangeGroup.iterator(); iter.hasNext();) {
283             CorrectionChangeGroup element = (CorrectionChangeGroup) iter.next();
284             element.setDocumentNumber(documentNumber);
285         }
286     }
287 
288     public String getCorrectionTypeCode() {
289         return correctionTypeCode;
290     }
291 
292     public void setCorrectionTypeCode(String correctionTypeCode) {
293         this.correctionTypeCode = correctionTypeCode;
294     }
295 
296     public boolean getCorrectionSelection() {
297         return correctionSelection;
298     }
299 
300     public void setCorrectionSelection(boolean correctionSelection) {
301         this.correctionSelection = correctionSelection;
302     }
303 
304     public boolean getCorrectionFileDelete() {
305         return correctionFileDelete;
306     }
307 
308     public void setCorrectionFileDelete(boolean correctionFileDelete) {
309         this.correctionFileDelete = correctionFileDelete;
310     }
311 
312     public Integer getCorrectionRowCount() {
313         return correctionRowCount;
314     }
315 
316     public void setCorrectionRowCount(Integer correctionRowCount) {
317         this.correctionRowCount = correctionRowCount;
318     }
319 
320     public Integer getCorrectionChangeGroupNextLineNumber() {
321         return correctionChangeGroupNextLineNumber;
322     }
323 
324     public void setCorrectionChangeGroupNextLineNumber(Integer correctionChangeGroupNextLineNumber) {
325         this.correctionChangeGroupNextLineNumber = correctionChangeGroupNextLineNumber;
326     }
327 
328     public KualiDecimal getCorrectionDebitTotalAmount() {
329         if (ObjectUtils.isNull(correctionDebitTotalAmount)) {
330             return KualiDecimal.ZERO;
331         }
332         
333         return correctionDebitTotalAmount;
334     }
335 
336     public void setCorrectionDebitTotalAmount(KualiDecimal correctionDebitTotalAmount) {
337         this.correctionDebitTotalAmount = correctionDebitTotalAmount;
338     }
339 
340     public KualiDecimal getCorrectionCreditTotalAmount() {
341         if (ObjectUtils.isNull(correctionCreditTotalAmount)) {
342             return KualiDecimal.ZERO;
343         }
344         
345         return correctionCreditTotalAmount;
346     }
347 
348     public void setCorrectionCreditTotalAmount(KualiDecimal correctionCreditTotalAmount) {
349         this.correctionCreditTotalAmount = correctionCreditTotalAmount;
350     }
351 
352     public KualiDecimal getCorrectionBudgetTotalAmount() {
353         return correctionBudgetTotalAmount;
354     }
355 
356     public void setCorrectionBudgetTotalAmount(KualiDecimal correctionBudgetTotalAmount) {
357         this.correctionBudgetTotalAmount = correctionBudgetTotalAmount;
358     }
359 
360     public String getCorrectionInputFileName() {
361         return correctionInputFileName;
362     }
363 
364     public void setCorrectionInputFileName(String correctionInputFileName) {
365         this.correctionInputFileName = correctionInputFileName;
366     }
367 
368     public String getCorrectionOutputFileName() {
369         return correctionOutputFileName;
370     }
371 
372     public void setCorrectionOutputFileName(String correctionOutputFileName) {
373         this.correctionOutputFileName = correctionOutputFileName;
374     }
375 
376     public List<CorrectionChangeGroup> getCorrectionChangeGroup() {
377         Collections.sort(correctionChangeGroup);
378         return correctionChangeGroup;
379     }
380 
381     public void setCorrectionChangeGroup(List<CorrectionChangeGroup> correctionChangeGroup) {
382         this.correctionChangeGroup = correctionChangeGroup;
383     }
384 
385     protected String buildFileExtensionWithDate(Date date) {
386         String dateFormatStr = ".yyyy-MMM-dd.HH-mm-ss";
387         DateFormat dateFormat = new SimpleDateFormat(dateFormatStr);
388 
389         return dateFormat.format(date) + GeneralLedgerConstants.BatchFileSystem.EXTENSION;
390 
391 
392     }
393 }