View Javadoc
1   /*
2    * The Kuali Financial System, a comprehensive financial management system for higher education.
3    *
4    * Copyright 2005-2014 The Kuali Foundation
5    *
6    * This program is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU Affero General Public License as
8    * published by the Free Software Foundation, either version 3 of the
9    * License, or (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU Affero General Public License for more details.
15   *
16   * You should have received a copy of the GNU Affero General Public License
17   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  package org.kuali.kfs.sys.document;
20  
21  import java.util.Map;
22  
23  import org.apache.commons.lang.StringUtils;
24  import org.apache.log4j.Logger;
25  import org.kuali.kfs.sys.KFSConstants;
26  import org.kuali.kfs.sys.businessobject.FinancialSystemDocumentHeader;
27  import org.kuali.kfs.sys.context.SpringContext;
28  import org.kuali.kfs.sys.document.dataaccess.FinancialSystemDocumentHeaderDao;
29  import org.kuali.rice.kew.api.WorkflowRuntimeException;
30  import org.kuali.rice.kew.api.document.DocumentStatus;
31  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
32  import org.kuali.rice.kim.api.identity.Person;
33  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
34  import org.kuali.rice.kns.document.MaintenanceDocumentBase;
35  import org.kuali.rice.krad.bo.DocumentHeader;
36  import org.kuali.rice.krad.util.ObjectUtils;
37  
38  /**
39   * This class is used by the system to use financial specific objects and data for maintenance documents
40   */
41  public class FinancialSystemMaintenanceDocument extends MaintenanceDocumentBase implements FinancialSystemDocument {
42      private static final Logger LOG = Logger.getLogger(FinancialSystemMaintenanceDocument.class);
43  
44      private transient Map<String,Boolean> canEditCache;
45  
46      /**
47       * Constructs a FinancialSystemMaintenanceDocument.java.
48       */
49      public FinancialSystemMaintenanceDocument() {
50          super();
51      }
52  
53      /**
54       * Constructs a FinancialSystemMaintenanceDocument.java.
55       * @param documentTypeName
56       */
57      public FinancialSystemMaintenanceDocument(String documentTypeName) {
58          super(documentTypeName);
59      }
60  
61      /**
62       * @see org.kuali.rice.krad.document.DocumentBase#setDocumentHeader(org.kuali.rice.krad.bo.DocumentHeader)
63       */
64      @Override
65      public void setDocumentHeader(DocumentHeader documentHeader) {
66          if ((documentHeader != null) && (!FinancialSystemDocumentHeader.class.isAssignableFrom(documentHeader.getClass()))) {
67              throw new IllegalArgumentException("document header of class '" + documentHeader.getClass() + "' is not assignable from financial document header class '" + FinancialSystemDocumentHeader.class + "'");
68          }
69          this.documentHeader = documentHeader;
70      }
71  
72      /**
73       * This is the default implementation which ensures that document note attachment references are loaded.
74       *
75       * @see org.kuali.rice.krad.document.Document#processAfterRetrieve()
76       */
77      @Override
78      public void processAfterRetrieve() {
79          // set correctedByDocumentId manually, since OJB doesn't maintain that relationship
80          try {
81              DocumentHeader correctingDocumentHeader = SpringContext.getBean(FinancialSystemDocumentHeaderDao.class).getCorrectingDocumentHeader(getDocumentHeader().getDocumentNumber());
82              if (ObjectUtils.isNotNull(correctingDocumentHeader) && !correctingDocumentHeader.getWorkflowDocument().isCanceled() && !correctingDocumentHeader.getWorkflowDocument().isDisapproved()) {
83                  getFinancialSystemDocumentHeader().setCorrectedByDocumentId(correctingDocumentHeader.getDocumentNumber());
84              }
85          } catch (RuntimeException e) {
86              LOG.error("Received WorkflowException trying to get route header id from workflow document", e);
87              throw new WorkflowRuntimeException(e);
88          }
89          // set the ad hoc route recipients too, since OJB doesn't maintain that relationship
90          // TODO - see KULNRVSYS-1054
91  
92          super.processAfterRetrieve();
93      }
94  
95      /**
96       * This is the default implementation which checks for a different workflow statuses, and updates the Kuali status accordingly.
97       *
98       * @see org.kuali.rice.krad.document.Document#doRouteStatusChange()
99       */
100     @Override
101     public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) {
102         getFinancialSystemDocumentHeader().setWorkflowDocumentStatusCode(statusChangeEvent.getNewRouteStatus());
103 
104         if (getDocumentHeader().getWorkflowDocument().isCanceled()) {
105             getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(KFSConstants.DocumentStatusCodes.CANCELLED);
106         }
107         else if (getDocumentHeader().getWorkflowDocument().isEnroute()) {
108             getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(KFSConstants.DocumentStatusCodes.ENROUTE);
109         }
110         if (getDocumentHeader().getWorkflowDocument().isDisapproved()) {
111             getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(KFSConstants.DocumentStatusCodes.DISAPPROVED);
112         }
113         if (getDocumentHeader().getWorkflowDocument().isProcessed()) {
114             getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(KFSConstants.DocumentStatusCodes.APPROVED);
115         }
116         if ( LOG.isInfoEnabled() ) {
117             LOG.info("Status is: " + getFinancialSystemDocumentHeader().getFinancialDocumentStatusCode());
118         }
119 
120         super.doRouteStatusChange(statusChangeEvent);
121     }
122 
123     @Override
124     public boolean answerSplitNodeQuestion(String nodeName) {
125         if (getNewMaintainableObject() == null) {
126             throw new UnsupportedOperationException("Cannot access Maintainable class to answer split node question");
127         }
128         if (getNewMaintainableObject() instanceof FinancialSystemMaintainable) {
129             return ((FinancialSystemMaintainable)getNewMaintainableObject()).answerSplitNodeQuestion(nodeName);
130         } else if (getNewMaintainableObject() instanceof FinancialSystemGlobalMaintainable) {
131             return ((FinancialSystemGlobalMaintainable)getNewMaintainableObject()).answerSplitNodeQuestion(nodeName);
132         } else {
133             throw new UnsupportedOperationException("Maintainable for "+getNewMaintainableObject().getBoClass().getName()+" does not extend org.kuali.kfs.sys.document.FinancialSystemMaintainable nor org.kuali.kfs.sys.document.FinancialSystemGlobalMaintainable and therefore cannot answer split node question");
134         }
135     }
136 
137     /**
138      * This method is used for routing and simply returns the initiator's Chart code.
139      * @return The Chart code of the document initiator
140      */
141     public String getInitiatorChartOfAccountsCode() {
142         String[] chartOrg = getInitiatorPrimaryDepartmentCode();
143         return chartOrg[0];
144     }
145 
146     /**
147      * This method is used for routing and simply returns the initiator's Organization code.
148      * @return The Organization code of the document initiator
149      */
150     public String getInitiatorOrganizationCode() {
151         String[] chartOrg = getInitiatorPrimaryDepartmentCode();
152         return chartOrg[1];
153     }
154 
155     /**
156      *
157      * This method is a utility method that returns a String array containing the document initiator's
158      * ChartCode in the first index and the OrganizationCode in the second.
159      * @return a String array.
160      */
161     protected String[] getInitiatorPrimaryDepartmentCode() {
162 
163         String netID = documentHeader.getWorkflowDocument().getInitiatorPrincipalId();
164         Person person =  KimApiServiceLocator.getPersonService().getPerson(netID);
165 
166         String deptCode = person.getPrimaryDepartmentCode();
167         String[] chartOrg = deptCode.split("-");
168         return chartOrg;
169 
170     }
171 
172     @Override
173     public FinancialSystemDocumentHeader getFinancialSystemDocumentHeader() {
174         return (FinancialSystemDocumentHeader)documentHeader;
175     }
176 
177 	@Override
178     public void prepareForSave() {
179         if (StringUtils.isBlank(getFinancialSystemDocumentHeader().getInitiatorPrincipalId())) {
180             getFinancialSystemDocumentHeader().setInitiatorPrincipalId(getFinancialSystemDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId());
181         }
182         if (StringUtils.isBlank(getFinancialSystemDocumentHeader().getWorkflowDocumentTypeName())) {
183             getFinancialSystemDocumentHeader().setWorkflowDocumentTypeName(getFinancialSystemDocumentHeader().getWorkflowDocument().getDocumentTypeName());
184         }
185         if (ObjectUtils.isNull(getFinancialSystemDocumentHeader().getWorkflowCreateDate())) {
186             getFinancialSystemDocumentHeader().setWorkflowCreateDate(new java.sql.Timestamp(getFinancialSystemDocumentHeader().getWorkflowDocument().getDateCreated().getMillis()));
187         }
188         // we're preparing to save here.  If the save fails, the transaction should roll back - so the fact that the doc header is in saved mode shouldn't
189         // cause problems.  And since org.kuali.rice.krad.service.impl.PostProcessorServiceImpl#doRouteStatusChange will NOT save the document when the
190         // DocStatus is saved, let's simply pre-anticipate that
191         final String statusCode = getFinancialSystemDocumentHeader().getWorkflowDocument().getStatus().equals(DocumentStatus.INITIATED) ? DocumentStatus.SAVED.getCode() : getFinancialSystemDocumentHeader().getWorkflowDocument().getStatus().getCode();
192         getFinancialSystemDocumentHeader().setWorkflowDocumentStatusCode(statusCode);
193         super.prepareForSave();
194     }
195 }
196