Merge pull request #1167 from MegaAlex/MIFOSX-1630

Merged and Closed (y)
This commit is contained in:
Markus Geiß
2014-12-05 12:46:27 +01:00
6 changed files with 127 additions and 55 deletions
+4
View File
@@ -26947,7 +26947,9 @@ No Request Body:
<td class=fielddesc>
Column type. Must be one of the following:
<ul class="field">
<li>Boolean</li>
<li>Date</li>
<li>DateTime</li>
<li>Decimal</li>
<li>Dropdown</li>
<li>Number</li>
@@ -27257,7 +27259,9 @@ GET https://DomainName/api/v1/datatables/{datatable}
<td class=fielddesc>
Column type. Must be one of the following:
<ul class="field">
<li>Boolean</li>
<li>Date</li>
<li>DateTime</li>
<li>Decimal</li>
<li>Dropdown</li>
<li>Number</li>
@@ -45,7 +45,7 @@ public class DatatableCommandFromApiJsonDeserializer {
private final Set<String> supportedParametersForChangeColumns = new HashSet<>(Arrays.asList("name", "newName", "length",
"mandatory", "after", "code", "newCode"));
private final Set<String> supportedParametersForDropColumns = new HashSet<>(Arrays.asList("name"));
private final Object[] supportedColumnTypes = { "string", "number", "decimal", "date", "text", "dropdown" };
private final Object[] supportedColumnTypes = { "string", "number", "boolean", "decimal", "date", "datetime", "text", "dropdown" };
private final Object[] supportedApptableNames = { "m_loan", "m_savings_account", "m_client", "m_group", "m_center", "m_office",
"m_savings_product", "m_product_loan" };
@@ -18,6 +18,7 @@ import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.MonthDay;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
@@ -144,10 +145,10 @@ public class JsonParserHelper {
/**
* Method used to extract integers from unformatted strings. Ex: "1" ,
* "100002" etc
*
*
* Please note that this method does not support extracting Integers from
* locale specific formatted strings Ex "1,000" etc
*
*
* @param parameterName
* @param element
* @param parametersPassedInRequest
@@ -354,6 +355,36 @@ public class JsonParserHelper {
public static LocalDate convertFrom(final String dateAsString, final String parameterName, final String dateFormat,
final Locale clientApplicationLocale) {
return convertDateTimeFrom(dateAsString, parameterName,
dateFormat, clientApplicationLocale).toLocalDate();
}
public static LocalDateTime convertDateTimeFrom(final String dateTimeAsString, final String parameterName,
final String dateTimeFormat, final Locale clientApplicationLocale) {
validateDateFormatAndLocale(parameterName, dateTimeFormat, clientApplicationLocale);
LocalDateTime eventLocalDateTime = null;
if (StringUtils.isNotBlank(dateTimeAsString)) {
try {
eventLocalDateTime = DateTimeFormat.forPattern(dateTimeFormat).withLocale(clientApplicationLocale)
.parseLocalDateTime(dateTimeAsString.toLowerCase(clientApplicationLocale));
} catch (final IllegalArgumentException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.dateFormat.format", "The parameter "
+ parameterName + " is invalid based on the dateFormat: '" + dateTimeFormat + "' and locale: '"
+ clientApplicationLocale + "' provided:", parameterName, eventLocalDateTime, dateTimeFormat);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
}
return eventLocalDateTime;
}
private static void validateDateFormatAndLocale(final String parameterName, final String dateFormat,
final Locale clientApplicationLocale) {
if (StringUtils.isBlank(dateFormat) || clientApplicationLocale == null) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
@@ -375,25 +406,6 @@ public class JsonParserHelper {
dataValidationErrors);
}
LocalDate eventLocalDate = null;
if (StringUtils.isNotBlank(dateAsString)) {
try {
// Locale locale = LocaleContextHolder.getLocale();
eventLocalDate = DateTimeFormat.forPattern(dateFormat).withLocale(clientApplicationLocale)
.parseLocalDate(dateAsString.toLowerCase(clientApplicationLocale));
} catch (final IllegalArgumentException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.date.format", "The parameter "
+ parameterName + " is invalid based on the dateFormat: '" + dateFormat + "' and locale: '"
+ clientApplicationLocale + "' provided:", parameterName, dateAsString, dateFormat);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
}
return eventLocalDate;
}
public Integer convertToInteger(final String numericalValueFormatted, final String parameterName, final Locale clientApplicationLocale) {
@@ -69,6 +69,8 @@ public final class ResultsetColumnHeaderData {
displayType = "DECIMAL";
} else if (isAnyText()) {
displayType = "TEXT";
} else if(isBit()) {
displayType = "BOOLEAN";
} else {
throw new PlatformDataIntegrityException("error.msg.invalid.lookup.type", "Invalid Lookup Type:" + this.columnType
+ " - Column Name: " + this.columnName);
@@ -137,7 +139,7 @@ public final class ResultsetColumnHeaderData {
}
private boolean isAnyInteger() {
return isInt() || isSmallInt() || isTinyInt() || isMediumInt() || isBigInt() || isBit();
return isInt() || isSmallInt() || isTinyInt() || isMediumInt() || isBigInt();
}
private boolean isInt() {
@@ -184,6 +186,10 @@ public final class ResultsetColumnHeaderData {
return "DATE".equalsIgnoreCase(this.columnDisplayType);
}
public boolean isDateTimeDisplayType() {
return "DATETIME".equalsIgnoreCase(this.columnDisplayType);
}
public boolean isIntegerDisplayType() {
return "INTEGER".equalsIgnoreCase(this.columnDisplayType);
}
@@ -192,6 +198,10 @@ public final class ResultsetColumnHeaderData {
return "DECIMAL".equalsIgnoreCase(this.columnDisplayType);
}
public boolean isBooleanDisplayType() {
return "BOOLEAN".equalsIgnoreCase(this.columnDisplayType);
}
public boolean isCodeValueDisplayType() {
return "CODEVALUE".equalsIgnoreCase(this.columnDisplayType);
}
@@ -11,6 +11,7 @@ import java.util.List;
import javax.sql.DataSource;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
@@ -147,8 +148,13 @@ public class GenericDataServiceImpl implements GenericDataService {
final LocalDate localDate = new LocalDate(currVal);
writer.append("[" + localDate.getYear() + ", " + localDate.getMonthOfYear() + ", " + localDate.getDayOfMonth()
+ "]");
} else if (currColType.equals("DATETIME")) {
final LocalDateTime localDateTime = new LocalDateTime(currVal);
writer.append("[" + localDateTime.getYear() + ", " + localDateTime.getMonthOfYear() + ", "
+ localDateTime.getDayOfMonth() + " " + localDateTime.getHourOfDay() + ", "
+ localDateTime.getMinuteOfHour() + ", " + localDateTime.getSecondOfMinute() + ", "
+ localDateTime.getMillisOfSecond() + "]");
} else {
writer.append(doubleQuote + replace(currVal, doubleQuote, slashDoubleQuote) + doubleQuote);
}
}
@@ -17,11 +17,13 @@ import java.util.Set;
import javax.sql.DataSource;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.GenericJDBCException;
import org.hibernate.exception.SQLGrammarException;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.mifosplatform.infrastructure.codes.service.CodeReadPlatformService;
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
@@ -76,8 +78,10 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
{
put("string", "VARCHAR");
put("number", "INT");
put("boolean", "BIT");
put("decimal", "DECIMAL");
put("date", "DATE");
put("datetime", "DATETIME");
put("text", "TEXT");
put("dropdown", "INT");
}
@@ -514,7 +518,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
/***
* In cases of tables storing hierarchical entities (like m_group),
* different entities would end up being stored in the same table.
*
*
* Ex: Centers are a specific type of group, add abstractions for
* the same
***/
@@ -777,7 +781,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
/**
* Update data table, set column value to empty string where current value
* is NULL. Run update SQL only if the "mandatory" property is set to true
*
*
* @param datatableName
* Name of data table
* @param column
@@ -1028,7 +1032,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (datatableId != null) {
pkValue = datatableId;
}
final String sql = getUpdateSql(dataTableName, pkName, pkValue, changes);
final String sql = getUpdateSql(grs.getColumnHeaders(), dataTableName, pkName, pkValue, changes);
logger.info("Update sql: " + sql);
if (StringUtils.isNotBlank(sql)) {
this.jdbcTemplate.update(sql);
@@ -1312,18 +1316,24 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
String selectColumns = "";
String columnName = "";
String pValue = null;
for (final String key : affectedColumns.keySet()) {
pValue = affectedColumns.get(key);
if (StringUtils.isEmpty(pValue)) {
pValueWrite = "null";
} else {
pValueWrite = singleQuote + this.genericDataService.replace(pValue, singleQuote, singleQuote + singleQuote) + singleQuote;
for(final ResultsetColumnHeaderData pColumnHeader : columnHeaders) {
final String key = pColumnHeader.getColumnName();
if(affectedColumns.containsKey(key)) {
pValue = affectedColumns.get(key);
if (StringUtils.isEmpty(pValue)) {
pValueWrite = "null";
} else {
if ("bit".equalsIgnoreCase(pColumnHeader.getColumnType())) {
pValueWrite = BooleanUtils.toString(BooleanUtils.toBooleanObject(pValue), "1", "0", "null");
} else {
pValueWrite = singleQuote + this.genericDataService.replace(pValue, singleQuote, singleQuote + singleQuote) + singleQuote;
}
}
columnName = "`" + key + "`";
insertColumns += ", " + columnName;
selectColumns += "," + pValueWrite + " as " + columnName;
}
columnName = "`" + key + "`";
insertColumns += ", " + columnName;
selectColumns += "," + pValueWrite + " as " + columnName;
}
addSql = "insert into `" + datatable + "` (`" + fkName + "` " + insertColumns + ")" + " select " + appTableId + " as id"
@@ -1337,7 +1347,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
/**
* This method is used special for ppi cases Where the score need to be
* computed
*
*
* @param columnHeaders
* @param datatable
* @param fkName
@@ -1385,8 +1395,9 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
return vaddSql;
}
private String getUpdateSql(final String datatable, final String keyFieldName, final Long keyFieldValue,
final Map<String, Object> changedColumns) {
private String getUpdateSql(List<ResultsetColumnHeaderData> columnHeaders, final String datatable,
final String keyFieldName, final Long keyFieldValue,
final Map<String, Object> changedColumns) {
// just updating fields that have changed since pre-update read - though
// its possible these values are different from the page the user was
@@ -1402,22 +1413,28 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
final String singleQuote = "'";
boolean firstColumn = true;
String sql = "update `" + datatable + "` ";
for (final ResultsetColumnHeaderData pColumnHeader : columnHeaders) {
final String key = pColumnHeader.getColumnName();
if(changedColumns.containsKey(key)) {
if (firstColumn) {
sql += " set ";
firstColumn = false;
} else {
sql += ", ";
}
for (final String key : changedColumns.keySet()) {
if (firstColumn) {
sql += " set ";
firstColumn = false;
} else {
sql += ", ";
pValue = (String) changedColumns.get(key);
if (StringUtils.isEmpty(pValue)) {
pValueWrite = "null";
} else {
if ("bit".equalsIgnoreCase(pColumnHeader.getColumnType())) {
pValueWrite = BooleanUtils.toString(BooleanUtils.toBooleanObject(pValue), "1", "0", "null");
} else {
pValueWrite = singleQuote + this.genericDataService.replace(pValue, singleQuote, singleQuote + singleQuote) + singleQuote;
}
}
sql += "`" + key + "` = " + pValueWrite;
}
pValue = (String) changedColumns.get(key);
if (StringUtils.isEmpty(pValue)) {
pValueWrite = "null";
} else {
pValueWrite = singleQuote + this.genericDataService.replace(pValue, singleQuote, singleQuote + singleQuote) + singleQuote;
}
sql += "`" + key + "` = " + pValueWrite;
}
sql += " where " + keyFieldName + " = " + keyFieldValue;
@@ -1511,7 +1528,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
final Locale clientApplicationLocale) {
String paramValue = pValue;
if (columnHeader.isDateDisplayType() || columnHeader.isIntegerDisplayType() || columnHeader.isDecimalDisplayType()) {
if (columnHeader.isDateDisplayType() || columnHeader.isDateTimeDisplayType()
|| columnHeader.isIntegerDisplayType() || columnHeader.isDecimalDisplayType() || columnHeader.isBooleanDisplayType()) {
// only trim if string is not empty and is not null.
// throws a NULL pointer exception if the check below is not applied
paramValue = StringUtils.isNotEmpty(paramValue) ? paramValue.trim() : paramValue;
@@ -1569,6 +1587,14 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
} else {
paramValue = tmpDate.toString();
}
} else if (columnHeader.isDateTimeDisplayType()) {
final LocalDateTime tmpDateTime = JsonParserHelper.convertDateTimeFrom(paramValue,
columnHeader.getColumnName(), dateFormat, clientApplicationLocale);
if (tmpDateTime == null) {
paramValue = null;
} else {
paramValue = tmpDateTime.toString();
}
} else if (columnHeader.isIntegerDisplayType()) {
final Integer tmpInt = this.helper.convertToInteger(paramValue, columnHeader.getColumnName(), clientApplicationLocale);
if (tmpInt == null) {
@@ -1583,6 +1609,20 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
} else {
paramValue = tmpDecimal.toString();
}
} else if (columnHeader.isBooleanDisplayType()) {
final Boolean tmpBoolean = BooleanUtils.toBooleanObject(paramValue);
if (tmpBoolean == null) {
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.boolean.format", "The parameter "
+ columnHeader.getColumnName() + " has value: " + paramValue + " which is invalid boolean value.",
columnHeader.getColumnName(), paramValue);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
} else {
paramValue = tmpBoolean.toString();
}
} else if (columnHeader.isString()) {
if (paramValue.length() > columnHeader.getColumnLength()) {
final ApiParameterError error = ApiParameterError.parameterError(