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.endow.document.validation.impl;
017    
018    import java.math.BigDecimal;
019    
020    import org.apache.commons.lang.StringUtils;
021    import org.kuali.kfs.module.endow.EndowConstants;
022    import org.kuali.kfs.module.endow.EndowKeyConstants;
023    import org.kuali.kfs.module.endow.EndowPropertyConstants;
024    import org.kuali.kfs.module.endow.businessobject.ClassCode;
025    import org.kuali.kfs.module.endow.businessobject.EndowmentSourceTransactionLine;
026    import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionLine;
027    import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionSecurity;
028    import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionTaxLotLine;
029    import org.kuali.kfs.module.endow.businessobject.RegistrationCode;
030    import org.kuali.kfs.module.endow.businessobject.Security;
031    import org.kuali.kfs.module.endow.document.EndowmentSecurityDetailsDocument;
032    import org.kuali.kfs.module.endow.document.EndowmentTransactionalDocument;
033    import org.kuali.kfs.module.endow.document.service.RegistrationCodeService;
034    import org.kuali.kfs.module.endow.document.service.SecurityService;
035    import org.kuali.kfs.sys.context.SpringContext;
036    import org.kuali.rice.kns.document.Document;
037    import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
038    import org.kuali.rice.kns.rules.TransactionalDocumentRuleBase;
039    import org.kuali.rice.kns.util.GlobalVariables;
040    import org.kuali.rice.kns.util.KNSConstants;
041    import org.kuali.rice.kns.util.ObjectUtils;
042    
043    public class EndowmentTransactionalDocumentBaseRule extends TransactionalDocumentRuleBase {
044        /**
045         * This method is a convenience method to easily add a Document level error (ie, one not tied to a specific field, but
046         * applicable to the whole document).
047         * 
048         * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
049         */
050        protected void putGlobalError(String errorConstant) {
051            if (!errorAlreadyExists(KNSConstants.DOCUMENT_ERRORS, errorConstant)) {
052                GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(KNSConstants.DOCUMENT_ERRORS, errorConstant);
053            }
054        }
055    
056        /**
057         * This method is a convenience method to easily add a Document level error (ie, one not tied to a specific field, but
058         * applicable to the whole document).
059         * 
060         * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
061         * @param parameter - Replacement value for part of the error message.
062         */
063        protected void putGlobalError(String errorConstant, String parameter) {
064            if (!errorAlreadyExists(KNSConstants.DOCUMENT_ERRORS, errorConstant)) {
065                GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(KNSConstants.DOCUMENT_ERRORS, errorConstant, parameter);
066            }
067        }
068    
069        /**
070         * This method is a convenience method to easily add a Document level error (ie, one not tied to a specific field, but
071         * applicable to the whole document).
072         * 
073         * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
074         * @param parameters - Array of replacement values for part of the error message.
075         */
076        protected void putGlobalError(String errorConstant, String[] parameters) {
077            if (!errorAlreadyExists(KNSConstants.DOCUMENT_ERRORS, errorConstant)) {
078                GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(KNSConstants.DOCUMENT_ERRORS, errorConstant, parameters);
079            }
080        }
081    
082        /**
083         * This method is a convenience method to add a property-specific error to the global errors list. This method makes sure that
084         * the correct prefix is added to the property name so that it will display correctly on maintenance documents.
085         * 
086         * @param propertyName - Property name of the element that is associated with the error. Used to mark the field as errored in
087         *        the UI.
088         * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
089         */
090        protected void putFieldError(String propertyName, String errorConstant) {
091            if (!errorAlreadyExists(propertyName, errorConstant)) {
092                GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(propertyName, errorConstant);
093            }
094        }
095    
096        /**
097         * This method is a convenience method to add a property-specific error to the global errors list. This method makes sure that
098         * the correct prefix is added to the property name so that it will display correctly on maintenance documents.
099         * 
100         * @param propertyName - Property name of the element that is associated with the error. Used to mark the field as errored in
101         *        the UI.
102         * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
103         * @param parameter - Single parameter value that can be used in the message so that you can display specific values to the
104         *        user.
105         */
106        protected void putFieldError(String propertyName, String errorConstant, String parameter) {
107            if (!errorAlreadyExists(propertyName, errorConstant)) {
108                GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(propertyName, errorConstant, parameter);
109            }
110        }
111    
112        /**
113         * This method is a convenience method to add a property-specific error to the global errors list. This method makes sure that
114         * the correct prefix is added to the property name so that it will display correctly on maintenance documents.
115         * 
116         * @param propertyName - Property name of the element that is associated with the error. Used to mark the field as errored in
117         *        the UI.
118         * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
119         * @param parameters - Array of strings holding values that can be used in the message so that you can display specific values
120         *        to the user.
121         */
122        protected void putFieldError(String propertyName, String errorConstant, String[] parameters) {
123            if (!errorAlreadyExists(propertyName, errorConstant)) {
124                GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(propertyName, errorConstant, parameters);
125            }
126        }
127    
128        /**
129         * This method is a convenience method to add a property-specific document error to the global errors list. This method makes
130         * sure that the correct prefix is added to the property name so that it will display correctly on maintenance documents.
131         * 
132         * @param propertyName - Property name of the element that is associated with the error. Used to mark the field as errored in
133         *        the UI.
134         * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
135         * @param parameter - Single parameter value that can be used in the message so that you can display specific values to the
136         *        user.
137         */
138        protected void putDocumentError(String propertyName, String errorConstant, String parameter) {
139            if (!errorAlreadyExists(MaintenanceDocumentRuleBase.DOCUMENT_ERROR_PREFIX + propertyName, errorConstant)) {
140                GlobalVariables.getMessageMap().putError(MaintenanceDocumentRuleBase.DOCUMENT_ERROR_PREFIX + propertyName, errorConstant, parameter);
141            }
142        }
143    
144        /**
145         * This method is a convenience method to add a property-specific document error to the global errors list. This method makes
146         * sure that the correct prefix is added to the property name so that it will display correctly on maintenance documents.
147         * 
148         * @param propertyName - Property name of the element that is associated with the error. Used to mark the field as errored in
149         *        the UI.
150         * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
151         * @param parameters - Array of String parameters that can be used in the message so that you can display specific values to the
152         *        user.
153         */
154        protected void putDocumentError(String propertyName, String errorConstant, String[] parameters) {
155            GlobalVariables.getMessageMap().putError(MaintenanceDocumentRuleBase.DOCUMENT_ERROR_PREFIX + propertyName, errorConstant, parameters);
156        }
157    
158        /**
159         * Convenience method to determine whether the field already has the message indicated. This is useful if you want to suppress
160         * duplicate error messages on the same field.
161         * 
162         * @param propertyName - propertyName you want to test on
163         * @param errorConstant - errorConstant you want to test
164         * @return returns True if the propertyName indicated already has the errorConstant indicated, false otherwise
165         */
166        protected boolean errorAlreadyExists(String propertyName, String errorConstant) {
167    
168            if (GlobalVariables.getMessageMap().fieldHasMessage(propertyName, errorConstant)) {
169                return true;
170            }
171            else {
172                return false;
173            }
174        }
175    
176        /**
177         * This method specifically doesn't put any prefixes before the error so that the developer can do things specific to the
178         * globals errors (like newDelegateChangeDocument errors)
179         * 
180         * @param propertyName
181         * @param errorConstant
182         */
183        protected void putGlobalsError(String propertyName, String errorConstant) {
184            if (!errorAlreadyExists(propertyName, errorConstant)) {
185                GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(propertyName, errorConstant);
186            }
187        }
188    
189        /**
190         * This method specifically doesn't put any prefixes before the error so that the developer can do things specific to the
191         * globals errors (like newDelegateChangeDocument errors)
192         * 
193         * @param propertyName
194         * @param errorConstant
195         * @param parameter
196         */
197        protected void putGlobalsError(String propertyName, String errorConstant, String parameter) {
198            if (!errorAlreadyExists(propertyName, errorConstant)) {
199                GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(propertyName, errorConstant, parameter);
200            }
201        }
202    
203    
204        /**
205         * This method obtains the Prefix for displaying errors on the UI for Source & Target lines.
206         * 
207         * @param document
208         * @param isSource
209         * @return
210         */
211        protected String getEndowmentTransactionSecurityPrefix(EndowmentTransactionalDocument document, boolean isSource) {
212            if (isSource)
213                return EndowPropertyConstants.TRANSACTION_SOURCE_SECURITY_PREFIX;
214            else
215                return EndowPropertyConstants.TRANSACTION_TARGET_SECURITY_PREFIX;
216        }
217    
218        /**
219         * This method returns the Security line associated with a Transaction.
220         * 
221         * @param document
222         * @param isSource
223         * @return
224         */
225        protected EndowmentTransactionSecurity getEndowmentTransactionSecurity(EndowmentTransactionalDocument document, boolean isSource) {
226            if (isSource)
227                return ((EndowmentSecurityDetailsDocument) document).getSourceTransactionSecurity();
228            else
229                return ((EndowmentSecurityDetailsDocument) document).getTargetTransactionSecurity();
230        }
231    
232        /**
233         * This method validate the Security code.
234         * 
235         * @param tranSecurity
236         * @return
237         */
238        protected boolean isSecurityCodeEmpty(EndowmentTransactionalDocument document, boolean isSource) {
239            EndowmentTransactionSecurity tranSecurity = getEndowmentTransactionSecurity(document, isSource);
240    
241            if (StringUtils.isEmpty(tranSecurity.getSecurityID())) {
242                putFieldError(getEndowmentTransactionSecurityPrefix(document, isSource) + EndowPropertyConstants.TRANSACTION_SECURITY_ID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_SECURITY_REQUIRED);
243                return true;
244            }
245    
246            return false;
247        }
248    
249        /**
250         * This method validates the Registration code.
251         * 
252         * @param tranSecurity
253         * @return
254         */
255        protected boolean isRegistrationCodeEmpty(EndowmentTransactionalDocument document, boolean isSource) {
256            EndowmentTransactionSecurity tranSecurity = getEndowmentTransactionSecurity(document, isSource);
257    
258            if (StringUtils.isEmpty(tranSecurity.getRegistrationCode())) {
259                putFieldError(getEndowmentTransactionSecurityPrefix(document, isSource) + EndowPropertyConstants.TRANSACTION_REGISTRATION_ID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_REGISTRATION_CODE_REQUIRED);
260                return true;
261            }
262    
263            return false;
264        }
265    
266    
267        /**
268         * This method validates the Security code by trying to create a Security object from the code.
269         * 
270         * @param document
271         * @param isSource
272         * @return
273         */
274        protected boolean validateSecurityCode(EndowmentSecurityDetailsDocument document, boolean isSource) {
275            boolean success = true;
276            String prefix = null;
277    
278            EndowmentTransactionSecurity tranSecurity = getEndowmentTransactionSecurity(document, isSource);
279    
280            Security security = (Security) SpringContext.getBean(SecurityService.class).getByPrimaryKey(tranSecurity.getSecurityID());
281            tranSecurity.setSecurity(security);
282            if (null == security) {
283                putFieldError(getEndowmentTransactionSecurityPrefix(document, isSource) + EndowPropertyConstants.TRANSACTION_SECURITY_ID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_SECURITY_INVALID);
284                success = false;
285            }
286    
287            return success;
288        }
289    
290        /**
291         * This method validates the Registration code by trying to create a RegistrationCode object from the code.
292         * 
293         * @param document
294         * @param isSource
295         * @return
296         */
297        protected boolean validateRegistrationCode(EndowmentSecurityDetailsDocument document, boolean isSource) {
298            boolean success = true;
299            String prefix = null;
300    
301            EndowmentTransactionSecurity tranSecurity = getEndowmentTransactionSecurity(document, isSource);
302    
303            RegistrationCode registrationCode = (RegistrationCode) SpringContext.getBean(RegistrationCodeService.class).getByPrimaryKey(tranSecurity.getRegistrationCode());
304            tranSecurity.setRegistrationCodeObj(registrationCode);
305            if (null == registrationCode) {
306                putFieldError(getEndowmentTransactionSecurityPrefix(document, isSource) + EndowPropertyConstants.TRANSACTION_REGISTRATION_ID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_REGISTRATION_CODE_INVALID);
307                success = false;
308            }
309    
310            return success;
311        }
312    
313        /**
314         * This method checks if the Security is Active.
315         * 
316         * @param document
317         * @param isSource
318         * @return
319         */
320        protected boolean isSecurityActive(EndowmentSecurityDetailsDocument document, boolean isSource) {
321            EndowmentTransactionSecurity tranSecurity = getEndowmentTransactionSecurity(document, isSource);
322    
323            if (tranSecurity.getSecurity().isActive())
324                return true;
325            else {
326                putFieldError(getEndowmentTransactionSecurityPrefix(document, isSource) + EndowPropertyConstants.TRANSACTION_SECURITY_ID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_SECURITY_INACTIVE);
327                return false;
328            }
329        }
330    
331        /**
332         * Validates that the security class code type is not Liability.
333         * 
334         * @param endowmentTransactionSecurity
335         * @return true is valid, false otherwise
336         */
337        protected boolean validateSecurityClassCodeTypeNotLiability(EndowmentSecurityDetailsDocument document, boolean isSource) {
338            boolean isValid = true;
339            EndowmentTransactionSecurity endowmentTransactionSecurity = getEndowmentTransactionSecurity(document, isSource);
340            Security security = endowmentTransactionSecurity.getSecurity();
341            if (ObjectUtils.isNotNull(security)) {
342                ClassCode classCode = security.getClassCode();
343                if (ObjectUtils.isNotNull(classCode)) {
344                    String classCodeType = classCode.getClassCodeType();
345                    if (EndowConstants.ClassCodeTypes.LIABILITY.equalsIgnoreCase(classCodeType)) {
346                        isValid = false;
347    
348                        if (isSource) {
349                            putFieldError(EndowPropertyConstants.TRANSACTION_SOURCE_SECURITY_PREFIX + EndowPropertyConstants.TRANSACTION_SECURITY_ID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_SECURITY_NOT_LIABILITY);
350                        }
351                        else {
352                            putFieldError(EndowPropertyConstants.TRANSACTION_TARGET_SECURITY_PREFIX + EndowPropertyConstants.TRANSACTION_SECURITY_ID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_SECURITY_NOT_LIABILITY);
353                        }
354                    }
355                }
356            }
357    
358            return isValid;
359    
360        }
361    
362        /**
363         * This method checks if the Registration Code is Active.
364         * 
365         * @param document
366         * @param isSource
367         * @return
368         */
369        protected boolean isRegistrationCodeActive(EndowmentSecurityDetailsDocument document, boolean isSource) {
370            EndowmentTransactionSecurity tranSecurity = getEndowmentTransactionSecurity(document, isSource);
371    
372            if (tranSecurity.getRegistrationCodeObj().isActive())
373                return true;
374            else {
375                putFieldError(getEndowmentTransactionSecurityPrefix(document, isSource) + EndowPropertyConstants.TRANSACTION_REGISTRATION_ID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_REGISTRATION_CODE_INACTIVE);
376                return false;
377            }
378        }
379    
380        /**
381         * This method validates the Security Class Type Code.
382         * 
383         * @param document
384         * @param isSource
385         * @param classCodeType
386         * @return
387         */
388        protected boolean validateSecurityClassTypeCode(EndowmentSecurityDetailsDocument document, boolean isSource, String classCodeType) {
389            EndowmentTransactionSecurity tranSecurity = getEndowmentTransactionSecurity(document, isSource);
390            tranSecurity.getSecurity().refreshNonUpdateableReferences();
391    
392            if (tranSecurity.getSecurity().getClassCode().getClassCodeType().equalsIgnoreCase(classCodeType))
393                return true;
394            else {
395                putFieldError(getEndowmentTransactionSecurityPrefix(document, isSource) + EndowPropertyConstants.TRANSACTION_SECURITY_ID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_SECURITY_CLASS_CODE_MISMATCH);
396                return false;
397            }
398        }
399    
400        /**
401         * @see org.kuali.rice.kns.rules.DocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.Document)
402         */
403        @Override
404        protected boolean processCustomRouteDocumentBusinessRules(Document document) {
405            boolean isValid = super.processCustomSaveDocumentBusinessRules(document);
406            isValid &= !GlobalVariables.getMessageMap().hasErrors();
407    
408            EndowmentTransactionalDocument endowmentTransactionalDocument = null;
409    
410            if (isValid) {
411                endowmentTransactionalDocument = (EndowmentTransactionalDocument) document;
412    
413                // Validates Tx Sub Type Code
414                isValid &= isSubTypeEmpty(endowmentTransactionalDocument);
415            }
416    
417            return GlobalVariables.getMessageMap().getErrorCount() == 0;
418        }
419    
420        /**
421         * This method validates the Sub Type Code.
422         * 
423         * @param document
424         * @return
425         */
426        protected boolean isSubTypeEmpty(EndowmentTransactionalDocument document) {
427            boolean success = true;
428    
429            if (StringUtils.isEmpty(document.getTransactionSubTypeCode())) {
430                putFieldError(EndowConstants.TRANSACTION_DETAILS_ERRORS, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_DETAILS_SUB_TYPE_REQUIRED);
431                success = false;
432            }
433    
434            return success;
435        }
436    
437    }