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.coa.document;
017    
018    import java.util.ArrayList;
019    import java.util.Collection;
020    import java.util.Collections;
021    import java.util.Comparator;
022    import java.util.List;
023    import java.util.Map;
024    
025    import org.kuali.kfs.coa.businessobject.OrganizationReversion;
026    import org.kuali.kfs.coa.businessobject.OrganizationReversionCategory;
027    import org.kuali.kfs.coa.businessobject.OrganizationReversionDetail;
028    import org.kuali.kfs.coa.service.OrganizationReversionDetailTrickleDownInactivationService;
029    import org.kuali.kfs.coa.service.OrganizationReversionService;
030    import org.kuali.kfs.sys.context.SpringContext;
031    import org.kuali.kfs.sys.document.FinancialSystemMaintainable;
032    import org.kuali.rice.kns.bo.PersistableBusinessObject;
033    import org.kuali.rice.kns.document.MaintenanceDocument;
034    import org.kuali.rice.kns.maintenance.Maintainable;
035    import org.kuali.rice.kns.util.KNSConstants;
036    import org.kuali.rice.kns.util.ObjectUtils;
037    import org.kuali.rice.kns.util.TypedArrayList;
038    import org.kuali.rice.kns.web.ui.Field;
039    import org.kuali.rice.kns.web.ui.Row;
040    import org.kuali.rice.kns.web.ui.Section;
041    
042    /**
043     * This class provides some specific functionality for the {@link OrganizationReversion} maintenance document inner class for doing
044     * comparisons on {@link OrganizationReversionCategory} populateBusinessObject setBusinessObject - pre-populate the static list of
045     * details with each category isRelationshipRefreshable - makes sure that {@code organizationReversionGlobalDetails} isn't wiped out
046     * accidentally
047     */
048    public class OrganizationReversionMaintainableImpl extends FinancialSystemMaintainable {
049        private transient OrganizationReversionService organizationReversionService;
050    
051        /**
052         * This comparator is used internally for sorting the list of categories
053         */
054        private class categoryComparator implements Comparator<OrganizationReversionDetail> {
055    
056            public int compare(OrganizationReversionDetail detail0, OrganizationReversionDetail detail1) {
057    
058                OrganizationReversionCategory category0 = detail0.getOrganizationReversionCategory();
059                OrganizationReversionCategory category1 = detail1.getOrganizationReversionCategory();
060    
061                String code0 = category0.getOrganizationReversionCategoryCode();
062                String code1 = category1.getOrganizationReversionCategoryCode();
063    
064                return code0.compareTo(code1);
065            }
066    
067        }
068    
069        /**
070         * pre-populate the static list of details with each category
071         * 
072         * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#setBusinessObject(org.kuali.rice.kns.bo.BusinessObject)
073         */
074        public void setBusinessObject(PersistableBusinessObject businessObject) {
075    
076            OrganizationReversionService organizationReversionService = SpringContext.getBean(OrganizationReversionService.class);
077            OrganizationReversion organizationReversion = (OrganizationReversion) businessObject;
078            List<OrganizationReversionDetail> details = organizationReversion.getOrganizationReversionDetail();
079    
080            if (details == null) {
081                details = new TypedArrayList(OrganizationReversionDetail.class);
082                organizationReversion.setOrganizationReversionDetail(details);
083            }
084    
085            if (details.size() == 0) {
086    
087                Collection<OrganizationReversionCategory> categories = organizationReversionService.getCategoryList();
088    
089                for (OrganizationReversionCategory category : categories) {
090                    if (category.isActive()) {
091                        OrganizationReversionDetail detail = new OrganizationReversionDetail();
092                        detail.setOrganizationReversionCategoryCode(category.getOrganizationReversionCategoryCode());
093                        detail.setOrganizationReversionCategory(category);
094                        details.add(detail);
095                    }
096                }
097    
098                Collections.sort(details, new categoryComparator());
099    
100            }
101    
102            super.setBusinessObject(businessObject);
103        }
104    
105        /**
106         * A method that prevents lookups from refreshing the Organization Reversion Detail list (because, if it is refreshed before a
107         * save...it ends up destroying the list).
108         * 
109         * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#isRelationshipRefreshable(java.lang.Class, java.lang.String)
110         */
111        @Override
112        protected boolean isRelationshipRefreshable(Class boClass, String relationshipName) {
113            if (relationshipName.equals("organizationReversionDetail")) {
114                return false;
115            }
116            else {
117                return super.isRelationshipRefreshable(boClass, relationshipName);
118            }
119        }
120        
121        /**
122         * Determines if this maint doc is inactivating an organization reversion
123         * @return true if the document is inactivating an active organization reversion, false otherwise
124         */
125        protected boolean isInactivatingOrganizationReversion() {
126            // the account has to be closed on the new side when editing in order for it to be possible that we are closing the account
127            if (KNSConstants.MAINTENANCE_EDIT_ACTION.equals(getMaintenanceAction()) && !((OrganizationReversion) getBusinessObject()).isActive()) {
128                OrganizationReversion existingOrganizationReversionFromDB = retrieveExistingOrganizationReversion();
129                if (ObjectUtils.isNotNull(existingOrganizationReversionFromDB)) {
130                    // now see if the original account was not closed, in which case, we are closing the account
131                    if (existingOrganizationReversionFromDB.isActive()) {
132                        return true;
133                    }
134                }
135            }
136            return false;
137        }
138        
139        /**
140         * Determines if this maint doc is activating an organization reversion
141         * @return true if the document is activating an inactive organization reversion, false otherwise
142         */
143        protected boolean isActivatingOrganizationReversion() {
144            // the account has to be closed on the new side when editing in order for it to be possible that we are closing the account
145            if (KNSConstants.MAINTENANCE_EDIT_ACTION.equals(getMaintenanceAction()) && ((OrganizationReversion) getBusinessObject()).isActive()) {
146                OrganizationReversion existingOrganizationReversionFromDB = retrieveExistingOrganizationReversion();
147                if (ObjectUtils.isNotNull(existingOrganizationReversionFromDB)) {
148                    // now see if the original account was not closed, in which case, we are closing the account
149                    if (!existingOrganizationReversionFromDB.isActive()) {
150                        return true;
151                    }
152                }
153            }
154            return false;
155        }
156        
157        /**
158         * Grabs the old version of this org reversion from the database
159         * @return the old version of this organization reversion
160         */
161        protected OrganizationReversion retrieveExistingOrganizationReversion() {
162            final OrganizationReversion orgRev = (OrganizationReversion)getBusinessObject();
163            final OrganizationReversion oldOrgRev = SpringContext.getBean(OrganizationReversionService.class).getByPrimaryId(orgRev.getUniversityFiscalYear(), orgRev.getChartOfAccountsCode(), orgRev.getOrganizationCode());
164            return oldOrgRev;
165        }
166    
167        /**
168         * Overridden to trickle down inactivation or activation to details
169         * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#saveBusinessObject()
170         */
171        @Override
172        public void saveBusinessObject() {
173            final boolean isActivatingOrgReversion = isActivatingOrganizationReversion();
174            final boolean isInactivatingOrgReversion = isInactivatingOrganizationReversion();
175            
176            super.saveBusinessObject();
177            
178            if (isActivatingOrgReversion) {
179                SpringContext.getBean(OrganizationReversionDetailTrickleDownInactivationService.class).trickleDownActiveOrganizationReversionDetails((OrganizationReversion)getBusinessObject(), documentNumber);
180            } else if (isInactivatingOrgReversion) {
181                SpringContext.getBean(OrganizationReversionDetailTrickleDownInactivationService.class).trickleDownInactiveOrganizationReversionDetails((OrganizationReversion)getBusinessObject(), documentNumber);
182            }
183        }
184    
185        /**
186         * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#getSections(org.kuali.rice.kns.document.MaintenanceDocument, org.kuali.rice.kns.maintenance.Maintainable)
187         */
188        @Override
189        public List getSections(MaintenanceDocument document, Maintainable oldMaintainable) {
190            List<Section> sections = super.getSections(document, oldMaintainable);
191            if (organizationReversionService == null) {
192                organizationReversionService = SpringContext.getBean(OrganizationReversionService.class);
193            }
194            for (Section section : sections) {
195                for (Row row : section.getRows()) {
196                    List<Field> updatedFields = new ArrayList<Field>();
197                    for (Field field : row.getFields()) {
198                        if (shouldIncludeField(field)) {
199                            updatedFields.add(field);
200                        }
201                    }
202                    row.setFields(updatedFields);
203                }
204            }
205            return sections;
206        }
207        
208        /**
209         * Determines if the given field should be included in the updated row, once we take out inactive categories
210         * @param field the field to check
211         * @return true if the field should be included (ie, it doesn't describe an organization reversion with an inactive category); false otherwise
212         */
213        protected boolean shouldIncludeField(Field field) {
214            boolean includeField = true;
215            if (field.getContainerRows() != null) {
216                for (Row containerRow : field.getContainerRows()) {
217                    for (Field containedField : containerRow.getFields()) {
218                        if (containedField.getPropertyName().matches("organizationReversionDetail\\[\\d+\\]\\.organizationReversionCategory\\.organizationReversionCategoryName")) {
219                            final String categoryValue = containedField.getPropertyValue();
220                            includeField = organizationReversionService.isCategoryActiveByName(categoryValue);
221                        }
222                    }
223                }
224            }
225            return includeField;
226        }
227        
228    }