001/*
002 * Copyright 2008 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 */
016package org.kuali.ole.sys.document;
017
018import java.util.Map;
019import java.util.Set;
020
021import org.apache.log4j.Logger;
022import org.kuali.ole.sys.OLEConstants;
023import org.kuali.ole.sys.businessobject.FinancialSystemDocumentHeader;
024import org.kuali.ole.sys.context.SpringContext;
025import org.kuali.ole.sys.document.dataaccess.FinancialSystemDocumentHeaderDao;
026import org.kuali.ole.sys.document.service.FinancialSystemDocumentService;
027import org.kuali.ole.sys.service.impl.OleParameterConstants;
028import org.kuali.rice.core.api.util.type.KualiDecimal;
029import org.kuali.rice.coreservice.framework.parameter.ParameterService;
030import org.kuali.rice.kew.api.WorkflowRuntimeException;
031import org.kuali.rice.kew.api.exception.WorkflowException;
032import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
033import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
034import org.kuali.rice.kns.service.DocumentHelperService;
035import org.kuali.rice.krad.bo.DocumentHeader;
036import org.kuali.rice.krad.document.TransactionalDocumentBase;
037import org.kuali.rice.krad.service.BusinessObjectService;
038import org.kuali.rice.krad.util.GlobalVariables;
039
040/**
041 * This class is a OLE specific TransactionalDocumentBase class
042 */
043public class FinancialSystemTransactionalDocumentBase extends TransactionalDocumentBase implements FinancialSystemTransactionalDocument {
044    private static final Logger LOG = Logger.getLogger(FinancialSystemTransactionalDocumentBase.class);
045
046    protected static final String UPDATE_TOTAL_AMOUNT_IN_POST_PROCESSING_PARAMETER_NAME = "UPDATE_TOTAL_AMOUNT_IN_POST_PROCESSING_IND";
047
048    private static transient BusinessObjectService businessObjectService;
049    private static transient FinancialSystemDocumentService financialSystemDocumentService;
050    private static transient ParameterService parameterService;
051
052    private transient Map<String,Boolean> canEditCache;
053
054    /**
055     * Constructs a FinancialSystemTransactionalDocumentBase.java.
056     */
057    public FinancialSystemTransactionalDocumentBase() {
058        super();
059    }
060
061    @Override
062    public FinancialSystemDocumentHeader getFinancialSystemDocumentHeader() {
063        return (FinancialSystemDocumentHeader) documentHeader;
064    }
065
066    /**
067     * @see org.kuali.rice.krad.document.DocumentBase#setDocumentHeader(org.kuali.rice.krad.bo.DocumentHeader)
068     */
069    @Override
070    public void setDocumentHeader(DocumentHeader documentHeader) {
071        if ((documentHeader != null) && (!FinancialSystemDocumentHeader.class.isAssignableFrom(documentHeader.getClass()))) {
072            throw new IllegalArgumentException("document header of class '" + documentHeader.getClass() + "' is not assignable from financial document header class '" + FinancialSystemDocumentHeader.class + "'");
073        }
074        this.documentHeader = documentHeader;
075    }
076
077    /**
078     * If the document has a total amount, call method on document to get the total and set in doc header.
079     *
080     * @see org.kuali.rice.krad.document.Document#prepareForSave()
081     */
082    @Override
083    public void prepareForSave() {
084        if (this instanceof AmountTotaling) {
085            getFinancialSystemDocumentHeader().setFinancialDocumentTotalAmount(((AmountTotaling) this).getTotalDollarAmount());
086        }
087        super.prepareForSave();
088    }
089
090    /**
091     * This is the default implementation which ensures that document note attachment references are loaded.
092     *
093     * @see org.kuali.rice.krad.document.Document#processAfterRetrieve()
094     */
095    @Override
096    public void processAfterRetrieve() {
097        // set correctedByDocumentId manually, since OJB doesn't maintain that relationship
098        try {
099            DocumentHeader correctingDocumentHeader = SpringContext.getBean(FinancialSystemDocumentHeaderDao.class).getCorrectingDocumentHeader(getFinancialSystemDocumentHeader().getDocumentNumber());
100            if (correctingDocumentHeader != null) {
101                getFinancialSystemDocumentHeader().setCorrectedByDocumentId(correctingDocumentHeader.getDocumentNumber());
102            }
103        } catch (Exception e) {
104            LOG.error("Received WorkflowException trying to get route header id from workflow document.", e);
105            throw new WorkflowRuntimeException(e);
106        }
107        // set the ad hoc route recipients too, since OJB doesn't maintain that relationship
108        // TODO - see KULNRVSYS-1054
109
110        super.processAfterRetrieve();
111    }
112
113    /**
114     * This is the default implementation which checks for a different workflow statuses, and updates the Kuali status accordingly.
115     *
116     * @see org.kuali.rice.krad.document.Document#doRouteStatusChange()
117     */
118    @Override
119    public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) {
120        if (getDocumentHeader().getWorkflowDocument().isCanceled()) {
121            getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(OLEConstants.DocumentStatusCodes.CANCELLED);
122        }
123        else if (getDocumentHeader().getWorkflowDocument().isEnroute()) {
124            getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(OLEConstants.DocumentStatusCodes.ENROUTE);
125        }
126        if (getDocumentHeader().getWorkflowDocument().isDisapproved()) {
127            getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(OLEConstants.DocumentStatusCodes.DISAPPROVED);
128        }
129        if (getDocumentHeader().getWorkflowDocument().isProcessed()) {
130            getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(OLEConstants.DocumentStatusCodes.APPROVED);
131        }
132        if ( LOG.isInfoEnabled() ) {
133            LOG.info("Document: " + statusChangeEvent.getDocumentId() + " -- Status is: " + getFinancialSystemDocumentHeader().getFinancialDocumentStatusCode());
134        }
135
136        super.doRouteStatusChange(statusChangeEvent);
137    }
138
139    /**
140     * This is the default implementation which, if parameter KFS-SYS / Document / UPDATE_TOTAL_AMOUNT_IN_POST_PROCESSING_IND is on, updates the document
141     * and resaves if needed
142     * @see org.kuali.rice.kns.document.DocumentBase#doRouteLevelChange(org.kuali.rice.kew.dto.DocumentRouteLevelChangeDTO)
143     */
144    @Override
145    public void doRouteLevelChange(DocumentRouteLevelChange levelChangeEvent) {
146        if (this instanceof AmountTotaling
147                && getDocumentHeader() != null
148                && getParameterService() != null
149                && getBusinessObjectService() != null
150                && getParameterService().parameterExists(OleParameterConstants.FINANCIAL_SYSTEM_DOCUMENT.class, UPDATE_TOTAL_AMOUNT_IN_POST_PROCESSING_PARAMETER_NAME)
151                && getParameterService().getParameterValueAsBoolean(OleParameterConstants.FINANCIAL_SYSTEM_DOCUMENT.class, UPDATE_TOTAL_AMOUNT_IN_POST_PROCESSING_PARAMETER_NAME)) {
152            final KualiDecimal currentTotal = ((AmountTotaling)this).getTotalDollarAmount();
153            if (!currentTotal.equals(getFinancialSystemDocumentHeader().getFinancialDocumentTotalAmount())) {
154                getFinancialSystemDocumentHeader().setFinancialDocumentTotalAmount(currentTotal);
155                getBusinessObjectService().save(getFinancialSystemDocumentHeader());
156            }
157        }
158        super.doRouteLevelChange(levelChangeEvent);
159    }
160
161    /**
162     * @see org.kuali.ole.sys.document.Correctable#toErrorCorrection()
163     */
164    public void toErrorCorrection() throws WorkflowException, IllegalStateException {
165        DocumentHelperService documentHelperService = SpringContext.getBean(DocumentHelperService.class);
166        final Set<String> documentActionsFromPresentationController = documentHelperService.getDocumentPresentationController(this).getDocumentActions(this);
167        final Set<String> documentActionsFromAuthorizer = documentHelperService.getDocumentAuthorizer(this).getDocumentActions(this, GlobalVariables.getUserSession().getPerson(), documentActionsFromPresentationController);
168        if (!documentActionsFromAuthorizer.contains(OLEConstants.KFS_ACTION_CAN_ERROR_CORRECT)) {
169            throw new IllegalStateException(this.getClass().getName() + " does not support document-level error correction");
170        }
171
172        String sourceDocumentHeaderId = getDocumentNumber();
173        setNewDocumentHeader();
174        getFinancialSystemDocumentHeader().setFinancialDocumentInErrorNumber(sourceDocumentHeaderId);
175        addCopyErrorDocumentNote("error-correction for document " + sourceDocumentHeaderId);
176    }
177
178    @Override
179    public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException {
180        throw new UnsupportedOperationException("No split node logic defined for split node "+nodeName+" on " + this.getClass().getSimpleName());
181    }
182
183    /**
184     * @return the default implementation of the ParameterService
185     */
186    protected ParameterService getParameterService() {
187       if (parameterService == null) {
188           parameterService = SpringContext.getBean(ParameterService.class);
189       }
190       return parameterService;
191    }
192
193    /**
194     * @return the default implementation of the BusinessObjectService
195     */
196    protected BusinessObjectService getBusinessObjectService() {
197        if (businessObjectService == null) {
198            businessObjectService = SpringContext.getBean(BusinessObjectService.class);
199        }
200        return businessObjectService;
201    }
202
203    protected FinancialSystemDocumentService getFinancialSystemDocumentService() {
204        if (financialSystemDocumentService == null) {
205            financialSystemDocumentService = SpringContext.getBean(FinancialSystemDocumentService.class);
206        }
207        return financialSystemDocumentService;
208    }
209
210    @Override
211    public void toCopy() throws WorkflowException, IllegalStateException {
212        FinancialSystemDocumentHeader oldDocumentHeader = getFinancialSystemDocumentHeader();
213        super.toCopy();
214
215        getFinancialSystemDocumentService().prepareToCopy(oldDocumentHeader, this);
216    }
217
218    /**
219     * Updates status of this document and saves the workflow data
220     *
221     * @param applicationDocumentStatus is the app doc status to save
222     * @throws WorkflowException
223     */
224    public void updateAndSaveAppDocStatus(String applicationDocumentStatus) throws WorkflowException {
225        getFinancialSystemDocumentHeader().updateAndSaveAppDocStatus(applicationDocumentStatus);
226    }
227
228    /**
229     * Gets the applicationDocumentStatus attribute.
230     *
231     * @return Returns the applicationDocumentStatus
232     */
233
234    public String getApplicationDocumentStatus() {
235        return getFinancialSystemDocumentHeader().getApplicationDocumentStatus();
236    }
237
238    /**
239     * Sets the applicationDocumentStatus attribute.
240     *
241     * @param applicationDocumentStatus The applicationDocumentStatus to set.
242     */
243    public void setApplicationDocumentStatus(String applicationDocumentStatus) {
244        getFinancialSystemDocumentHeader().setApplicationDocumentStatus(applicationDocumentStatus);
245    }
246}