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.fp.document.authorization;
017    
018    import java.util.Set;
019    
020    import org.apache.commons.lang.StringUtils;
021    import org.kuali.kfs.fp.businessobject.CashDrawer;
022    import org.kuali.kfs.fp.document.CashManagementDocument;
023    import org.kuali.kfs.fp.document.service.CashManagementService;
024    import org.kuali.kfs.fp.service.CashDrawerService;
025    import org.kuali.kfs.sys.KFSConstants;
026    import org.kuali.kfs.sys.KfsAuthorizationConstants;
027    import org.kuali.kfs.sys.KFSConstants.CashDrawerConstants;
028    import org.kuali.kfs.sys.context.SpringContext;
029    import org.kuali.kfs.sys.document.authorization.LedgerPostingDocumentPresentationControllerBase;
030    import org.kuali.rice.kew.dto.ValidActionsDTO;
031    import org.kuali.rice.kew.util.KEWConstants;
032    import org.kuali.rice.kns.datadictionary.MaintenanceDocumentEntry;
033    import org.kuali.rice.kns.document.Document;
034    import org.kuali.rice.kns.maintenance.Maintainable;
035    import org.kuali.rice.kns.service.DataDictionaryService;
036    import org.kuali.rice.kns.service.MaintenanceDocumentService;
037    import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
038    
039    public class CashManagementDocumentPresentationControllerBase extends LedgerPostingDocumentPresentationControllerBase implements CashManagementDocumentPresentationController {
040    
041        /**
042         * @see org.kuali.kfs.sys.document.authorization.FinancialSystemTransactionalDocumentPresentationControllerBase#getEditModes(org.kuali.rice.kns.document.Document)
043         */
044        @Override
045        public Set<String> getEditModes(Document document) {
046            Set<String> editModes = super.getEditModes(document);
047    
048            KualiWorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
049            if (workflowDocument.stateIsSaved()) {
050                editModes.add(KfsAuthorizationConstants.CashManagementEditMode.ALLOW_CANCEL_DEPOSITS);
051    
052                CashManagementDocument cashManagementDocument = (CashManagementDocument) document;
053                if (!cashManagementDocument.hasFinalDeposit()) {
054                    editModes.add(KfsAuthorizationConstants.CashManagementEditMode.ALLOW_ADDITIONAL_DEPOSITS);
055                }
056            }
057    
058            return editModes;
059        }
060    
061        /**
062         * @see org.kuali.rice.kns.document.authorization.DocumentPresentationControllerBase#canApprove(org.kuali.rice.kns.document.Document)
063         */
064        @Override
065        protected boolean canApprove(Document document) {
066            KualiWorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
067            if (workflowDocument.stateIsEnroute()) {
068                ValidActionsDTO validActions = workflowDocument.getRouteHeader().getValidActions();
069                return validActions.contains(KEWConstants.ACTION_TAKEN_APPROVED_CD);
070            }
071    
072            return super.canApprove(document);
073        }
074    
075        /**
076         * @see org.kuali.rice.kns.document.authorization.DocumentPresentationControllerBase#canBlanketApprove(org.kuali.rice.kns.document.Document)
077         */
078        @Override
079        protected boolean canBlanketApprove(Document document) {
080            KualiWorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
081            if (workflowDocument.stateIsInitiated() || workflowDocument.stateIsSaved()) {
082                CashManagementDocument cmDoc = (CashManagementDocument) document;
083                if (!cmDoc.hasFinalDeposit() || !SpringContext.getBean(CashManagementService.class).allVerifiedCashReceiptsAreDeposited(cmDoc)) {
084                    return false;
085                }
086    
087                // CM document can only be routed if it contains a Final Deposit
088                ValidActionsDTO validActions = workflowDocument.getRouteHeader().getValidActions();
089                return validActions.contains(KEWConstants.ACTION_TAKEN_BLANKET_APPROVE_CD);
090            }
091    
092            return super.canBlanketApprove(document);
093        }
094    
095        /**
096         * @see org.kuali.rice.kns.document.authorization.DocumentPresentationControllerBase#canCancel(org.kuali.rice.kns.document.Document)
097         */
098        @Override
099        protected boolean canCancel(Document document) {
100            KualiWorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
101            if (workflowDocument.stateIsInitiated() || workflowDocument.stateIsSaved()) {
102                CashManagementDocument cmDoc = (CashManagementDocument) document;
103                if (!SpringContext.getBean(CashManagementService.class).allowDocumentCancellation(cmDoc)) {
104                    return false;
105                }
106    
107                // CM document can only be routed if it contains a Final Deposit
108                ValidActionsDTO validActions = workflowDocument.getRouteHeader().getValidActions();
109                return validActions.contains(KEWConstants.ACTION_TAKEN_CANCELED_CD);
110            }
111    
112            return super.canCancel(document);
113        }
114    
115        /**
116         * @see org.kuali.rice.kns.document.authorization.DocumentPresentationControllerBase#canDisapprove(org.kuali.rice.kns.document.Document)
117         */
118        @Override
119        protected boolean canDisapprove(Document document) {
120            KualiWorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
121            if (workflowDocument.stateIsEnroute()) {
122                ValidActionsDTO validActions = workflowDocument.getRouteHeader().getValidActions();
123                return validActions.contains(KEWConstants.ACTION_TAKEN_DENIED_CD);
124            }
125    
126            return super.canDisapprove(document);
127        }
128    
129        /**
130         * @see org.kuali.rice.kns.document.authorization.DocumentPresentationControllerBase#canRoute(org.kuali.rice.kns.document.Document)
131         */
132        @Override
133        protected boolean canRoute(Document document) {
134            KualiWorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
135            if (workflowDocument.stateIsInitiated() || workflowDocument.stateIsSaved()) {
136                CashManagementDocument cmDoc = (CashManagementDocument) document;
137                if (!cmDoc.hasFinalDeposit() || !SpringContext.getBean(CashManagementService.class).allVerifiedCashReceiptsAreDeposited(cmDoc)) {
138                    return false;
139                }
140    
141                // CM document can only be routed if it contains a Final Deposit
142                ValidActionsDTO validActions = workflowDocument.getRouteHeader().getValidActions();
143                return validActions.contains(KEWConstants.ACTION_TAKEN_ROUTED_CD);
144            }
145    
146            return super.canRoute(document);
147        }
148    
149        /**
150         * @see org.kuali.rice.kns.document.authorization.DocumentPresentationControllerBase#canSave(org.kuali.rice.kns.document.Document)
151         */
152        @Override
153        protected boolean canSave(Document document) {
154            KualiWorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
155            if (workflowDocument.stateIsInitiated() || workflowDocument.stateIsSaved()) {
156                CashManagementDocument cmDoc = (CashManagementDocument) document;
157                if (cmDoc.getCashDrawerStatus() == null || cmDoc.getCashDrawerStatus().equals(CashDrawerConstants.STATUS_CLOSED)) {
158                    return false;
159                }
160    
161                // CM document can only be saved (via the save button) if the CashDrawer is not closed
162                ValidActionsDTO validActions = workflowDocument.getRouteHeader().getValidActions();
163                return validActions.contains(KEWConstants.ACTION_TAKEN_SAVED_CD);
164            }
165    
166            return super.canRoute(document);
167        }
168    
169        /**
170         * @see org.kuali.rice.kns.document.authorization.DocumentPresentationControllerBase#canAdHocRoute(org.kuali.rice.kns.document.Document)
171         */
172        @Override
173        protected boolean canAddAdhocRequests(Document document) {
174            KualiWorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
175            if (workflowDocument.stateIsEnroute()) {
176                ValidActionsDTO validActions = workflowDocument.getRouteHeader().getValidActions();
177                return validActions.contains(KEWConstants.ACTION_TAKEN_FYI_CD);
178            }
179    
180            return super.canAddAdhocRequests(document);
181        }
182        
183        /**
184         * Determines if the cash drawer can be opened by testing two things:
185         * <ol>
186         *  <li>That the cash drawer is currently closed.</li>
187         *  <li>That no cash drawer maintenance documents have a lock on the cash drawer.</li>
188         * </ol>
189         * @param document the document that wishes to open the cash drawer
190         * @return true if the cash drawer can be opened, false otherwise
191         */
192        public boolean canOpenCashDrawer(Document document) {
193            final CashDrawer cashDrawer = retrieveCashDrawer(document);
194            return cashDrawer.isClosed() && noExistCashDrawerMaintLocks(cashDrawer, document.getDocumentNumber());
195        }
196        
197        /**
198         * Retrieves the cash drawer associated with the given cash management document
199         * @param document a CashManagementDocument with an associated cash drawer
200         * @return the associated cash drawer
201         */
202        protected CashDrawer retrieveCashDrawer(Document document) {
203            final CashManagementDocument cmDoc = (CashManagementDocument)document;
204            final CashDrawer cashDrawer = SpringContext.getBean(CashDrawerService.class).getByCampusCode(cmDoc.getCampusCode());
205            return cashDrawer;
206        }
207        
208        /**
209         * Determines that no maintenance documents have locks on the given cash drawer
210         * @param cashDrawer the cash drawer that may have locks on it
211         * @return true if there are no maintenance documents with locks on the cash drawer, false otherwise
212         */
213        protected boolean noExistCashDrawerMaintLocks(CashDrawer cashDrawer, String documentNumber) {
214           final MaintenanceDocumentEntry cashDrawerMaintDocEntry = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getMaintenanceDocumentEntryForBusinessObjectClass(cashDrawer.getClass());
215           Maintainable cashDrawerMaintainable = createCashDrawerMaintainable(cashDrawerMaintDocEntry);
216           cashDrawerMaintainable.setBoClass(cashDrawer.getClass());
217           cashDrawerMaintainable.setBusinessObject(cashDrawer);
218           cashDrawerMaintainable.setDocumentNumber(documentNumber);
219           
220           final String lockingDocument = SpringContext.getBean(MaintenanceDocumentService.class).getLockingDocumentId(cashDrawerMaintainable, documentNumber);
221           return StringUtils.isBlank(lockingDocument);
222        }
223        
224        /**
225         * Builds an instance of the appropriate Maintainable implementation for the Cash Drawer Maintainable
226         * @param cashDrawerMaintenanceDocumentEntry the data dictionary entry from the Cash Drawer's maintenance document 
227         * @return an appropriate Maintainable
228         */
229        protected Maintainable createCashDrawerMaintainable(MaintenanceDocumentEntry cashDrawerMaintenanceDocumentEntry) {
230            Maintainable cashDrawerMaintainable;
231            try {
232                cashDrawerMaintainable = cashDrawerMaintenanceDocumentEntry.getMaintainableClass().newInstance();
233            }
234            catch (InstantiationException ie) {
235                throw new RuntimeException("Cannot instantiate instance of maintainable implementation "+cashDrawerMaintenanceDocumentEntry.getMaintainableClass().getName(), ie);
236            }
237            catch (IllegalAccessException iae) {
238                throw new RuntimeException("Illegal access occurred while instantiating instance of maintainable implementation "+cashDrawerMaintenanceDocumentEntry.getMaintainableClass().getName(), iae);
239            }
240            return cashDrawerMaintainable;
241        }
242    }