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.bc.document.web.struts;
017    
018    import java.util.ArrayList;
019    import java.util.HashMap;
020    import java.util.HashSet;
021    import java.util.List;
022    import java.util.Set;
023    
024    import javax.servlet.http.HttpServletRequest;
025    
026    import org.kuali.kfs.coa.businessobject.Account;
027    import org.kuali.kfs.coa.businessobject.Organization;
028    import org.kuali.kfs.module.bc.BCConstants;
029    import org.kuali.kfs.module.bc.BCKeyConstants;
030    import org.kuali.kfs.module.bc.BCPropertyConstants;
031    import org.kuali.kfs.module.bc.BCConstants.LockStatus;
032    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionLockStatus;
033    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionPosition;
034    import org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding;
035    import org.kuali.kfs.module.bc.document.service.BudgetConstructionProcessorService;
036    import org.kuali.kfs.module.bc.document.service.BudgetDocumentService;
037    import org.kuali.kfs.module.bc.document.service.LockService;
038    import org.kuali.kfs.module.bc.document.service.SalarySettingService;
039    import org.kuali.kfs.module.bc.util.SalarySettingFieldsHolder;
040    import org.kuali.kfs.sys.KFSConstants;
041    import org.kuali.kfs.sys.KFSPropertyConstants;
042    import org.kuali.kfs.sys.ObjectUtil;
043    import org.kuali.kfs.sys.context.SpringContext;
044    import org.kuali.kfs.sys.identity.KfsKimAttributes;
045    import org.kuali.rice.kim.bo.types.dto.AttributeSet;
046    import org.kuali.rice.kim.service.PermissionService;
047    import org.kuali.rice.kim.service.RoleManagementService;
048    import org.kuali.rice.kns.service.BusinessObjectService;
049    import org.kuali.rice.kns.util.ErrorMap;
050    import org.kuali.rice.kns.util.MessageMap;
051    
052    /**
053     * the base struts form for the detail salary setting: by position or by incumbent
054     */
055    public abstract class DetailSalarySettingForm extends SalarySettingBaseForm {
056        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DetailSalarySettingForm.class);
057    
058        private PendingBudgetConstructionAppointmentFunding newBCAFLine;
059        private boolean addLine;
060    
061        private String positionNumber;
062        private String emplid;
063        private String name;
064    
065        private SalarySettingService salarySettingService = SpringContext.getBean(SalarySettingService.class);
066        private BudgetDocumentService budgetDocumentService = SpringContext.getBean(BudgetDocumentService.class);
067        private PermissionService permissionService = SpringContext.getBean(PermissionService.class);
068        private LockService lockService = SpringContext.getBean(LockService.class);
069        private BusinessObjectService businessObjectService = SpringContext.getBean(BusinessObjectService.class);
070    
071        private static final List<String> comparableFields = getComparableFields();
072    
073        /**
074         * Constructs a DetailSalarySettingForm.java.
075         */
076        public DetailSalarySettingForm() {
077            super();
078    
079            this.setEditingMode(new HashMap<String, String>());
080            this.setNewBCAFLine(new PendingBudgetConstructionAppointmentFunding());
081        }
082    
083        /**
084         * @see org.kuali.rice.kns.web.struts.form.KualiForm#populate(javax.servlet.http.HttpServletRequest)
085         */
086        @Override
087        public void populate(HttpServletRequest request) {
088            super.populate(request);
089    
090            this.setSingleAccountMode(this.resetSingleAccountModeFlag());
091    
092            this.populateBCAFLines();
093        }
094    
095        /**
096         * @see org.kuali.kfs.module.bc.document.web.struts.SalarySettingBaseForm#populateBCAFLines()
097         */
098        @Override
099        public void populateBCAFLines() {
100            super.populateBCAFLines();
101    
102            this.refreshBCAFLine(this.getNewBCAFLine());
103        }
104    
105        /**
106         * @see org.kuali.kfs.module.bc.document.web.struts.SalarySettingBaseForm#refreshBCAFLine(org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding)
107         */
108        @Override
109        public void refreshBCAFLine(PendingBudgetConstructionAppointmentFunding appointmentFunding) {
110            super.refreshBCAFLine(appointmentFunding);
111    
112            appointmentFunding.refreshReferenceObject(BCPropertyConstants.BUDGET_CONSTRUCTION_INTENDED_INCUMBENT);
113            appointmentFunding.refreshReferenceObject(BCPropertyConstants.BUDGET_CONSTRUCTION_POSITION);
114            appointmentFunding.refreshReferenceObject(BCPropertyConstants.BUDGET_CONSTRUCTION_ADMINISTRATIVE_POST);
115        }
116    
117        /**
118         * acquire position and funding locks for all appointment fundings
119         */
120        public boolean acquirePositionAndFundingLocks(MessageMap errorMap) {
121            List<PendingBudgetConstructionAppointmentFunding> appointmentFundings = this.getAppointmentFundings();
122            for (PendingBudgetConstructionAppointmentFunding appointmentFunding : appointmentFundings) {
123                boolean gotLocks = this.acquirePositionAndFundingLocks(appointmentFunding, errorMap);
124    
125                if (!gotLocks) {
126                    return false;
127                }
128            }
129            return true;
130        }
131    
132        /**
133         * acquire position and funding locks for the given appointment funding
134         * 
135         * @param appointmentFunding the given appointment funding
136         * @return true if the position and funding locks for the given appointment funding are acquired successfully, otherwise, false
137         */
138        public boolean acquirePositionAndFundingLocks(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) {
139            LOG.info("acquirePositionAndFundingLocks() started");
140    
141            try {
142                // not to acquire any lock for the display-only and non-budgetable funding line
143                if (appointmentFunding.isDisplayOnlyMode() || !appointmentFunding.isBudgetable()) {
144                    return true;
145                }
146    
147                // acquire position lock for the current funding line
148                BudgetConstructionPosition position = appointmentFunding.getBudgetConstructionPosition();
149                String positionNumber = position.getPositionNumber();
150                Integer universityFiscalYear = position.getUniversityFiscalYear();
151                String principalId = this.getPerson().getPrincipalId();
152                Boolean positionWasAlreadyLocked = lockService.isPositionLockedByUser(positionNumber, universityFiscalYear, principalId);
153                if (!positionWasAlreadyLocked) {
154                    BudgetConstructionLockStatus positionLockingStatus = lockService.lockPosition(position, this.getPerson());
155                    if (!LockStatus.SUCCESS.equals(positionLockingStatus.getLockStatus())) {
156                        errorMap.putError(BCPropertyConstants.NEW_BCAF_LINE, BCKeyConstants.ERROR_FAIL_TO_LOCK_POSITION, position.toString());
157    
158                        // gwp - added if test, unlock all others only when initially loading the screen
159                        // not during the add line action
160                        if (!appointmentFunding.isNewLineIndicator()) {
161                            this.releasePositionAndFundingLocks();
162                        }
163                        return false;
164                    }
165                }
166    
167                // acquire funding lock for the current funding line
168                BudgetConstructionLockStatus fundingLockingStatus = this.getLockStatusForBudgetByAccountMode(appointmentFunding);
169                if (fundingLockingStatus == null) {
170                    fundingLockingStatus = lockService.lockFunding(appointmentFunding, this.getPerson());
171                }
172    
173                if (!LockStatus.SUCCESS.equals(fundingLockingStatus.getLockStatus())) {
174                    errorMap.putError(BCPropertyConstants.NEW_BCAF_LINE, BCKeyConstants.ERROR_FAIL_TO_LOCK_FUNDING, appointmentFunding.getAppointmentFundingString());
175    
176                    // gwp - added if test, unlock all others only when initially loading the screen
177                    // not during the add line action
178                    if (!appointmentFunding.isNewLineIndicator()) {
179                        this.releasePositionAndFundingLocks();
180                    }
181                    else {
182                        // adding a new line, just release the earlier position lock
183                        // if we just issued it above, not from other line
184                        if (!positionWasAlreadyLocked) {
185                            lockService.unlockPosition(positionNumber, universityFiscalYear, principalId);
186                        }
187                    }
188                    return false;
189                }
190            }
191            catch (Exception e) {
192                this.releasePositionAndFundingLocks();
193    
194                String errorMessage = "Failed when acquiring position/funding lock for " + appointmentFunding;
195                LOG.error(errorMessage, e);
196                throw new RuntimeException(errorMessage, e);
197            }
198    
199            return true;
200        }
201    
202        /**
203         * update the access modes of all appointment fundings
204         */
205        public boolean updateAccessMode(MessageMap errorMap) {
206            List<PendingBudgetConstructionAppointmentFunding> appointmentFundings = this.getAppointmentFundings();
207            for (PendingBudgetConstructionAppointmentFunding appointmentFunding : appointmentFundings) {
208                boolean accessModeUpdated = this.updateAccessMode(appointmentFunding, errorMap);
209    
210                if (!accessModeUpdated) {
211                    return false;
212                }
213            }
214            return true;
215        }
216    
217        /**
218         * update the access mode of the given appointment funding
219         * 
220         * @param appointmentFunding the given appointment funding
221         * @return true if the access mode of the given appointment funding are updated successfully, otherwise, false
222         */
223        public boolean updateAccessMode(PendingBudgetConstructionAppointmentFunding appointmentFunding, MessageMap errorMap) {
224            LOG.info("updateAccessMode() started");
225    
226            try {
227                SalarySettingFieldsHolder fieldsHolder = this.getSalarySettingFieldsHolder();
228    
229                // update the access flags of the current funding line
230                boolean updated = salarySettingService.updateAccessOfAppointmentFunding(appointmentFunding, fieldsHolder, this.isBudgetByAccountMode(), this.isEditAllowed(), this.getPerson());
231                if (!updated) {
232                    errorMap.putError(BCPropertyConstants.NEW_BCAF_LINE, BCKeyConstants.ERROR_FAIL_TO_UPDATE_FUNDING_ACCESS, appointmentFunding.getAppointmentFundingString());
233                    return false;
234                }
235            }
236            catch (Exception e) {
237                String errorMessage = "Failed to update the access mode of " + appointmentFunding + ".";
238                LOG.error(errorMessage, e);
239                throw new RuntimeException(errorMessage, e);
240            }
241    
242            return true;
243        }
244    
245        /**
246         * acquire transaction locks for the savable appointment fundings
247         * 
248         * @return true if the transaction locks for all savable appointment fundings are acquired successfully, otherwise, false
249         */
250        public boolean acquireTransactionLocks(MessageMap messageMap) {
251            LOG.info("acquireTransactionLocks() started");
252    
253            for (PendingBudgetConstructionAppointmentFunding appointmentFunding : this.getSavableAppointmentFundings()) {
254                try {
255                    BudgetConstructionLockStatus transactionLockStatus = this.getLockStatusForBudgetByAccountMode(appointmentFunding);
256                    if (transactionLockStatus == null) {
257                        transactionLockStatus = lockService.lockTransaction(appointmentFunding, this.getPerson());
258                    }
259    
260                    if (!LockStatus.SUCCESS.equals(transactionLockStatus.getLockStatus())) {
261                        messageMap.putError(BCPropertyConstants.NEW_BCAF_LINE, BCKeyConstants.ERROR_FAIL_TO_ACQUIRE_TRANSACTION_LOCK, appointmentFunding.getAppointmentFundingString());
262    
263                        this.releaseTransactionLocks();
264                        return false;
265                    }
266                }
267                catch (Exception e) {
268                    this.releaseTransactionLocks();
269                    this.releasePositionAndFundingLocks();
270    
271                    LOG.error("Failed when acquiring transaction lock for " + appointmentFunding, e);
272                    throw new RuntimeException("Failed when acquiring transaction lock for " + appointmentFunding, e);
273                }
274            }
275    
276            return true;
277        }
278    
279        /**
280         * release all position and funding locks acquired in current action by the current user
281         */
282        public void releasePositionAndFundingLocks() {
283            LOG.info("releasePositionAndFundingLocks() started");
284    
285            List<PendingBudgetConstructionAppointmentFunding> releasableAppointmentFundings = this.getReleasableAppointmentFundings();
286            lockService.unlockFunding(releasableAppointmentFundings, this.getPerson());
287    
288            Set<BudgetConstructionPosition> lockedPositionSet = new HashSet<BudgetConstructionPosition>();
289            for (PendingBudgetConstructionAppointmentFunding fundingLine : releasableAppointmentFundings) {
290                lockedPositionSet.add(fundingLine.getBudgetConstructionPosition());
291                LOG.info("fundingLine: " + fundingLine);
292            }
293    
294            LOG.info("releasePositionAndFundingLocks()" + lockedPositionSet);
295            List<BudgetConstructionPosition> lockedPositions = new ArrayList<BudgetConstructionPosition>();
296            lockedPositions.addAll(lockedPositionSet);
297            lockService.unlockPostion(lockedPositions, this.getPerson());
298            for (BudgetConstructionPosition position : lockedPositionSet) {
299                LOG.info("fundingLine: " + position.getPositionLockUserIdentifier());
300            }
301        }
302    
303        /**
304         * release all the transaction locks acquired in current action by the current user
305         */
306        public void releaseTransactionLocks() {
307            LOG.info("releaseTransactionLocks() started");
308    
309            List<PendingBudgetConstructionAppointmentFunding> fundingsWithTransactionLocks = this.getReleasableAppointmentFundings();
310            for (PendingBudgetConstructionAppointmentFunding appointmentFunding : fundingsWithTransactionLocks) {
311                lockService.unlockTransaction(appointmentFunding, this.getPerson());
312            }
313        }
314    
315        /**
316         * get the appointment fundings that can be saved
317         */
318        public List<PendingBudgetConstructionAppointmentFunding> getSavableAppointmentFundings() {
319            LOG.info("getSavableAppointmentFundings() started");
320    
321            // get the funding lines that can be saved
322            List<PendingBudgetConstructionAppointmentFunding> savableAppointmentFundings = new ArrayList<PendingBudgetConstructionAppointmentFunding>();
323            for (PendingBudgetConstructionAppointmentFunding fundingLine : this.getAppointmentFundings()) {
324    
325                // save-able line is one that is edit-able
326                // rules should catch attempts to save active, !purged, !isBudgetable lines
327                if (!fundingLine.isDisplayOnlyMode()) {
328                    savableAppointmentFundings.add(fundingLine);
329                }
330            }
331            return savableAppointmentFundings;
332        }
333    
334        /**
335         * get the appointment fundings for which the position or funding locks can be released
336         */
337        public List<PendingBudgetConstructionAppointmentFunding> getReleasableAppointmentFundings() {
338            LOG.info("getReleasableAppointmentFundings() started");
339    
340            List<PendingBudgetConstructionAppointmentFunding> savableAppointmentFundings = this.getSavableAppointmentFundings();
341            List<PendingBudgetConstructionAppointmentFunding> releasableAppointmentFundings = new ArrayList<PendingBudgetConstructionAppointmentFunding>();
342            releasableAppointmentFundings.addAll(savableAppointmentFundings);
343    
344            return releasableAppointmentFundings;
345        }
346    
347        /**
348         * determine whether there is any active funding line in the given savable appointment funding lines
349         */
350        public List<PendingBudgetConstructionAppointmentFunding> getActiveFundingLines() {
351            LOG.info("getActiveFundingLines() started");
352    
353            List<PendingBudgetConstructionAppointmentFunding> activeFundingLines = new ArrayList<PendingBudgetConstructionAppointmentFunding>();
354            for (PendingBudgetConstructionAppointmentFunding appointmentFunding : this.getSavableAppointmentFundings()) {
355                if (!appointmentFunding.isAppointmentFundingDeleteIndicator()) {
356                    activeFundingLines.add(appointmentFunding);
357                }
358            }
359            return activeFundingLines;
360        }
361    
362        /**
363         * sets the default fields not setable by the user for added lines and any other required initialization
364         * 
365         * @param appointmentFunding the given appointment funding line
366         */
367        public PendingBudgetConstructionAppointmentFunding createNewAppointmentFundingLine() {
368            PendingBudgetConstructionAppointmentFunding appointmentFunding = new PendingBudgetConstructionAppointmentFunding();
369    
370            if (this.isAddLine() || this.isSingleAccountMode()) {
371                appointmentFunding.setChartOfAccountsCode(this.getChartOfAccountsCode());
372                appointmentFunding.setAccountNumber(this.getAccountNumber());
373    
374                // empty field implies dashes and is fixed in add action
375                if (this.getSubAccountNumber().equals(KFSConstants.getDashSubAccountNumber())) {
376                    appointmentFunding.setSubAccountNumber(KFSConstants.EMPTY_STRING);
377                }
378                else {
379                    appointmentFunding.setSubAccountNumber(this.getSubAccountNumber());
380                }
381                appointmentFunding.setFinancialObjectCode(this.getFinancialObjectCode());
382    
383                // empty field implies dashes and is fixed in add action
384                if (this.getFinancialSubObjectCode().equals(KFSConstants.getDashFinancialSubObjectCode())) {
385                    appointmentFunding.setFinancialSubObjectCode(KFSConstants.EMPTY_STRING);
386                }
387                else {
388                    appointmentFunding.setFinancialSubObjectCode(this.getFinancialSubObjectCode());
389                }
390            }
391    
392            appointmentFunding.setUniversityFiscalYear(this.getUniversityFiscalYear());
393            appointmentFunding.setAppointmentFundingDeleteIndicator(false);
394            appointmentFunding.setNewLineIndicator(true);
395            appointmentFunding.setAppointmentFundingDurationCode(BCConstants.AppointmentFundingDurationCodes.NONE.durationCode);
396    
397            return appointmentFunding;
398        }
399    
400        /**
401         * pick up the appointment fundings belonging to the specified account from a collection of fundings that are associated with a
402         * position/incumbent
403         */
404        public void pickAppointmentFundingsForSingleAccount() {
405            LOG.info("pickAppointmentFundingsForSingleAccount() started");
406    
407            List<PendingBudgetConstructionAppointmentFunding> excludedFundings = new ArrayList<PendingBudgetConstructionAppointmentFunding>();
408            for (PendingBudgetConstructionAppointmentFunding appointmentFunding : this.getAppointmentFundings()) {
409                if (!ObjectUtil.equals(appointmentFunding, this, comparableFields)) {
410                    excludedFundings.add(appointmentFunding);
411                }
412            }
413    
414            this.getAppointmentFundings().removeAll(excludedFundings);
415        }
416    
417        /**
418         * Funding/transaction locks are not required for the lines associated with a document already open in budget by account mode
419         */
420        private BudgetConstructionLockStatus getLockStatusForBudgetByAccountMode(PendingBudgetConstructionAppointmentFunding appointmentFunding) {
421            LOG.info("getLockStatusForBudgetByAccountMode() started");
422    
423            BudgetConstructionLockStatus transactionLockStatus = null;
424    
425            if (this.isBudgetByAccountMode() && ObjectUtil.equals(appointmentFunding, this, comparableFields)) {
426                transactionLockStatus = new BudgetConstructionLockStatus();
427                transactionLockStatus.setLockStatus(LockStatus.SUCCESS);
428            }
429    
430            return transactionLockStatus;
431        }
432    
433        /**
434         * get the names of comparable fields that are considered to determine a single account, that is, the fundings are considered
435         * being assocated with the given account if they have the same values of the fields as specified.
436         */
437        public static List<String> getComparableFields() {
438            List<String> comparableFields = new ArrayList<String>();
439            comparableFields.add(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE);
440            comparableFields.add(KFSPropertyConstants.ACCOUNT_NUMBER);
441            comparableFields.add(KFSPropertyConstants.SUB_ACCOUNT_NUMBER);
442    
443            return comparableFields;
444        }
445    
446        /**
447         * determine whether the editing mode for detail salary setting is in single account mode or not
448         */
449        private boolean resetSingleAccountModeFlag() {
450    
451            List<Organization> processorOrgs = SpringContext.getBean(BudgetConstructionProcessorService.class).getProcessorOrgs(this.getPerson());
452            Boolean isOrgApprover = processorOrgs != null && !processorOrgs.isEmpty();
453    
454            if (this.isBudgetByAccountMode()) {
455    
456                Account account = new Account();
457                account.setAccountNumber(this.getAccountNumber());
458                account.setChartOfAccountsCode(this.getChartOfAccountsCode());
459                account = (Account) businessObjectService.retrieve(account);
460    
461                RoleManagementService roleService = SpringContext.getBean(RoleManagementService.class);
462                AttributeSet qualification = new AttributeSet();
463                qualification.put(KfsKimAttributes.CHART_OF_ACCOUNTS_CODE, getChartOfAccountsCode());
464                qualification.put(KfsKimAttributes.ACCOUNT_NUMBER, getAccountNumber());
465                qualification.put(KfsKimAttributes.DOCUMENT_TYPE_NAME, BCConstants.BUDGET_CONSTRUCTION_DOCUMENT_NAME);
466    
467                List<String> roleId = new ArrayList<String>();
468                roleId.add(roleService.getRoleIdByName(KFSConstants.ParameterNamespaces.KFS, KFSConstants.SysKimConstants.FISCAL_OFFICER_KIM_ROLE_NAME));
469    
470                Boolean isFiscalOfficerOrDelegate = roleService.principalHasRole(getPerson().getPrincipalId(), roleId, qualification);
471    
472                return (isFiscalOfficerOrDelegate && !isOrgApprover);
473            }
474    
475            // instruct the detail salary setting by multiple account mode if current user is an organization level approver
476            if (isOrgApprover) {
477                return false;
478            }
479            else {
480                throw new RuntimeException("Access denied: not authorized to do the detail salary setting");
481            }
482        }
483    
484        /**
485         * Gets the newBCAFLine attribute.
486         * 
487         * @return Returns the newBCAFLine.
488         */
489        public PendingBudgetConstructionAppointmentFunding getNewBCAFLine() {
490            return newBCAFLine;
491        }
492    
493        /**
494         * Sets the newBCAFLine attribute value.
495         * 
496         * @param newBCAFLine The newBCAFLine to set.
497         */
498        public void setNewBCAFLine(PendingBudgetConstructionAppointmentFunding newBCAFLine) {
499            this.newBCAFLine = newBCAFLine;
500        }
501    
502        /**
503         * Gets the emplid attribute.
504         * 
505         * @return Returns the emplid.
506         */
507        public String getEmplid() {
508            return emplid;
509        }
510    
511        /**
512         * Sets the emplid attribute value.
513         * 
514         * @param emplid The emplid to set.
515         */
516        public void setEmplid(String emplid) {
517            this.emplid = emplid;
518        }
519    
520        /**
521         * Gets the addLine attribute.
522         * 
523         * @return Returns the addLine.
524         */
525        public boolean isAddLine() {
526            return addLine;
527        }
528    
529        /**
530         * Sets the addLine attribute value.
531         * 
532         * @param addLine The addLine to set.
533         */
534        public void setAddLine(boolean addLine) {
535            this.addLine = addLine;
536        }
537    
538        /**
539         * Gets the positionNumber attribute.
540         * 
541         * @return Returns the positionNumber.
542         */
543        public String getPositionNumber() {
544            return positionNumber;
545        }
546    
547        /**
548         * Sets the positionNumber attribute value.
549         * 
550         * @param positionNumber The positionNumber to set.
551         */
552        public void setPositionNumber(String positionNumber) {
553            this.positionNumber = positionNumber;
554        }
555    
556        /**
557         * Gets the name attribute.
558         * 
559         * @return Returns the name.
560         */
561        public String name() {
562            return name;
563        }
564    
565        /**
566         * Sets the name attribute value.
567         * 
568         * @param name The name to set.
569         */
570        public void setName(String name) {
571            this.name = name;
572        }
573    
574        /**
575         * @see org.kuali.rice.kns.web.struts.form.KualiForm#shouldPropertyBePopulatedInForm(java.lang.String,
576         *      javax.servlet.http.HttpServletRequest)
577         */
578        @Override
579        public boolean shouldPropertyBePopulatedInForm(String requestParameterName, HttpServletRequest request) {
580    
581            if (super.shouldPropertyBePopulatedInForm(requestParameterName, request)) {
582                return true;
583            }
584            else {
585                // make sure special disabled fields are allowed to be populated
586                if (requestParameterName.endsWith(BCPropertyConstants.APPOINTMENT_REQUESTED_CSF_AMOUNT) || requestParameterName.endsWith(BCPropertyConstants.APPOINTMENT_REQUESTED_CSF_TIME_PERCENT) || requestParameterName.endsWith(BCPropertyConstants.APPOINTMENT_FUNDING_REASON_AMOUNT)) {
587                    return true;
588                }
589                else {
590                    return false;
591                }
592            }
593        }
594    }