/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.ar.batch.vo; import org.apache.commons.beanutils.ConversionException; import org.apache.commons.beanutils.converters.SqlDateConverter; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.module.ar.batch.report.CustomerLoadBatchErrors; import org.kuali.kfs.module.ar.businessobject.Customer; import org.kuali.kfs.module.ar.businessobject.CustomerAddress; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.rice.core.api.datetime.DateTimeService; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService; /** * * This class converts a CustomerDigesterVO object to a standard * Customer object. */ public class CustomerDigesterAdapter { private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CustomerDigesterAdapter.class); private static final Class<Customer> BO_CLASS = Customer.class; private static final String DD_ENTRY_NAME = BO_CLASS.getName(); private DateTimeService dateTimeService; private MaintenanceDocumentDictionaryService maintDocDDService; private Customer customer; private String customerName; private CustomerLoadBatchErrors errors; private CustomerDigesterVO customerDigesterVO; public CustomerDigesterAdapter() { if (dateTimeService == null) dateTimeService = SpringContext.getBean(DateTimeService.class); if (maintDocDDService == null) maintDocDDService = SpringContext.getBean(MaintenanceDocumentDictionaryService.class); } /** * * Converts a CustomerDigesterVO to a real Customer BO. Tries to do intelligent type * conversions where the types arent Strings. * * NOTE that conversion exceptions will be swallowed! and converted to errors in the * parameter errorMap. * * @param customerDigesterVO The VO full of String values to convert from. * @param errorMap An empty MessageMap collection to add errors to. Only new errors will be added. * @return A populated Customer object, from the VO. */ public Customer convert(CustomerDigesterVO customerDigesterVO, CustomerLoadBatchErrors errors) { if (customerDigesterVO == null) { throw new IllegalArgumentException("Parameter customerDigesterVO may not be null."); } this.customerDigesterVO = customerDigesterVO; // the whole error system is keyed of customerName, so if we dont get one of those, we cant even proceed. if (StringUtils.isBlank(customerDigesterVO.getCustomerName())) { LOG.error("CustomerName can never be empty-string or null."); addError("customerName", String.class, customerDigesterVO.getCustomerName(), "CustomerName can never be empty-string or null."); return null; } customer = new Customer(); customerName = this.customerDigesterVO.getCustomerName(); if (errors == null) { LOG.error("Passed in CustomerLoadBatchErrors must not be null."); throw new IllegalArgumentException("Passed in CustomerLoadBatchErrors must not be null."); } this.errors = errors; convertCustomerStringProperties(); convertCustomerDateProperties(); convertCustomerKualiDecimalProperties(); convertCustomerBooleanProperties(); convertCustomerAddresses(); return customer; } private void convertCustomerStringProperties() { // these are String to String conversions, so they will always work customer.setCustomerNumber(applyDefaultValue("customerNumber", customerDigesterVO.getCustomerNumber())); customer.setCustomerName(applyDefaultValue("customerName", customerDigesterVO.getCustomerName())); customer.setCustomerParentCompanyNumber(applyDefaultValue("customerParentCompanyNumber", customerDigesterVO.getCustomerParentCompanyNumber())); customer.setCustomerTypeCode(applyDefaultValue("customerTypeCode", customerDigesterVO.getCustomerTypeCode())); customer.setCustomerTaxTypeCode(applyDefaultValue("customerTaxTypeCode", customerDigesterVO.getCustomerTaxTypeCode())); customer.setCustomerTaxNbr(applyDefaultValue("customerTaxNbr", customerDigesterVO.getCustomerTaxNbr())); customer.setCustomerPhoneNumber(applyDefaultValue("customerPhoneNumber", customerDigesterVO.getCustomerPhoneNumber())); customer.setCustomer800PhoneNumber(applyDefaultValue("customer800PhoneNumber", customerDigesterVO.getCustomer800PhoneNumber())); customer.setCustomerContactName(applyDefaultValue("customerContactName", customerDigesterVO.getCustomerContactName())); customer.setCustomerContactPhoneNumber(applyDefaultValue("customerContactPhoneNumber", customerDigesterVO.getCustomerContactPhoneNumber())); customer.setCustomerFaxNumber(applyDefaultValue("customerFaxNumber", customerDigesterVO.getCustomerFaxNumber())); customer.setCustomerCreditApprovedByName(applyDefaultValue("customerCreditApprovedByName", customerDigesterVO.getCustomerCreditApprovedByName())); customer.setCustomerEmailAddress(applyDefaultValue("customerEmailAddress", customerDigesterVO.getCustomerEmailAddress())); return; } private void convertCustomerDateProperties() { java.sql.Date todayDate = dateTimeService.getCurrentSqlDate(); customer.setCustomerAddressChangeDate(todayDate); customer.setCustomerRecordAddDate(todayDate); customer.setCustomerLastActivityDate(todayDate); customer.setCustomerBirthDate(convertToJavaSqlDate("customerBirthDate", applyDefaultValue("customerBirthDate", customerDigesterVO.getCustomerBirthDate()))); return; } private void convertCustomerKualiDecimalProperties() { customer.setCustomerCreditLimitAmount(convertToKualiDecimal("customerCreditLimitAmount", applyDefaultValue("customerCreditLimitAmount", customerDigesterVO.getCustomerCreditLimitAmount()))); return; } private void convertCustomerBooleanProperties() { customer.setActive(convertToLittleBoolean("customerActiveIndicator", applyDefaultValue("customerActiveIndicator", customerDigesterVO.getCustomerActiveIndicator()))); customer.setCustomerTaxExemptIndicator(convertToLittleBoolean("customerTaxExemptIndicator", applyDefaultValue("customerTaxExemptIndicator", customerDigesterVO.getCustomerTaxExemptIndicator()))); return; } private void convertCustomerAddresses() { CustomerAddress customerAddress = null; for (CustomerAddressDigesterVO addressVO : customerDigesterVO.getCustomerAddresses()) { customerAddress = convertCustomerAddress(addressVO, customer.getCustomerNumber()); customer.getCustomerAddresses().add(customerAddress); } return; } private CustomerAddress convertCustomerAddress(CustomerAddressDigesterVO customerAddressDigesterVO, String customerNumber) { CustomerAddress customerAddress = new CustomerAddress(); // link the customerAddress to the parent customer customerAddress.setCustomerNumber(customerNumber); customerAddress.setCustomerAddressName(applyDefaultValue("customerAddressName", customerAddressDigesterVO.getCustomerAddressName())); customerAddress.setCustomerLine1StreetAddress(applyDefaultValue("customerLine1StreetAddress", customerAddressDigesterVO.getCustomerLine1StreetAddress())); customerAddress.setCustomerLine2StreetAddress(applyDefaultValue("customerLine2StreetAddress", customerAddressDigesterVO.getCustomerLine2StreetAddress())); customerAddress.setCustomerCityName(applyDefaultValue("customerCityName", customerAddressDigesterVO.getCustomerCityName())); customerAddress.setCustomerStateCode(applyDefaultValue("customerStateCode", customerAddressDigesterVO.getCustomerStateCode())); customerAddress.setCustomerZipCode(applyDefaultValue("customerZipCode", customerAddressDigesterVO.getCustomerZipCode())); customerAddress.setCustomerCountryCode(applyDefaultValue("customerCountryCode", customerAddressDigesterVO.getCustomerCountryCode())); customerAddress.setCustomerAddressInternationalProvinceName(applyDefaultValue("customerAddressInternationalProvinceName", customerAddressDigesterVO.getCustomerAddressInternationalProvinceName())); customerAddress.setCustomerInternationalMailCode(applyDefaultValue("customerInternationalMailCode", customerAddressDigesterVO.getCustomerInternationalMailCode())); customerAddress.setCustomerEmailAddress(applyDefaultValue("customerEmailAddress", customerAddressDigesterVO.getCustomerEmailAddress())); customerAddress.setCustomerAddressTypeCode(applyDefaultValue("customerAddressTypeCode", customerAddressDigesterVO.getCustomerAddressTypeCode())); customerAddress.setCustomerAddressEndDate(convertToJavaSqlDate("customerAddressEndDate", applyDefaultValue("customerAddressEndDate", customerAddressDigesterVO.getCustomerAddressEndDate()))); return customerAddress; } /** * * This method converts a string value that may represent a date into a java.sql.Date. * If the value is blank (whitespace, empty, null) then a null Date object is returned. If * the value cannot be converted to a java.sql.Date, then a RuntimException or ConversionException * will be thrown. * * @param propertyName Name of the field whose value is being converted. * @param dateValue The value being converted. * @param errorMap The errorMap to add conversion errors to. * @return A valid java.sql.Date with the converted value, if possible. */ private java.sql.Date convertToJavaSqlDate(String propertyName, String dateValue) { if (StringUtils.isBlank(dateValue)) { return null; } java.sql.Date date = null; SqlDateConverter converter = new SqlDateConverter(); Object obj = null; try { obj = converter.convert(java.sql.Date.class, dateValue); } catch (ConversionException e) { LOG.error("Failed to convert the value [" + dateValue + "] from field [" + propertyName + "] to a java.sql.Date."); addError(propertyName, java.sql.Date.class, dateValue, "Could not convert value to target type."); return null; } try { date = (java.sql.Date) obj; } catch (Exception e) { LOG.error("Failed to cast the converters results to a java.sql.Date."); addError(propertyName, java.sql.Date.class, dateValue, "Could not convert value to target type."); return null; } if (!(obj instanceof java.sql.Date)) { LOG.error("Failed to convert the value [" + dateValue + "] from field [" + propertyName + "] to a java.sql.Date."); addError(propertyName, java.sql.Date.class, dateValue, "Could not convert value to target type."); return null; } return date; } /** * * This method converts a string, which may be blank, null or whitespace, into a KualiDecimal, if possible. * * A null, blank, or whitespace value passed in will result in a Null KualiDecimal value returned. A value passed in * which is not blank, but cannot otherwise be converted to a KualiDecimal, will throw a ValueObjectConverterException. * Otherwise, the value will be converted to a KualiDecimal and returned. * * @param propertyName The name of the property being converted (used for exception handling). * @param stringDecimal The value being passed in, which will be converted to a KualiDecimal. * @param errorMap The errorMap to add conversion errors to. * @return A valid KualiDecimal value. If the method returns a value, then it will be a legitimate value. */ private KualiDecimal convertToKualiDecimal(String propertyName, String stringDecimal) { if (StringUtils.isBlank(stringDecimal)) { return null; } KualiDecimal kualiDecimal = null; try { kualiDecimal = new KualiDecimal(stringDecimal); } catch (NumberFormatException e) { LOG.error("Failed to convert the value [" + stringDecimal + "] from field [" + propertyName + "] to a KualiDecimal."); addError(propertyName, KualiDecimal.class, stringDecimal, "Could not convert value to target type."); return null; } return kualiDecimal; } /** * * This method converts a String into a boolean. * * It will return * @param propertyName * @param stringBoolean * @param errorMap The errorMap to add conversion errors to. * @return */ private static final boolean convertToLittleBoolean(String propertyName, String stringBoolean) { if (StringUtils.isBlank(stringBoolean)) { return false; } if ("Y".equalsIgnoreCase(stringBoolean)) { return true; } if ("YES".equalsIgnoreCase(stringBoolean)) { return true; } if ("TRUE".equalsIgnoreCase(stringBoolean)) { return true; } if ("T".equalsIgnoreCase(stringBoolean)) { return true; } if ("1".equalsIgnoreCase(stringBoolean)) { return true; } return false; } /** * * This method is used to apply any DataDictionary default value rules, if appropriate. * * If the incoming value isnt blank, empty, or null, then nothing happens, and the method * returns the incoming value. * * If the value is empty/blank/null, then the MaintenanceDocumentDictionaryService is consulted, * and if there is a defaultValue applied to this field, then its used in place of the empty/blank/null. * * @param propertyName The propertyName of the field (must match case exactly to work). * @param batchValue The invoming value from the batch file, which at this point is always still a string. * @return If the original value is null/blank/empty, then if a default value is configured, that default value * is returned. If no default value is configured, then the original value (trimmed) is returned. Otherwise, * if the original incoming value is not empty/null/blank, then the original value is immediately returned. */ private String applyDefaultValue(String propertyName, String batchValue) { // short-circuit if value isnt empty/blank/null, as default wouldnt apply anyway if (StringUtils.isNotBlank(batchValue)) { return batchValue; } // if its a string, we try to normalize it to null if empty/blank String incomingValue; if (StringUtils.isBlank(batchValue)) { incomingValue = null; } else { incomingValue = StringUtils.trimToNull(batchValue); } // apply the default value from DD if exists String defaultValue = maintDocDDService.getFieldDefaultValue(BO_CLASS, propertyName); if (incomingValue == null && StringUtils.isNotBlank(defaultValue)) { LOG.info("Applied DD default value of '" + defaultValue + "' to field [" + propertyName + "]."); return defaultValue; } else { return ((incomingValue == null) ? "" : incomingValue); } } private void addError(String propertyName, Class<?> propertyClass, String origValue, String description) { LOG.error("Failed conversion on field [" + propertyName + "] with value: '" + origValue + "': " + description); errors.addError(customerName, propertyName, propertyClass, origValue, description); } public void setDateTimeService(DateTimeService dateTimeService) { this.dateTimeService = dateTimeService; } public void setMaintDocDDService(MaintenanceDocumentDictionaryService maintDocDDService) { this.maintDocDDService = maintDocDDService; } }