Merge pull request #1167 from MegaAlex/MIFOSX-1630
Merged and Closed (y)
This commit is contained in:
@@ -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>
|
||||
|
||||
+1
-1
@@ -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" };
|
||||
|
||||
|
||||
+33
-21
@@ -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) {
|
||||
|
||||
+11
-1
@@ -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);
|
||||
}
|
||||
|
||||
+7
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+71
-31
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user