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.ar.batch.service.impl;
017    
018    import java.sql.Date;
019    import java.sql.Timestamp;
020    import java.util.ArrayList;
021    import java.util.Calendar;
022    import java.util.Iterator;
023    import java.util.List;
024    
025    import org.apache.log4j.Logger;
026    import org.kuali.kfs.module.ar.batch.service.InvoiceRecurrenceService;
027    import org.kuali.kfs.module.ar.businessobject.InvoiceRecurrence;
028    import org.kuali.kfs.module.ar.dataaccess.InvoiceRecurrenceDao;
029    import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument;
030    import org.kuali.rice.kew.exception.WorkflowException;
031    import org.kuali.rice.kew.util.KEWConstants;
032    import org.kuali.rice.kns.UserSession;
033    import org.kuali.rice.kns.bo.AdHocRoutePerson;
034    import org.kuali.rice.kns.bo.AdHocRouteRecipient;
035    import org.kuali.rice.kns.bo.AdHocRouteWorkgroup;
036    import org.kuali.rice.kns.document.MaintenanceDocument;
037    import org.kuali.rice.kns.service.BusinessObjectService;
038    import org.kuali.rice.kns.service.DateTimeService;
039    import org.kuali.rice.kns.service.DocumentService;
040    import org.kuali.rice.kns.util.DateUtils;
041    import org.kuali.rice.kns.util.GlobalVariables;
042    import org.kuali.rice.kns.util.KNSConstants;
043    import org.kuali.rice.kns.util.ObjectUtils;
044    import org.springframework.transaction.annotation.Transactional;
045    
046    /**
047     *  
048     * Lockbox Iterators are sorted by processedInvoiceDate and batchSequenceNumber. 
049     * Potentially there could be many batches on the same date. 
050     * For each set of records with the same processedInvoiceDate and batchSequenceNumber, 
051     * there will be one Cash-Control document. Each record within this set will create one Application document.
052     * 
053     */
054    
055    @Transactional
056    public class InvoiceRecurrenceServiceImpl implements InvoiceRecurrenceService {
057    
058        public InvoiceRecurrenceDao invoiceRecurrenceDao;
059        private static Logger LOG = org.apache.log4j.Logger.getLogger(InvoiceRecurrenceServiceImpl.class);
060        private DocumentService documentService;
061        private DateTimeService dateTimeService;
062        private BusinessObjectService boService;
063        public DateTimeService getDateTimeService() {
064            return dateTimeService;
065        }
066    
067        public void setDateTimeService(DateTimeService dateTimeService) {
068            this.dateTimeService = dateTimeService;
069        }
070    
071        public DocumentService getDocumentService() {
072            return documentService;
073        }
074    
075        public void setDocumentService(DocumentService documentService) {
076            this.documentService = documentService;
077        }
078    
079        public boolean processInvoiceRecurrence() throws WorkflowException {
080            
081            Iterator<InvoiceRecurrence> itr = invoiceRecurrenceDao.getAllActiveInvoiceRecurrences();
082            CustomerInvoiceDocument customerInvoiceDocument = new CustomerInvoiceDocument();
083            while (itr.hasNext()) {
084                InvoiceRecurrence invoiceRecurrence = (InvoiceRecurrence)itr.next();
085                
086                /* Get some dates and calendars  */
087                Date currentDate = getDateTimeService().getCurrentSqlDate();
088                Calendar currentCalendar = Calendar.getInstance();
089                currentCalendar.setTime(getDateTimeService().getCurrentTimestamp());
090    
091                Date currentMonthProcessDate;
092                Calendar currentMonthProcessCalendar = Calendar.getInstance();
093    
094                Date nextProcessDate;
095                Calendar nextProcessCalendar = Calendar.getInstance();
096                
097                Date lastProcessDate;
098                Calendar lastProcessCalendar = Calendar.getInstance();
099    
100                Date beginDate = invoiceRecurrence.getDocumentRecurrenceBeginDate();
101                Calendar beginCalendar = Calendar.getInstance();
102                beginCalendar.setTime(new Timestamp(invoiceRecurrence.getDocumentRecurrenceBeginDate().getTime()));
103    
104                Date endDate = invoiceRecurrence.getDocumentRecurrenceEndDate();
105                Date lastCreateDate = invoiceRecurrence.getDocumentLastCreateDate();
106                String intervalCode = invoiceRecurrence.getDocumentRecurrenceIntervalCode();
107                Integer totalRecurrenceNumber = invoiceRecurrence.getDocumentTotalRecurrenceNumber();
108    
109                
110                /* Calculate currentMonthProcessDate*/
111                currentMonthProcessCalendar = currentCalendar;
112                int day = beginCalendar.get(Calendar.DAY_OF_MONTH);
113                currentMonthProcessCalendar.set(Calendar.DAY_OF_MONTH, day);
114                currentMonthProcessDate = DateUtils.convertToSqlDate(currentMonthProcessCalendar.getTime());
115    
116                /* Calculate the nextProcessDate */
117                if (currentDate.after(currentMonthProcessDate)) {
118                    nextProcessCalendar = currentMonthProcessCalendar;
119                    nextProcessCalendar.add(Calendar.MONTH, 1);
120                } 
121                else {
122                    /* currentDate is less than or equal to currentMonthProcessDate
123                     * so the nextProcessDate is equal to the currentMonthProcessDate */
124                    nextProcessCalendar = currentMonthProcessCalendar;
125                }
126                nextProcessDate = DateUtils.convertToSqlDate(nextProcessCalendar.getTime());
127                
128                /* Calculate the lastProcessDate by subtracting one month from nextProcessingDate */
129                lastProcessCalendar = nextProcessCalendar;
130                lastProcessCalendar.add(Calendar.MONTH, -1);
131                lastProcessDate = DateUtils.convertToSqlDate(lastProcessCalendar.getTime());
132                if (lastProcessDate.before(beginDate)) {
133                    lastProcessCalendar.clear();
134                }
135                lastProcessDate = DateUtils.convertToSqlDate(lastProcessCalendar.getTime());
136                 /* if nextProcessDate is equal to currentDate create INV document */
137                if (nextProcessDate.equals(currentDate)) {
138                    /* copy INV document to a new INV document */
139                    String initiator = invoiceRecurrence.getDocumentInitiatorUserPersonUserIdentifier();
140                    GlobalVariables.setUserSession(new UserSession(initiator));
141    
142                    customerInvoiceDocument = (CustomerInvoiceDocument)getDocumentService().getByDocumentHeaderId(invoiceRecurrence.getInvoiceNumber());
143                    customerInvoiceDocument.toCopy();
144                    List<AdHocRouteRecipient> adHocRouteRecipients = new ArrayList<AdHocRouteRecipient>();
145                    adHocRouteRecipients.add(buildApprovePersonRecipient(initiator));
146                    //adHocRouteRecipients.add(buildApproveWorkgroupRecipient(workgroup));
147                    getDocumentService().routeDocument(customerInvoiceDocument, "This is a recurred Customer Invoice", adHocRouteRecipients);
148                    invoiceRecurrence.setDocumentLastCreateDate(currentDate);
149                    boService.save(invoiceRecurrence);
150                    
151                }
152    
153                /* if nextProcessDate is greater than currentDate BUT less than or equal to endDate */
154                if (nextProcessDate.after(currentDate) && (!nextProcessDate.after(endDate))) {
155                    if ((ObjectUtils.isNotNull(lastCreateDate) && lastProcessDate.after(lastCreateDate))  ||
156                        (ObjectUtils.isNull(lastCreateDate)  && beginDate.before(currentDate)) ) {
157                        /* copy INV document to a new INV document */
158                        String initiator = invoiceRecurrence.getDocumentInitiatorUserPersonUserIdentifier();
159                        GlobalVariables.setUserSession(new UserSession(initiator));
160    
161                        customerInvoiceDocument = (CustomerInvoiceDocument)getDocumentService().getByDocumentHeaderId(invoiceRecurrence.getInvoiceNumber());
162                        customerInvoiceDocument.toCopy();
163                        List<AdHocRouteRecipient> adHocRouteRecipients = new ArrayList<AdHocRouteRecipient>();
164                        adHocRouteRecipients.add(buildApprovePersonRecipient(initiator));
165                        //adHocRouteRecipients.add(buildApproveWorkgroupRecipient(workgroup));
166                        getDocumentService().routeDocument(customerInvoiceDocument, "This is a recurred Customer Invoice", adHocRouteRecipients);
167                        invoiceRecurrence.setDocumentLastCreateDate(currentDate);
168                        boService.save(invoiceRecurrence);
169                    }
170                }
171                
172                /* Check if this is the last recurrence. If yes, inactivate the INVR and send an FYI to the initiator and workgroup.  */
173                if (!nextProcessDate.before(endDate)) {
174                    /* Change the active indicator to 'N' and send an FYI */
175                    String initiator = invoiceRecurrence.getDocumentInitiatorUserPersonUserIdentifier();
176                    GlobalVariables.setUserSession(new UserSession(initiator));
177    
178                    MaintenanceDocument newMaintDoc = (MaintenanceDocument) getDocumentService().getNewDocument(getInvoiceRecurrenceMaintenanceDocumentTypeName());
179                    newMaintDoc.getOldMaintainableObject().setBusinessObject(invoiceRecurrence);
180                    InvoiceRecurrence newInvoiceRecurrence = invoiceRecurrence;
181                    newInvoiceRecurrence.setActive(false);
182                    newMaintDoc.getDocumentHeader().setDocumentDescription("Generated by Batch process");
183                    newMaintDoc.getDocumentHeader().setExplanation("Inactivated by the Batch process");
184                    newMaintDoc.getNewMaintainableObject().setBusinessObject(newInvoiceRecurrence);
185                    newMaintDoc.getNewMaintainableObject().setMaintenanceAction(KNSConstants.MAINTENANCE_EDIT_ACTION);
186                    List<AdHocRouteRecipient> adHocRouteRecipients = new ArrayList<AdHocRouteRecipient>();
187                    adHocRouteRecipients.add(buildFyiPersonRecipient(initiator));
188                    //adHocRouteRecipients.add(buildFyiWorkgroupRecipient(workgroup));
189                    getDocumentService().routeDocument(newMaintDoc, null, adHocRouteRecipients);
190                    newInvoiceRecurrence.setDocumentLastCreateDate(currentDate);
191                    boService.save(newInvoiceRecurrence);
192                }
193            }
194            return true;
195    
196        }
197        
198        protected String getInvoiceRecurrenceMaintenanceDocumentTypeName() {
199            return "INVR";
200        }
201    
202        /**
203         * 
204         * This method builds a FYI recipient.
205         * @param userId
206         * @return
207         */
208        protected AdHocRouteRecipient buildFyiPersonRecipient(String userId) {
209            AdHocRouteRecipient adHocRouteRecipient = new AdHocRoutePerson();
210            adHocRouteRecipient.setActionRequested(KEWConstants.ACTION_REQUEST_FYI_REQ);
211            adHocRouteRecipient.setId(userId);
212            return adHocRouteRecipient;
213        }
214        
215        /**
216         * 
217         * This method builds a recipient for Approval.
218         * @param userId
219         * @return
220         */
221        protected AdHocRouteRecipient buildApprovePersonRecipient(String userId) {
222            AdHocRouteRecipient adHocRouteRecipient = new AdHocRoutePerson();
223            adHocRouteRecipient.setActionRequested(KEWConstants.ACTION_REQUEST_APPROVE_REQ);
224            adHocRouteRecipient.setId(userId);
225            return adHocRouteRecipient;
226        }
227        
228        /**
229         * 
230         * This method builds a FYI workgroup recipient.
231         * @param userId
232         * @return
233         */
234        protected AdHocRouteRecipient buildFyiWorkgroupRecipient(String workgroupId) {
235            AdHocRouteRecipient adHocRouteRecipient = new AdHocRouteWorkgroup();
236            adHocRouteRecipient.setActionRequested(KEWConstants.ACTION_REQUEST_FYI_REQ);
237            adHocRouteRecipient.setId(workgroupId);
238            return adHocRouteRecipient;
239        }
240        
241        /**
242         * 
243         * This method builds a workgroup recipient for Approval.
244         * @param userId
245         * @return
246         */
247        protected AdHocRouteRecipient buildApproveWorkgroupRecipient(String workgroupId) {
248            AdHocRouteRecipient adHocRouteRecipient = new AdHocRouteWorkgroup();
249            adHocRouteRecipient.setActionRequested(KEWConstants.ACTION_REQUEST_APPROVE_REQ);
250            adHocRouteRecipient.setId(workgroupId);
251            return adHocRouteRecipient;
252        }
253        
254        public InvoiceRecurrenceDao getInvoiceRecurrenceDao() {
255            return invoiceRecurrenceDao;
256        }
257    
258        public void setInvoiceRecurrenceDao(InvoiceRecurrenceDao invoiceRecurrenceDao) {
259            this.invoiceRecurrenceDao = invoiceRecurrenceDao;
260        }
261        
262        public void setBusinessObjectService (BusinessObjectService boService)
263        {
264            this.boService = boService;
265        }
266    }