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.gl.businessobject.inquiry;
017
018 import java.util.ArrayList;
019 import java.util.HashMap;
020 import java.util.Iterator;
021 import java.util.List;
022 import java.util.Map;
023 import java.util.Properties;
024
025 import org.apache.commons.lang.StringUtils;
026 import org.kuali.kfs.gl.Constant;
027 import org.kuali.kfs.gl.businessobject.AccountBalance;
028 import org.kuali.kfs.gl.businessobject.lookup.BusinessObjectFieldConverter;
029 import org.kuali.kfs.sys.KFSConstants;
030 import org.kuali.kfs.sys.KFSPropertyConstants;
031 import org.kuali.kfs.sys.businessobject.inquiry.KfsInquirableImpl;
032 import org.kuali.kfs.sys.context.SpringContext;
033 import org.kuali.rice.kew.doctype.bo.DocumentTypeEBO;
034 import org.kuali.rice.kew.doctype.service.DocumentTypeService;
035 import org.kuali.rice.kew.dto.DocumentTypeDTO;
036 import org.kuali.rice.kns.bo.BusinessObject;
037 import org.kuali.rice.kns.datadictionary.AttributeDefinition;
038 import org.kuali.rice.kns.datadictionary.DataDictionaryEntryBase;
039 import org.kuali.rice.kns.lookup.HtmlData;
040 import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
041 import org.kuali.rice.kns.lookup.LookupUtils;
042 import org.kuali.rice.kns.service.BusinessObjectDictionaryService;
043 import org.kuali.rice.kns.service.DataDictionaryService;
044 import org.kuali.rice.kns.service.PersistenceStructureService;
045 import org.kuali.rice.kns.util.KNSConstants;
046 import org.kuali.rice.kns.util.ObjectUtils;
047 import org.kuali.rice.kns.util.UrlFactory;
048
049 /**
050 * This class is the template class for the customized inqurable implementations used to generate balance inquiry screens.
051 */
052 public abstract class AbstractGeneralLedgerInquirableImpl extends KfsInquirableImpl {
053 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AbstractGeneralLedgerInquirableImpl.class);
054
055 private BusinessObject businessObject;
056
057 /**
058 * @see org.kuali.kfs.sys.businessobject.inquiry.KfsInquirableImpl#getInquiryUrl(org.kuali.rice.kns.bo.BusinessObject, java.lang.String, boolean)
059 */
060 @Override
061 public HtmlData getInquiryUrl(BusinessObject businessObject, String attributeName, boolean forceInquiry) {
062 return this.getInquiryUrl(businessObject, attributeName);
063 }
064
065 /**
066 * Helper method to build an inquiry url for a result field.
067 *
068 * @param businessObject the business object instance to build the urls for
069 * @param attributeName the attribute name which links to an inquirable
070 * @return String url to inquiry
071 */
072 public HtmlData getInquiryUrl(BusinessObject businessObject, String attributeName) {
073 this.setBusinessObject(businessObject);
074 AnchorHtmlData inquiryHref = new AnchorHtmlData(KNSConstants.EMPTY_STRING, KNSConstants.EMPTY_STRING);
075 BusinessObjectDictionaryService businessDictionary = SpringContext.getBean(BusinessObjectDictionaryService.class);
076 PersistenceStructureService persistenceStructureService = SpringContext.getBean(PersistenceStructureService.class);
077
078 String baseUrl = KFSConstants.INQUIRY_ACTION;
079 Properties parameters = new Properties();
080 parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.START_METHOD);
081
082 Object attributeValue = null;
083 Class inquiryBusinessObjectClass = null;
084 String attributeRefName = "";
085 boolean isPkReference = false;
086
087 Map userDefinedAttributeMap = getUserDefinedAttributeMap();
088 boolean isUserDefinedAttribute = userDefinedAttributeMap == null ? false : userDefinedAttributeMap.containsKey(attributeName);
089
090 // determine the type of the given attribute: user-defined, regular, nested-referenced or primitive reference
091 if (isUserDefinedAttribute) {
092 attributeName = getAttributeName(attributeName);
093 inquiryBusinessObjectClass = getInquiryBusinessObjectClass(attributeName);
094 isPkReference = true;
095 }
096 else if (attributeName.equals(businessDictionary.getTitleAttribute(businessObject.getClass()))) {
097 inquiryBusinessObjectClass = businessObject.getClass();
098 isPkReference = true;
099 }
100 else if (ObjectUtils.isNestedAttribute(attributeName)) {
101 if (!"financialObject.financialObjectType.financialReportingSortCode".equals(attributeName)) {
102 inquiryBusinessObjectClass = LookupUtils.getNestedReferenceClass(businessObject, attributeName);
103 }
104 else {
105 return inquiryHref;
106 }
107 }
108 else {
109 Map primitiveReference = LookupUtils.getPrimitiveReference(businessObject, attributeName);
110 if (primitiveReference != null && !primitiveReference.isEmpty()) {
111 attributeRefName = (String) primitiveReference.keySet().iterator().next();
112 inquiryBusinessObjectClass = (Class) primitiveReference.get(attributeRefName);
113 }
114 attributeValue = ObjectUtils.getPropertyValue(businessObject, attributeName);
115 attributeValue = (attributeValue == null) ? "" : attributeValue.toString();
116 }
117
118 // process the business object class if the attribute name is not user-defined
119 if (!isUserDefinedAttribute) {
120 if (isExclusiveField(attributeName, attributeValue)) {
121 return inquiryHref;
122 }
123
124 if (inquiryBusinessObjectClass == null || businessDictionary.isInquirable(inquiryBusinessObjectClass) == null || !businessDictionary.isInquirable(inquiryBusinessObjectClass).booleanValue()) {
125 return inquiryHref;
126 }
127 }
128 parameters.put(KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, inquiryBusinessObjectClass.getName());
129
130 List keys = new ArrayList();
131 Map<String,String> inquiryFields = new HashMap<String, String>();
132 if (isUserDefinedAttribute) {
133 baseUrl = getBaseUrl();
134 keys = buildUserDefinedAttributeKeyList();
135
136 parameters.put(KFSConstants.RETURN_LOCATION_PARAMETER, Constant.RETURN_LOCATION_VALUE);
137 parameters.put(KFSConstants.GL_BALANCE_INQUIRY_FLAG, "true");
138 parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.SEARCH_METHOD);
139 parameters.put(KFSConstants.DOC_FORM_KEY, "88888888");
140
141 // add more customized parameters into the current parameter map
142 addMoreParameters(parameters, attributeName);
143 }
144 else if (persistenceStructureService.isPersistable(inquiryBusinessObjectClass)) {
145 keys = persistenceStructureService.listPrimaryKeyFieldNames(inquiryBusinessObjectClass);
146 }
147
148 // build key value url parameters used to retrieve the business object
149 if (keys != null) {
150 for (Iterator keyIterator = keys.iterator(); keyIterator.hasNext();) {
151 String keyName = (String) keyIterator.next();
152
153 // convert the key names based on their formats and types
154 String keyConversion = keyName;
155 if (ObjectUtils.isNestedAttribute(attributeName)) {
156 if (isUserDefinedAttribute) {
157 keyConversion = keyName;
158 }
159 else {
160 keyConversion = ObjectUtils.getNestedAttributePrefix(attributeName) + "." + keyName;
161 }
162 }
163 else {
164 if (isPkReference) {
165 keyConversion = keyName;
166 }
167 else {
168 keyConversion = persistenceStructureService.getForeignKeyFieldName(businessObject.getClass(), attributeRefName, keyName);
169 }
170 }
171
172 Object keyValue = ObjectUtils.getPropertyValue(businessObject, keyConversion);
173 keyValue = (keyValue == null) ? "" : keyValue.toString();
174
175 // convert the key value and name into the given ones
176 Object tempKeyValue = this.getKeyValue(keyName, keyValue);
177 keyValue = tempKeyValue == null ? keyValue : tempKeyValue;
178
179 String tempKeyName = this.getKeyName(keyName);
180 keyName = tempKeyName == null ? keyName : tempKeyName;
181
182 // add the key-value pair into the parameter map
183 if (keyName != null){
184 parameters.put(keyName, keyValue);
185 inquiryFields.put(keyName, keyValue.toString());
186 }
187 }
188 }
189
190 // Hack to make this work. I don't know why it doesn't pick up the whole primary key for these. The last big change to
191 // KualiInquirableImpl
192 // broke all of this
193 if (businessObject instanceof AccountBalance) {
194 AccountBalance ab = (AccountBalance) businessObject;
195 if ("financialObject.financialObjectLevel.financialConsolidationObject.finConsolidationObjectCode".equals(attributeName)) {
196 parameters.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, ab.getChartOfAccountsCode());
197 }
198 else if ("financialObject.financialObjectLevel.financialObjectLevelCode".equals(attributeName)) {
199 parameters.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, ab.getChartOfAccountsCode());
200 }
201 }
202
203 return getHyperLink(inquiryBusinessObjectClass, inquiryFields, UrlFactory.parameterizeUrl(baseUrl, parameters));
204 }
205
206 /**
207 * This method builds the inquiry url for user-defined attribute
208 *
209 * @return a List of attribute keys for the inquiry url
210 */
211 protected abstract List buildUserDefinedAttributeKeyList();
212
213 /**
214 * This method defines the user-defined attribute map
215 *
216 * @return the user-defined attribute map
217 */
218 protected abstract Map getUserDefinedAttributeMap();
219
220 /**
221 * This method finds the matching attribute name of given one
222 *
223 * @param attributeName the given attribute name
224 * @return the attribute name from the given one
225 */
226 protected abstract String getAttributeName(String attributeName);
227
228 /**
229 * This method finds the matching the key value of the given one
230 *
231 * @param keyName the given key name
232 * @param keyValue the given key value
233 * @return the key value from the given key value
234 */
235 protected abstract Object getKeyValue(String keyName, Object keyValue);
236
237 /**
238 * This method finds the matching the key name of the given one
239 *
240 * @param keyName the given key name
241 * @return the key value from the given key name
242 */
243 protected abstract String getKeyName(String keyName);
244
245 /**
246 * This method defines the lookupable implementation attribute name
247 *
248 * @return the lookupable implementation attribute name
249 */
250 protected abstract String getLookupableImplAttributeName();
251
252 /**
253 * This method defines the base inquiry url
254 *
255 * @return the base inquiry url
256 */
257 protected abstract String getBaseUrl();
258
259 /**
260 * This method gets the class name of the inquiry business object for a given attribute.
261 *
262 * @return the class name of the inquiry business object for a given attribute
263 */
264 protected abstract Class getInquiryBusinessObjectClass(String attributeName);
265
266 /**
267 * This method adds more parameters into the curren parameter map
268 *
269 * @param parameter the current parameter map
270 */
271 protected abstract void addMoreParameters(Properties parameter, String attributeName);
272
273 /**
274 * This method determines whether the input name-value pair is exclusive from the processing
275 *
276 * @param keyName the name of the name-value pair
277 * @param keyValue the value of the name-value pair
278 * @return true if the input key is in the exclusive list; otherwise, false
279 */
280 protected boolean isExclusiveField(Object keyName, Object keyValue) {
281
282 if (keyName != null && keyValue != null) {
283 String convertedKeyName = BusinessObjectFieldConverter.convertFromTransactionPropertyName(keyName.toString());
284
285 if (convertedKeyName.equals(KFSPropertyConstants.SUB_ACCOUNT_NUMBER) && keyValue.equals(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER)) {
286 return true;
287 }
288 else if (convertedKeyName.equals(KFSPropertyConstants.SUB_OBJECT_CODE) && keyValue.equals(Constant.CONSOLIDATED_SUB_OBJECT_CODE)) {
289 return true;
290 }
291 else if (convertedKeyName.equals(KFSPropertyConstants.OBJECT_TYPE_CODE) && keyValue.equals(Constant.CONSOLIDATED_OBJECT_TYPE_CODE)) {
292 return true;
293 }
294 if (convertedKeyName.equals(KFSPropertyConstants.SUB_ACCOUNT_NUMBER) && keyValue.equals(KFSConstants.getDashSubAccountNumber())) {
295 return true;
296 }
297 else if (convertedKeyName.equals(KFSPropertyConstants.SUB_OBJECT_CODE) && keyValue.equals(KFSConstants.getDashFinancialSubObjectCode())) {
298 return true;
299 }
300 else if (convertedKeyName.equals(KFSPropertyConstants.PROJECT_CODE) && keyValue.equals(KFSConstants.getDashProjectCode())) {
301 return true;
302 }
303 }
304 return false;
305 }
306
307 /**
308 * This method recovers the values of the given keys
309 *
310 * @param fieldValues unconsolidated values
311 * @param keyName a key name that may be in the fieldValues map
312 * @param keyValue a key value that may be in the fieldValues map
313 * @return the original value for a previously consolidated value
314 */
315 protected String recoverFieldValueFromConsolidation(Map fieldValues, Object keyName, Object keyValue) {
316 if (fieldValues == null || keyName == null || keyValue == null) {
317 return Constant.EMPTY_STRING;
318 }
319
320 Map convertedFieldValues = BusinessObjectFieldConverter.convertFromTransactionFieldValues(fieldValues);
321 String convertedKeyName = BusinessObjectFieldConverter.convertFromTransactionPropertyName(keyName.toString());
322
323 if (convertedKeyName.equals(KFSPropertyConstants.SUB_ACCOUNT_NUMBER) && keyValue.equals(Constant.CONSOLIDATED_SUB_ACCOUNT_NUMBER)) {
324 return this.getValueFromFieldValues(convertedFieldValues, keyName);
325 }
326 else if (convertedKeyName.equals(KFSPropertyConstants.SUB_OBJECT_CODE) && keyValue.equals(Constant.CONSOLIDATED_SUB_OBJECT_CODE)) {
327 return this.getValueFromFieldValues(convertedFieldValues, keyName);
328 }
329 else if (convertedKeyName.equals(KFSPropertyConstants.OBJECT_TYPE_CODE) && keyValue.equals(Constant.CONSOLIDATED_OBJECT_TYPE_CODE)) {
330 return this.getValueFromFieldValues(convertedFieldValues, keyName);
331 }
332
333 return Constant.EMPTY_STRING;
334 }
335
336 /**
337 * Utility method to get the value of the given key from the field values
338 *
339 * @param fieldValues a Map of key values
340 * @param keyName the name of the key to retrieve the value from
341 * @return the value for the key, or, if not found, an empty String
342 */
343 private String getValueFromFieldValues(Map fieldValues, Object keyName) {
344 String keyValue = Constant.EMPTY_STRING;
345
346 if (fieldValues.containsKey(keyName)) {
347 keyValue = (String) fieldValues.get(keyName);
348 }
349 return keyValue;
350 }
351
352 /**
353 * This takes a map of field values and then returns it without processing it, making this a sort
354 * of identity method for Maps
355 *
356 * @param fieldValues field values to return to the user
357 * @return the Map you sent in as a parameter
358 */
359 public Map getFieldValues(Map fieldValues) {
360 return fieldValues;
361 }
362
363 /**
364 * Given the nested name of an attribute in an object, returns the class that attribute will return
365 *
366 * @param businessObject the business object to find the propery class for
367 * @param attributeName the nested name of the attribute to find the class for
368 * @return the class of the nested attribute
369 */
370 public Class getNestedInquiryBusinessObjectClass(BusinessObject businessObject, String attributeName) {
371 // TODO: not finished
372 Class inquiryBusinessObjectClass = null;
373 String entryName = businessObject.getClass().getName();
374 LOG.debug("businessObject: " + entryName);
375 LOG.debug("attributeName: " + attributeName);
376
377 DataDictionaryService dataDictionary = SpringContext.getBean(DataDictionaryService.class);
378 AttributeDefinition attributeDefinition = null;
379
380 if (StringUtils.isBlank(attributeName)) {
381 throw new IllegalArgumentException("invalid (blank) attributeName");
382 }
383
384 DataDictionaryEntryBase entry = (DataDictionaryEntryBase) dataDictionary.getDataDictionary().getDictionaryObjectEntry(entryName);
385 if (entry != null) {
386 attributeDefinition = entry.getAttributeDefinition(attributeName);
387 inquiryBusinessObjectClass = LookupUtils.getNestedReferenceClass(businessObject, attributeName);
388 }
389
390 // TODO: need to get class for which this property belongs
391 // if (attributeDefinition instanceof AttributeReferenceDefinition) {
392 // AttributeReferenceDefinition attributeReferenceDefinition = (AttributeReferenceDefinition) attributeDefinition;
393 // LOG.debug("Source Classname = " + attributeReferenceDefinition.getSourceClassName());
394 // LOG.debug("Source Attribute = " + attributeReferenceDefinition.getSourceAttributeName());
395 //
396 // try {
397 // inquiryBusinessObjectClass = Class.forName(attributeReferenceDefinition.getSourceClassName());
398 // }
399 // catch (Exception e) {
400 // throw new IllegalArgumentException("fail to construct a Class");
401 // }
402 // }
403
404 return inquiryBusinessObjectClass;
405 }
406
407 /**
408 * Builds URL to document type inquiry based on a given document type code
409 *
410 * @param docTypeCode - document type code to inquiry on
411 * @return {@link HtmlData} representing inquiry URL
412 */
413 protected HtmlData getDocTypeInquiryUrl(String docTypeCode) {
414 DocumentTypeDTO docTypeDTO = SpringContext.getBean(DocumentTypeService.class).getDocumentTypeVO(docTypeCode);
415 if ( docTypeDTO == null ) {
416 return new AnchorHtmlData();
417 }
418 String baseUrl = KFSConstants.INQUIRY_ACTION;
419
420 Properties parameters = new Properties();
421 parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.START_METHOD);
422 parameters.put(KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, DocumentTypeEBO.class.getName());
423 parameters.put(KFSConstants.DOC_FORM_KEY, "88888888");
424 parameters.put(KFSPropertyConstants.DOCUMENT_TYPE_ID, docTypeDTO.getDocTypeId().toString());
425
426 Map<String, String> inquiryFields = new HashMap<String, String>();
427 inquiryFields.put(KFSPropertyConstants.DOCUMENT_TYPE_ID, docTypeDTO.getDocTypeId().toString());
428
429 return getHyperLink(DocumentTypeEBO.class, inquiryFields, UrlFactory.parameterizeUrl(baseUrl, parameters));
430 }
431
432 /**
433 * Gets the businessObject attribute.
434 * @return Returns the businessObject.
435 */
436 public BusinessObject getBusinessObject() {
437 return businessObject;
438 }
439
440 /**
441 * Sets the businessObject attribute value.
442 * @param businessObject The businessObject to set.
443 */
444 public void setBusinessObject(BusinessObject businessObject) {
445 this.businessObject = businessObject;
446 }
447 }