/* * 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.sys.document; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.businessobject.FinancialSystemDocumentHeader; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.document.dataaccess.FinancialSystemDocumentHeaderDao; import org.kuali.rice.kew.api.WorkflowRuntimeException; import org.kuali.rice.kew.api.document.DocumentStatus; import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange; import org.kuali.rice.kim.api.identity.Person; import org.kuali.rice.kim.api.services.KimApiServiceLocator; import org.kuali.rice.kns.document.MaintenanceDocumentBase; import org.kuali.rice.krad.bo.DocumentHeader; import org.kuali.rice.krad.util.ObjectUtils; /** * This class is used by the system to use financial specific objects and data for maintenance documents */ public class FinancialSystemMaintenanceDocument extends MaintenanceDocumentBase implements FinancialSystemDocument { private static final Logger LOG = Logger.getLogger(FinancialSystemMaintenanceDocument.class); private transient Map<String,Boolean> canEditCache; /** * Constructs a FinancialSystemMaintenanceDocument.java. */ public FinancialSystemMaintenanceDocument() { super(); } /** * Constructs a FinancialSystemMaintenanceDocument.java. * @param documentTypeName */ public FinancialSystemMaintenanceDocument(String documentTypeName) { super(documentTypeName); } /** * @see org.kuali.rice.krad.document.DocumentBase#setDocumentHeader(org.kuali.rice.krad.bo.DocumentHeader) */ @Override public void setDocumentHeader(DocumentHeader documentHeader) { if ((documentHeader != null) && (!FinancialSystemDocumentHeader.class.isAssignableFrom(documentHeader.getClass()))) { throw new IllegalArgumentException("document header of class '" + documentHeader.getClass() + "' is not assignable from financial document header class '" + FinancialSystemDocumentHeader.class + "'"); } this.documentHeader = documentHeader; } /** * This is the default implementation which ensures that document note attachment references are loaded. * * @see org.kuali.rice.krad.document.Document#processAfterRetrieve() */ @Override public void processAfterRetrieve() { // set correctedByDocumentId manually, since OJB doesn't maintain that relationship try { DocumentHeader correctingDocumentHeader = SpringContext.getBean(FinancialSystemDocumentHeaderDao.class).getCorrectingDocumentHeader(getDocumentHeader().getDocumentNumber()); if (ObjectUtils.isNotNull(correctingDocumentHeader) && !correctingDocumentHeader.getWorkflowDocument().isCanceled() && !correctingDocumentHeader.getWorkflowDocument().isDisapproved()) { getFinancialSystemDocumentHeader().setCorrectedByDocumentId(correctingDocumentHeader.getDocumentNumber()); } } catch (RuntimeException e) { LOG.error("Received WorkflowException trying to get route header id from workflow document", e); throw new WorkflowRuntimeException(e); } // set the ad hoc route recipients too, since OJB doesn't maintain that relationship // TODO - see KULNRVSYS-1054 super.processAfterRetrieve(); } /** * This is the default implementation which checks for a different workflow statuses, and updates the Kuali status accordingly. * * @see org.kuali.rice.krad.document.Document#doRouteStatusChange() */ @Override public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) { getFinancialSystemDocumentHeader().setWorkflowDocumentStatusCode(statusChangeEvent.getNewRouteStatus()); if (getDocumentHeader().getWorkflowDocument().isCanceled()) { getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(KFSConstants.DocumentStatusCodes.CANCELLED); } else if (getDocumentHeader().getWorkflowDocument().isEnroute()) { getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(KFSConstants.DocumentStatusCodes.ENROUTE); } if (getDocumentHeader().getWorkflowDocument().isDisapproved()) { getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(KFSConstants.DocumentStatusCodes.DISAPPROVED); } if (getDocumentHeader().getWorkflowDocument().isProcessed()) { getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(KFSConstants.DocumentStatusCodes.APPROVED); } if ( LOG.isInfoEnabled() ) { LOG.info("Status is: " + getFinancialSystemDocumentHeader().getFinancialDocumentStatusCode()); } super.doRouteStatusChange(statusChangeEvent); } @Override public boolean answerSplitNodeQuestion(String nodeName) { if (getNewMaintainableObject() == null) { throw new UnsupportedOperationException("Cannot access Maintainable class to answer split node question"); } if (getNewMaintainableObject() instanceof FinancialSystemMaintainable) { return ((FinancialSystemMaintainable)getNewMaintainableObject()).answerSplitNodeQuestion(nodeName); } else if (getNewMaintainableObject() instanceof FinancialSystemGlobalMaintainable) { return ((FinancialSystemGlobalMaintainable)getNewMaintainableObject()).answerSplitNodeQuestion(nodeName); } else { 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"); } } /** * This method is used for routing and simply returns the initiator's Chart code. * @return The Chart code of the document initiator */ public String getInitiatorChartOfAccountsCode() { String[] chartOrg = getInitiatorPrimaryDepartmentCode(); return chartOrg[0]; } /** * This method is used for routing and simply returns the initiator's Organization code. * @return The Organization code of the document initiator */ public String getInitiatorOrganizationCode() { String[] chartOrg = getInitiatorPrimaryDepartmentCode(); return chartOrg[1]; } /** * * This method is a utility method that returns a String array containing the document initiator's * ChartCode in the first index and the OrganizationCode in the second. * @return a String array. */ protected String[] getInitiatorPrimaryDepartmentCode() { String netID = documentHeader.getWorkflowDocument().getInitiatorPrincipalId(); Person person = KimApiServiceLocator.getPersonService().getPerson(netID); String deptCode = person.getPrimaryDepartmentCode(); String[] chartOrg = deptCode.split("-"); return chartOrg; } @Override public FinancialSystemDocumentHeader getFinancialSystemDocumentHeader() { return (FinancialSystemDocumentHeader)documentHeader; } @Override public void prepareForSave() { if (StringUtils.isBlank(getFinancialSystemDocumentHeader().getInitiatorPrincipalId())) { getFinancialSystemDocumentHeader().setInitiatorPrincipalId(getFinancialSystemDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId()); } if (StringUtils.isBlank(getFinancialSystemDocumentHeader().getWorkflowDocumentTypeName())) { getFinancialSystemDocumentHeader().setWorkflowDocumentTypeName(getFinancialSystemDocumentHeader().getWorkflowDocument().getDocumentTypeName()); } if (ObjectUtils.isNull(getFinancialSystemDocumentHeader().getWorkflowCreateDate())) { getFinancialSystemDocumentHeader().setWorkflowCreateDate(new java.sql.Timestamp(getFinancialSystemDocumentHeader().getWorkflowDocument().getDateCreated().getMillis())); } // 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 // cause problems. And since org.kuali.rice.krad.service.impl.PostProcessorServiceImpl#doRouteStatusChange will NOT save the document when the // DocStatus is saved, let's simply pre-anticipate that final String statusCode = getFinancialSystemDocumentHeader().getWorkflowDocument().getStatus().equals(DocumentStatus.INITIATED) ? DocumentStatus.SAVED.getCode() : getFinancialSystemDocumentHeader().getWorkflowDocument().getStatus().getCode(); getFinancialSystemDocumentHeader().setWorkflowDocumentStatusCode(statusCode); super.prepareForSave(); } }