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.module.cg.document; 017 018 import java.util.Collection; 019 import java.util.List; 020 import java.util.Map; 021 022 import org.apache.commons.lang.StringUtils; 023 import org.kuali.kfs.module.cg.businessobject.Proposal; 024 import org.kuali.kfs.module.cg.businessobject.ProposalProjectDirector; 025 import org.kuali.kfs.module.cg.businessobject.ProposalResearchRisk; 026 import org.kuali.kfs.module.cg.businessobject.ProposalSubcontractor; 027 import org.kuali.kfs.module.cg.businessobject.ResearchRiskType; 028 import org.kuali.kfs.module.cg.businessobject.defaultvalue.NextProposalNumberFinder; 029 import org.kuali.kfs.module.cg.document.service.RoutingFormResearchRiskService; 030 import org.kuali.kfs.sys.KFSConstants; 031 import org.kuali.kfs.sys.KFSPropertyConstants; 032 import org.kuali.kfs.sys.context.SpringContext; 033 import org.kuali.kfs.sys.document.FinancialSystemMaintainable; 034 import org.kuali.rice.kim.bo.Person; 035 import org.kuali.rice.kim.service.PersonService; 036 import org.kuali.rice.kns.bo.PersistableBusinessObject; 037 import org.kuali.rice.kns.document.MaintenanceDocument; 038 import org.kuali.rice.kns.util.AssertionUtils; 039 import org.kuali.rice.kns.util.ObjectUtils; 040 041 /** 042 * Methods for the Proposal maintenance document UI. 043 */ 044 public class ProposalMaintainableImpl extends FinancialSystemMaintainable { 045 public ProposalMaintainableImpl() { 046 super(); 047 } 048 049 /** 050 * Constructs a new ProposalMaintainableImpl from an existing {@link Proposal}. 051 * 052 * @param proposal 053 */ 054 public ProposalMaintainableImpl(Proposal proposal) { 055 super(proposal); 056 this.setBoClass(proposal.getClass()); 057 } 058 059 /** 060 * Use a new proposal number when creating a copy. 061 */ 062 @Override 063 public void processAfterCopy(MaintenanceDocument document, Map<String, String[]> parameters) { 064 getProposal().setProposalNumber(NextProposalNumberFinder.getLongValue()); 065 getProposal().setProposalClosingDate(null); 066 super.processAfterCopy(document, parameters); 067 } 068 069 /** 070 * This method is called for refreshing the {@link Agency} before display to show the full name in case the agency number was 071 * changed by hand before any submit that causes a redisplay. 072 */ 073 @Override 074 public void processAfterRetrieve() { 075 refreshProposal(false); 076 super.processAfterRetrieve(); 077 } 078 079 /** 080 * <p> 081 * This method is called for refreshing the {@link Agency} before a save to display the full name in case the agency number was 082 * changed by hand just before the save. Also, if there is only one {@link ProjectDirector}, then this method defaults it to be 083 * primary. This method can change data, unlike the rules. It is run before the rules.<p/> This default primary is limited to 084 * save actions (including route, etc) so that when the user adds multiple {@link ProjectDirectors} the first one added doesn't 085 * default to primary (so the user must choose). 086 */ 087 @Override 088 public void prepareForSave() { 089 refreshProposal(false); 090 List<ProposalProjectDirector> directors = getProposal().getProposalProjectDirectors(); 091 if (directors.size() == 1) { 092 directors.get(0).setProposalPrimaryProjectDirectorIndicator(true); 093 } 094 List<ProposalSubcontractor> proposalSubcontractors = getProposal().getProposalSubcontractors(); 095 if (proposalSubcontractors != null && !proposalSubcontractors.isEmpty()) { 096 int i = 0; 097 for (ProposalSubcontractor proposalSubcontractor : proposalSubcontractors) { 098 i++; 099 if (StringUtils.isBlank(proposalSubcontractor.getProposalSubcontractorNumber())) { 100 proposalSubcontractor.setProposalSubcontractorNumber("" + i); 101 } 102 } 103 } 104 super.prepareForSave(); 105 } 106 107 /** 108 * This method is called for refreshing the {@link Agency} and other related BOs after a lookup, to display their full name & 109 * etc without AJAX. 110 * 111 * @param refreshCaller 112 * @param fieldValues 113 * @param document 114 */ 115 @Override 116 public void refresh(String refreshCaller, Map fieldValues, MaintenanceDocument document) { 117 refreshProposal(KFSConstants.KUALI_LOOKUPABLE_IMPL.equals(fieldValues.get(KFSConstants.REFRESH_CALLER))); 118 super.refresh(refreshCaller, fieldValues, document); 119 } 120 121 /** 122 * This is a hook for initializing the BO from the maintenance framework. It initializes the {@link ResearchRiskType}s 123 * collection. 124 * 125 * @param generateDefaultValues true for initialization 126 */ 127 @Override 128 public void setGenerateDefaultValues(String docTypeName) { 129 // if (generateDefaultValues) { 130 initResearchRiskTypes(); 131 // } 132 super.setGenerateDefaultValues(docTypeName); 133 } 134 135 /** 136 * 137 */ 138 private void initResearchRiskTypes() { 139 List<ProposalResearchRisk> risks = getProposal().getProposalResearchRisks(); 140 AssertionUtils.assertThat(risks.isEmpty()); 141 // no requirement to exclude any risk types (except inactive ones, which the service excludes anyway) 142 final String[] riskTypeCodesToExclude = new String[0]; 143 List<ResearchRiskType> researchRiskTypes = SpringContext.getBean(RoutingFormResearchRiskService.class).getResearchRiskTypes(riskTypeCodesToExclude); 144 for (ResearchRiskType type : researchRiskTypes) { 145 ProposalResearchRisk ppr = new ProposalResearchRisk(); 146 ppr.setResearchRiskTypeCode(type.getResearchRiskTypeCode()); 147 ppr.setResearchRiskType(type); // one less refresh 148 risks.add(ppr); 149 } 150 } 151 152 /** 153 * @param refreshFromLookup 154 */ 155 private void refreshProposal(boolean refreshFromLookup) { 156 getProposal().refreshNonUpdateableReferences(); 157 158 getNewCollectionLine(KFSPropertyConstants.PROPOSAL_SUBCONTRACTORS).refreshNonUpdateableReferences(); 159 160 refreshNonUpdateableReferences(getProposal().getProposalOrganizations()); 161 refreshNonUpdateableReferences(getProposal().getProposalSubcontractors()); 162 refreshNonUpdateableReferences(getProposal().getProposalResearchRisks()); 163 164 refreshProposalProjectDirectors(refreshFromLookup); 165 } 166 167 /** 168 * Refreshes this maintainable's ProposalProjectDirectors. 169 * 170 * @param refreshFromLookup a lookup returns only the primary key, so ignore the secondary key when true 171 */ 172 private void refreshProposalProjectDirectors(boolean refreshFromLookup) { 173 if (refreshFromLookup) { 174 getNewCollectionLine(KFSPropertyConstants.PROPOSAL_PROJECT_DIRECTORS).refreshNonUpdateableReferences(); 175 refreshNonUpdateableReferences(getProposal().getProposalProjectDirectors()); 176 } 177 else { 178 refreshWithSecondaryKey((ProposalProjectDirector) getNewCollectionLine(KFSPropertyConstants.PROPOSAL_PROJECT_DIRECTORS)); 179 for (ProposalProjectDirector ppd : getProposal().getProposalProjectDirectors()) { 180 refreshWithSecondaryKey(ppd); 181 } 182 } 183 } 184 185 /** 186 * @param collection 187 */ 188 private static void refreshNonUpdateableReferences(Collection<? extends PersistableBusinessObject> collection) { 189 for (PersistableBusinessObject item : collection) { 190 item.refreshNonUpdateableReferences(); 191 } 192 } 193 194 /** 195 * Refreshes the reference to ProjectDirector, giving priority to its secondary key. Any secondary key that it has may be user 196 * input, so that overrides the primary key, setting the primary key. If its primary key is blank or nonexistent, then leave the 197 * current reference as it is, because it may be a nonexistent instance which is holding the secondary key (the username, i.e., 198 * principalName) so we can redisplay it to the user for correction. If it only has a primary key then use that, because it may 199 * be coming from the database, without any user input. 200 * 201 * @param ppd the ProposalProjectDirector to refresh 202 */ 203 private static void refreshWithSecondaryKey(ProposalProjectDirector ppd) { 204 String secondaryKey = null; 205 if (ObjectUtils.isNotNull(ppd.getProjectDirector())) { 206 secondaryKey = ppd.getProjectDirector().getPrincipalName(); 207 } 208 if (StringUtils.isNotBlank(secondaryKey)) { 209 Person dir = SpringContext.getBean(PersonService.class).getPersonByPrincipalName(secondaryKey); 210 ppd.setPrincipalId(dir == null ? null : dir.getPrincipalId()); 211 } 212 if (StringUtils.isNotBlank(ppd.getPrincipalId())) { 213 Person person = SpringContext.getBean(PersonService.class).getPerson(ppd.getPrincipalId()); 214 if (person != null) { 215 ppd.refreshNonUpdateableReferences(); 216 } 217 } 218 } 219 220 /** 221 * Gets the {@link Proposal} 222 * 223 * @return 224 */ 225 public Proposal getProposal() { 226 return (Proposal) getBusinessObject(); 227 } 228 229 /** 230 * called for refreshing the {@link Subcontractor} on {@link ProposalSubcontractor} before adding to the 231 * {@link ProposalSubcontractor}s collection on the proposal. this is to ensure that the summary fields are shown correctly. 232 * i.e. {@link Subcontractor} name 233 * 234 * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#addNewLineToCollection(java.lang.String) 235 */ 236 @Override 237 public void addNewLineToCollection(String collectionName) { 238 refreshProposal(false); 239 super.addNewLineToCollection(collectionName); 240 } 241 }