/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.ar.batch.service.impl; import java.sql.Date; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.kuali.kfs.module.ar.batch.service.InvoiceRecurrenceService; import org.kuali.kfs.module.ar.businessobject.InvoiceRecurrence; import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.util.KfsDateUtils; import org.kuali.rice.core.api.datetime.DateTimeService; import org.kuali.rice.kew.api.KewApiConstants; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.kns.document.MaintenanceDocument; import org.kuali.rice.krad.UserSession; import org.kuali.rice.krad.bo.AdHocRoutePerson; import org.kuali.rice.krad.bo.AdHocRouteRecipient; import org.kuali.rice.krad.bo.AdHocRouteWorkgroup; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.service.DocumentService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.KRADConstants; import org.kuali.rice.krad.util.ObjectUtils; import org.springframework.transaction.annotation.Transactional; /** * * Lockbox Iterators are sorted by processedInvoiceDate and batchSequenceNumber. * Potentially there could be many batches on the same date. * For each set of records with the same processedInvoiceDate and batchSequenceNumber, * there will be one Cash-Control document. Each record within this set will create one Application document. * */ @Transactional public class InvoiceRecurrenceServiceImpl implements InvoiceRecurrenceService { private static Logger LOG = org.apache.log4j.Logger.getLogger(InvoiceRecurrenceServiceImpl.class); private DocumentService documentService; private DateTimeService dateTimeService; private BusinessObjectService boService; public DateTimeService getDateTimeService() { return dateTimeService; } public void setDateTimeService(DateTimeService dateTimeService) { this.dateTimeService = dateTimeService; } public DocumentService getDocumentService() { return documentService; } public void setDocumentService(DocumentService documentService) { this.documentService = documentService; } @Override public boolean processInvoiceRecurrence() throws WorkflowException { Collection<InvoiceRecurrence> recurrences = getAllActiveInvoiceRecurrences(); CustomerInvoiceDocument customerInvoiceDocument = new CustomerInvoiceDocument(); for (InvoiceRecurrence invoiceRecurrence : recurrences) { /* Get some dates and calendars */ Date currentDate = getDateTimeService().getCurrentSqlDate(); Calendar currentCalendar = Calendar.getInstance(); currentCalendar.setTime(getDateTimeService().getCurrentTimestamp()); Date currentMonthProcessDate; Calendar currentMonthProcessCalendar = Calendar.getInstance(); Date nextProcessDate; Calendar nextProcessCalendar = Calendar.getInstance(); Date lastProcessDate; Calendar lastProcessCalendar = Calendar.getInstance(); Date beginDate = invoiceRecurrence.getDocumentRecurrenceBeginDate(); Calendar beginCalendar = Calendar.getInstance(); beginCalendar.setTime(new Timestamp(invoiceRecurrence.getDocumentRecurrenceBeginDate().getTime())); Date endDate = invoiceRecurrence.getDocumentRecurrenceEndDate(); Date lastCreateDate = invoiceRecurrence.getDocumentLastCreateDate(); String intervalCode = invoiceRecurrence.getDocumentRecurrenceIntervalCode(); Integer totalRecurrenceNumber = invoiceRecurrence.getDocumentTotalRecurrenceNumber(); /* Calculate currentMonthProcessDate*/ currentMonthProcessCalendar = currentCalendar; int day = beginCalendar.get(Calendar.DAY_OF_MONTH); currentMonthProcessCalendar.set(Calendar.DAY_OF_MONTH, day); currentMonthProcessDate = KfsDateUtils.convertToSqlDate(currentMonthProcessCalendar.getTime()); /* Calculate the nextProcessDate */ if (currentDate.after(currentMonthProcessDate)) { nextProcessCalendar = currentMonthProcessCalendar; nextProcessCalendar.add(Calendar.MONTH, 1); } else { /* currentDate is less than or equal to currentMonthProcessDate * so the nextProcessDate is equal to the currentMonthProcessDate */ nextProcessCalendar = currentMonthProcessCalendar; } nextProcessDate = KfsDateUtils.convertToSqlDate(nextProcessCalendar.getTime()); /* Calculate the lastProcessDate by subtracting one month from nextProcessingDate */ lastProcessCalendar = nextProcessCalendar; lastProcessCalendar.add(Calendar.MONTH, -1); lastProcessDate = KfsDateUtils.convertToSqlDate(lastProcessCalendar.getTime()); if (lastProcessDate.before(beginDate)) { lastProcessCalendar.clear(); } lastProcessDate = KfsDateUtils.convertToSqlDate(lastProcessCalendar.getTime()); /* if nextProcessDate is equal to currentDate create INV document */ if (nextProcessDate.equals(currentDate)) { /* copy INV document to a new INV document */ String initiator = invoiceRecurrence.getDocumentInitiatorUserPersonUserIdentifier(); GlobalVariables.setUserSession(new UserSession(initiator)); customerInvoiceDocument = (CustomerInvoiceDocument)getDocumentService().getByDocumentHeaderId(invoiceRecurrence.getInvoiceNumber()); customerInvoiceDocument.toCopy(); List<AdHocRouteRecipient> adHocRouteRecipients = new ArrayList<AdHocRouteRecipient>(); adHocRouteRecipients.add(buildApprovePersonRecipient(initiator)); getDocumentService().routeDocument(customerInvoiceDocument, "This is a recurred Customer Invoice", adHocRouteRecipients); invoiceRecurrence.setDocumentLastCreateDate(currentDate); boService.save(invoiceRecurrence); } /* if nextProcessDate is greater than currentDate BUT less than or equal to endDate */ if (nextProcessDate.after(currentDate) && (!nextProcessDate.after(endDate))) { if ((ObjectUtils.isNotNull(lastCreateDate) && lastProcessDate.after(lastCreateDate)) || (ObjectUtils.isNull(lastCreateDate) && beginDate.before(currentDate)) ) { /* copy INV document to a new INV document */ String initiator = invoiceRecurrence.getDocumentInitiatorUserPersonUserIdentifier(); GlobalVariables.setUserSession(new UserSession(initiator)); customerInvoiceDocument = (CustomerInvoiceDocument)getDocumentService().getByDocumentHeaderId(invoiceRecurrence.getInvoiceNumber()); customerInvoiceDocument.toCopy(); List<AdHocRouteRecipient> adHocRouteRecipients = new ArrayList<AdHocRouteRecipient>(); adHocRouteRecipients.add(buildApprovePersonRecipient(initiator)); getDocumentService().routeDocument(customerInvoiceDocument, "This is a recurred Customer Invoice", adHocRouteRecipients); invoiceRecurrence.setDocumentLastCreateDate(currentDate); boService.save(invoiceRecurrence); } } /* Check if this is the last recurrence. If yes, inactivate the INVR and send an FYI to the initiator and workgroup. */ if (!nextProcessDate.before(endDate)) { /* Change the active indicator to 'N' and send an FYI */ String initiator = invoiceRecurrence.getDocumentInitiatorUserPersonUserIdentifier(); GlobalVariables.setUserSession(new UserSession(initiator)); MaintenanceDocument newMaintDoc = (MaintenanceDocument) getDocumentService().getNewDocument(getInvoiceRecurrenceMaintenanceDocumentTypeName()); newMaintDoc.getOldMaintainableObject().setBusinessObject(invoiceRecurrence); InvoiceRecurrence newInvoiceRecurrence = invoiceRecurrence; newInvoiceRecurrence.setActive(false); newMaintDoc.getDocumentHeader().setDocumentDescription("Generated by Batch process"); newMaintDoc.getDocumentHeader().setExplanation("Inactivated by the Batch process"); newMaintDoc.getNewMaintainableObject().setBusinessObject(newInvoiceRecurrence); newMaintDoc.getNewMaintainableObject().setMaintenanceAction(KRADConstants.MAINTENANCE_EDIT_ACTION); List<AdHocRouteRecipient> adHocRouteRecipients = new ArrayList<AdHocRouteRecipient>(); adHocRouteRecipients.add(buildFyiPersonRecipient(initiator)); getDocumentService().routeDocument(newMaintDoc, null, adHocRouteRecipients); newInvoiceRecurrence.setDocumentLastCreateDate(currentDate); boService.save(newInvoiceRecurrence); } } return true; } /** * @return returns all active invoice recurrences */ protected Collection<InvoiceRecurrence> getAllActiveInvoiceRecurrences() { Map<String, Object> fieldValues = new HashMap<String, Object>(); fieldValues.put(KFSPropertyConstants.ACTIVE, Boolean.TRUE); final Collection<InvoiceRecurrence> recurrences = boService.findMatchingOrderBy(InvoiceRecurrence.class, fieldValues, "invoiceNumber", true); return recurrences; } protected String getInvoiceRecurrenceMaintenanceDocumentTypeName() { return "INVR"; } /** * * This method builds a FYI recipient. * @param userId * @return */ protected AdHocRouteRecipient buildFyiPersonRecipient(String userId) { AdHocRouteRecipient adHocRouteRecipient = new AdHocRoutePerson(); adHocRouteRecipient.setActionRequested(KewApiConstants.ACTION_REQUEST_FYI_REQ); adHocRouteRecipient.setId(userId); return adHocRouteRecipient; } /** * * This method builds a recipient for Approval. * @param userId * @return */ protected AdHocRouteRecipient buildApprovePersonRecipient(String userId) { AdHocRouteRecipient adHocRouteRecipient = new AdHocRoutePerson(); adHocRouteRecipient.setActionRequested(KewApiConstants.ACTION_REQUEST_APPROVE_REQ); adHocRouteRecipient.setId(userId); return adHocRouteRecipient; } /** * * This method builds a FYI workgroup recipient. * @param userId * @return */ protected AdHocRouteRecipient buildFyiWorkgroupRecipient(String workgroupId) { AdHocRouteRecipient adHocRouteRecipient = new AdHocRouteWorkgroup(); adHocRouteRecipient.setActionRequested(KewApiConstants.ACTION_REQUEST_FYI_REQ); adHocRouteRecipient.setId(workgroupId); return adHocRouteRecipient; } /** * * This method builds a workgroup recipient for Approval. * @param userId * @return */ protected AdHocRouteRecipient buildApproveWorkgroupRecipient(String workgroupId) { AdHocRouteRecipient adHocRouteRecipient = new AdHocRouteWorkgroup(); adHocRouteRecipient.setActionRequested(KewApiConstants.ACTION_REQUEST_APPROVE_REQ); adHocRouteRecipient.setId(workgroupId); return adHocRouteRecipient; } public void setBusinessObjectService (BusinessObjectService boService) { this.boService = boService; } }