diff --git a/mifosng-db/patches/patch-11-drop-and-recreate-command-source-table.sql b/mifosng-db/patches/patch-11-drop-and-recreate-command-source-table.sql new file mode 100644 index 000000000..2561d4348 --- /dev/null +++ b/mifosng-db/patches/patch-11-drop-and-recreate-command-source-table.sql @@ -0,0 +1,21 @@ + +drop table if exists `m_portfolio_command_source`; +CREATE TABLE `m_portfolio_command_source` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `permission_code` varchar(50) NOT NULL, + `api_operation` varchar(30) NOT NULL, + `api_resource` varchar(100) NOT NULL, + `resource_id` bigint(20) DEFAULT NULL, + `api_subresource` varchar(100) DEFAULT NULL, + `subresource_id` bigint(20) DEFAULT NULL, + `command_as_json` text NOT NULL, + `maker_id` bigint(20) NOT NULL, + `made_on_date` datetime NOT NULL, + `checker_id` bigint(20) DEFAULT NULL, + `checked_on_date` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `FK_m_maker_m_appuser` (`maker_id`), + KEY `FK_m_checker_m_appuser` (`checker_id`), + CONSTRAINT `FK_m_checker_m_appuser` FOREIGN KEY (`checker_id`) REFERENCES `m_appuser` (`id`), + CONSTRAINT `FK_m_maker_m_appuser` FOREIGN KEY (`maker_id`) REFERENCES `m_appuser` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditApiResource.java index 5fcad7869..58464ad30 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditApiResource.java @@ -16,6 +16,9 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; import org.apache.commons.lang.StringUtils; +import org.mifosplatform.audit.data.AuditData; +import org.mifosplatform.audit.data.AuditSearchData; +import org.mifosplatform.audit.service.AuditReadPlatformService; import org.mifosplatform.infrastructure.core.api.ApiParameterHelper; import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; @@ -30,128 +33,103 @@ import org.springframework.stereotype.Component; @Scope("singleton") public class AuditApiResource { - private final Set RESPONSE_DATA_PARAMETERS = new HashSet( - Arrays.asList("id", "apiOperation", "resource", "resourceId", - "maker", "madeOnDate", "checker", "checkedOnDate", - "commandAsJson")); - private final String resourceNameForPermissions = "AUDIT"; + private final Set RESPONSE_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "apiOperation", "resource", "resourceId", + "maker", "madeOnDate", "checker", "checkedOnDate", "commandAsJson")); - private final PlatformSecurityContext context; - private final AuditReadPlatformService auditReadPlatformService; - private final ApiRequestParameterHelper apiRequestParameterHelper; - private final DefaultToApiJsonSerializer toApiJsonSerializer; - private final DefaultToApiJsonSerializer toApiJsonSerializerSearchTemplate; + private final String resourceNameForPermissions = "AUDIT"; - @Autowired - public AuditApiResource( - final PlatformSecurityContext context, - final AuditReadPlatformService auditReadPlatformService, - final ApiRequestParameterHelper apiRequestParameterHelper, - final DefaultToApiJsonSerializer toApiJsonSerializer, - final DefaultToApiJsonSerializer toApiJsonSerializerSearchTemplate) { - this.context = context; - this.auditReadPlatformService = auditReadPlatformService; - this.apiRequestParameterHelper = apiRequestParameterHelper; - this.toApiJsonSerializer = toApiJsonSerializer; - this.toApiJsonSerializerSearchTemplate = toApiJsonSerializerSearchTemplate; - } + private final PlatformSecurityContext context; + private final AuditReadPlatformService auditReadPlatformService; + private final ApiRequestParameterHelper apiRequestParameterHelper; + private final DefaultToApiJsonSerializer toApiJsonSerializer; + private final DefaultToApiJsonSerializer toApiJsonSerializerSearchTemplate; - @GET - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String retrieveAuditEntries(@Context final UriInfo uriInfo, - @QueryParam("apiOperation") final String apiOperation, - @QueryParam("resource") final String resource, - @QueryParam("resourceId") final Long resourceId, - @QueryParam("makerId") final Long makerId, - @QueryParam("checkerId") final Long checkerId) { + @Autowired + public AuditApiResource(final PlatformSecurityContext context, final AuditReadPlatformService auditReadPlatformService, + final ApiRequestParameterHelper apiRequestParameterHelper, final DefaultToApiJsonSerializer toApiJsonSerializer, + final DefaultToApiJsonSerializer toApiJsonSerializerSearchTemplate) { + this.context = context; + this.auditReadPlatformService = auditReadPlatformService; + this.apiRequestParameterHelper = apiRequestParameterHelper; + this.toApiJsonSerializer = toApiJsonSerializer; + this.toApiJsonSerializerSearchTemplate = toApiJsonSerializerSearchTemplate; + } - context.authenticatedUser().validateHasReadPermission( - resourceNameForPermissions); + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAuditEntries(@Context final UriInfo uriInfo, @QueryParam("apiOperation") final String apiOperation, + @QueryParam("resource") final String resource, @QueryParam("resourceId") final Long resourceId, + @QueryParam("makerId") final Long makerId, @QueryParam("checkerId") final Long checkerId) { - final String extraCriteria = getExtraCriteria(apiOperation, resource, - resourceId, makerId, checkerId); + context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); - final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper - .process(uriInfo.getQueryParameters()); + final String extraCriteria = getExtraCriteria(apiOperation, resource, resourceId, makerId, checkerId); - final Collection auditEntries = this.auditReadPlatformService - .retrieveAuditEntries(extraCriteria, settings.isIncludeJson()); + final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - return this.toApiJsonSerializer.serialize(settings, auditEntries, - RESPONSE_DATA_PARAMETERS); - } + final Collection auditEntries = this.auditReadPlatformService.retrieveAuditEntries(extraCriteria, + settings.isIncludeJson()); - @GET - @Path("{auditId}") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String retrieveAuditEntry(@PathParam("auditId") final Long auditId, - @Context final UriInfo uriInfo) { + return this.toApiJsonSerializer.serialize(settings, auditEntries, RESPONSE_DATA_PARAMETERS); + } - context.authenticatedUser().validateHasReadPermission( - resourceNameForPermissions); + @GET + @Path("{auditId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAuditEntry(@PathParam("auditId") final Long auditId, @Context final UriInfo uriInfo) { - final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper - .process(uriInfo.getQueryParameters()); + context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); - final AuditData auditEntry = this.auditReadPlatformService - .retrieveAuditEntry(auditId); + final AuditData auditEntry = this.auditReadPlatformService.retrieveAuditEntry(auditId); - return this.toApiJsonSerializer.serialize(settings, auditEntry, - RESPONSE_DATA_PARAMETERS); - } + final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.toApiJsonSerializer.serialize(settings, auditEntry, RESPONSE_DATA_PARAMETERS); + } - @GET - @Path("/searchtemplate") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String retrieveAuditSearchTemplate(@Context final UriInfo uriInfo) { + @GET + @Path("/searchtemplate") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAuditSearchTemplate(@Context final UriInfo uriInfo) { - context.authenticatedUser().validateHasReadPermission( - resourceNameForPermissions); + context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); - final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper - .process(uriInfo.getQueryParameters()); + final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - final AuditSearchData auditSearchData = this.auditReadPlatformService - .retrieveSearchTemplate(); + final AuditSearchData auditSearchData = this.auditReadPlatformService.retrieveSearchTemplate(); - final Set RESPONSE_DATA_PARAMETERS_SEARCH_TEMPLATE = new HashSet( - Arrays.asList("appUsers", "apiOperations", "resources")); + final Set RESPONSE_DATA_PARAMETERS_SEARCH_TEMPLATE = new HashSet(Arrays.asList("appUsers", "apiOperations", + "resources")); - return this.toApiJsonSerializerSearchTemplate.serialize(settings, auditSearchData, - RESPONSE_DATA_PARAMETERS_SEARCH_TEMPLATE); - } + return this.toApiJsonSerializerSearchTemplate.serialize(settings, auditSearchData, RESPONSE_DATA_PARAMETERS_SEARCH_TEMPLATE); + } - private String getExtraCriteria(String apiOperation, String resource, - Long resourceId, Long makerId, Long checkerId) { + private String getExtraCriteria(final String apiOperation, final String resource, final Long resourceId, final Long makerId, final Long checkerId) { - String extraCriteria = ""; + String extraCriteria = ""; - if (apiOperation != null) { - extraCriteria += " and aud.api_operation = " - + ApiParameterHelper.sqlEncodeString(apiOperation); - } - if (resource != null) { - extraCriteria += " and aud.api_resource = " - + ApiParameterHelper.sqlEncodeString(resource); - } - if (resourceId != null) { - extraCriteria += " and aud.resource_id = " + resourceId; - } - if (makerId != null) { - extraCriteria += " and aud.maker_id = " + makerId; - } - if (checkerId != null) { - extraCriteria += " and aud.checker_id = " + checkerId; - } + if (apiOperation != null) { + extraCriteria += " and aud.api_operation = " + ApiParameterHelper.sqlEncodeString(apiOperation); + } + if (resource != null) { + extraCriteria += " and aud.api_resource = " + ApiParameterHelper.sqlEncodeString(resource); + } + if (resourceId != null) { + extraCriteria += " and aud.resource_id = " + resourceId; + } + if (makerId != null) { + extraCriteria += " and aud.maker_id = " + makerId; + } + if (checkerId != null) { + extraCriteria += " and aud.checker_id = " + checkerId; + } - if (StringUtils.isNotBlank(extraCriteria)) { - extraCriteria = extraCriteria.substring(4); - } - - return extraCriteria; - } + if (StringUtils.isNotBlank(extraCriteria)) { + extraCriteria = extraCriteria.substring(4); + } + return extraCriteria; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditReadPlatformService.java deleted file mode 100644 index d10f91283..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditReadPlatformService.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.mifosplatform.audit.api; - -import java.util.Collection; - -public interface AuditReadPlatformService { - - Collection retrieveAuditEntries(String extraCriteria, - boolean includeJson); - - AuditData retrieveAuditEntry(Long auditId); - - AuditSearchData retrieveSearchTemplate(); - -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditReadPlatformServiceImpl.java deleted file mode 100644 index f7147847f..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditReadPlatformServiceImpl.java +++ /dev/null @@ -1,157 +0,0 @@ -package org.mifosplatform.audit.api; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Collection; -import java.util.List; - -import org.apache.commons.lang.StringUtils; -import org.joda.time.LocalDate; -import org.mifosplatform.infrastructure.core.domain.JdbcSupport; -import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.useradministration.data.AppUserLookup; -import org.mifosplatform.useradministration.service.AppUserReadPlatformService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.stereotype.Service; - -@Service -public class AuditReadPlatformServiceImpl implements AuditReadPlatformService { - - private final JdbcTemplate jdbcTemplate; - private final PlatformSecurityContext context; - private final AppUserReadPlatformService appUserReadPlatformService; - - @Autowired - public AuditReadPlatformServiceImpl(final PlatformSecurityContext context, - final TenantAwareRoutingDataSource dataSource, - final AppUserReadPlatformService appUserReadPlatformService) { - this.context = context; - this.jdbcTemplate = new JdbcTemplate(dataSource); - this.appUserReadPlatformService = appUserReadPlatformService; - } - - private static final class AuditMapper implements RowMapper { - - public String schema(boolean includeJson) { - - String commandAsJsonString = ""; - if (includeJson) - commandAsJsonString = ", aud.command_as_json as commandAsJson "; - - return " aud.id as id, aud.api_operation as apiOperation, aud.api_resource as resource, aud.resource_id as resourceId," - + " mk.username as maker, aud.made_on_date as madeOnDate, ck.username as checker, aud.checked_on_date as checkedOnDate" - + commandAsJsonString - + " from m_portfolio_command_source aud " - + " left join m_appuser mk on mk.id = aud.maker_id" - + " left join m_appuser ck on ck.id = aud.checker_id"; - } - - @Override - public AuditData mapRow(final ResultSet rs, - @SuppressWarnings("unused") final int rowNum) - throws SQLException { - - final Long id = rs.getLong("id"); - final String apiOperation = rs.getString("apiOperation"); - final String resource = rs.getString("resource"); - final Long resourceId = JdbcSupport.getLong(rs, "resourceId"); - final String maker = rs.getString("maker"); - final LocalDate madeOnDate = JdbcSupport.getLocalDate(rs, - "madeOnDate"); - final String checker = rs.getString("checker"); - final LocalDate checkedOnDate = JdbcSupport.getLocalDate(rs, - "checkedOnDate"); - String commandAsJson; - // commandAsJson might not be on the select list of columns - try { - commandAsJson = rs.getString("commandAsJson"); - } catch (SQLException e) { - commandAsJson = null; - } - return new AuditData(id, apiOperation, resource, resourceId, maker, - madeOnDate, checker, checkedOnDate, commandAsJson); - } - } - - @Override - public Collection retrieveAuditEntries(String extraCriteria, - boolean includeJson) { - context.authenticatedUser(); - - final AuditMapper rm = new AuditMapper(); - - String sql = "select " + rm.schema(includeJson); - if (StringUtils.isNotBlank(extraCriteria)) - sql += " where (" + extraCriteria + ")"; - sql += " order by aud.id DESC"; - - return this.jdbcTemplate.query(sql, rm, new Object[] {}); - } - - @Override - public AuditData retrieveAuditEntry(Long auditId) { - context.authenticatedUser(); - - final AuditMapper rm = new AuditMapper(); - - String sql = "select " + rm.schema(true); - sql += " where aud.id = " + auditId; - - return this.jdbcTemplate.queryForObject(sql, rm, new Object[] {}); - } - - @Override - public AuditSearchData retrieveSearchTemplate() { - Collection appUsers = appUserReadPlatformService - .retrieveSearchTemplate(); - - ApiOperationsMapper mapper = new ApiOperationsMapper(); - List apiOperations = this.jdbcTemplate.query(mapper.schema(), - mapper, new Object[] {}); - - ApiResourcesMapper mapper2 = new ApiResourcesMapper(); - List resources = this.jdbcTemplate.query(mapper2.schema(), - mapper2, new Object[] {}); - - return new AuditSearchData(appUsers, apiOperations, resources); - } - - private static final class ApiOperationsMapper implements RowMapper { - - @Override - public String mapRow(final ResultSet rs, - @SuppressWarnings("unused") final int rowNum) - throws SQLException { - - return rs.getString("apiOperation"); - } - - public String schema() { - - return " SELECT distinct(action_name) as apiOperation FROM m_permission " - + " where action_name is not null and action_name <> 'READ' " - + " order by if(action_name in ('CREATE', 'DELETE', 'UPDATE'), action_name, 'ZZZ'), action_name"; - } - - } - - private static final class ApiResourcesMapper implements RowMapper { - - @Override - public String mapRow(final ResultSet rs, - @SuppressWarnings("unused") final int rowNum) - throws SQLException { - - return rs.getString("resource"); - } - - public String schema() { - - return " select distinct(api_resource) as resource from m_portfolio_command_source order by api_resource"; - } - - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditSearchData.java b/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditSearchData.java deleted file mode 100644 index f4e839087..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditSearchData.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.mifosplatform.audit.api; - -import java.util.Collection; -import java.util.List; - -import org.mifosplatform.useradministration.data.AppUserLookup; - -/** - * Immutable data object representing client data. - */ -final public class AuditSearchData { - @SuppressWarnings("unused") - private final Collection appUsers; - @SuppressWarnings("unused") - private final List apiOperations; - @SuppressWarnings("unused") - private final List resources; - - public AuditSearchData(final Collection appUsers, - final List apiOperations, final List resources) { - - this.appUsers = appUsers; - this.apiOperations = apiOperations; - this.resources = resources; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditData.java b/mifosng-provider/src/main/java/org/mifosplatform/audit/data/AuditData.java similarity index 94% rename from mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditData.java rename to mifosng-provider/src/main/java/org/mifosplatform/audit/data/AuditData.java index ca0b24e05..2f3ea5eaa 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/audit/api/AuditData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/audit/data/AuditData.java @@ -1,11 +1,11 @@ -package org.mifosplatform.audit.api; +package org.mifosplatform.audit.data; import org.joda.time.LocalDate; /** * Immutable data object representing client data. */ -final public class AuditData { +public final class AuditData { @SuppressWarnings("unused") private final Long id; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/audit/data/AuditSearchData.java b/mifosng-provider/src/main/java/org/mifosplatform/audit/data/AuditSearchData.java new file mode 100644 index 000000000..08d03d2c5 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/audit/data/AuditSearchData.java @@ -0,0 +1,25 @@ +package org.mifosplatform.audit.data; + +import java.util.Collection; +import java.util.List; + +import org.mifosplatform.useradministration.data.AppUserLookup; + +/** + * Immutable data object representing client data. + */ +public final class AuditSearchData { + + @SuppressWarnings("unused") + private final Collection appUsers; + @SuppressWarnings("unused") + private final List apiOperations; + @SuppressWarnings("unused") + private final List resources; + + public AuditSearchData(final Collection appUsers, final List apiOperations, final List resources) { + this.appUsers = appUsers; + this.apiOperations = apiOperations; + this.resources = resources; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/audit/service/AuditReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/audit/service/AuditReadPlatformService.java new file mode 100644 index 000000000..15b78226d --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/audit/service/AuditReadPlatformService.java @@ -0,0 +1,16 @@ +package org.mifosplatform.audit.service; + +import java.util.Collection; + +import org.mifosplatform.audit.data.AuditData; +import org.mifosplatform.audit.data.AuditSearchData; + +public interface AuditReadPlatformService { + + Collection retrieveAuditEntries(String extraCriteria, boolean includeJson); + + AuditData retrieveAuditEntry(Long auditId); + + AuditSearchData retrieveSearchTemplate(); + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/audit/service/AuditReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/audit/service/AuditReadPlatformServiceImpl.java new file mode 100644 index 000000000..0eefc90bd --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/audit/service/AuditReadPlatformServiceImpl.java @@ -0,0 +1,138 @@ +package org.mifosplatform.audit.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.joda.time.LocalDate; +import org.mifosplatform.audit.data.AuditData; +import org.mifosplatform.audit.data.AuditSearchData; +import org.mifosplatform.infrastructure.core.domain.JdbcSupport; +import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.useradministration.data.AppUserLookup; +import org.mifosplatform.useradministration.service.AppUserReadPlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +public class AuditReadPlatformServiceImpl implements AuditReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + private final PlatformSecurityContext context; + private final AppUserReadPlatformService appUserReadPlatformService; + + @Autowired + public AuditReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource, + final AppUserReadPlatformService appUserReadPlatformService) { + this.context = context; + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.appUserReadPlatformService = appUserReadPlatformService; + } + + private static final class AuditMapper implements RowMapper { + + public String schema(boolean includeJson) { + + String commandAsJsonString = ""; + if (includeJson) commandAsJsonString = ", aud.command_as_json as commandAsJson "; + + return " aud.id as id, aud.api_operation as apiOperation, aud.api_resource as resource, aud.resource_id as resourceId," + + " mk.username as maker, aud.made_on_date as madeOnDate, ck.username as checker, aud.checked_on_date as checkedOnDate" + + commandAsJsonString + " from m_portfolio_command_source aud " + " left join m_appuser mk on mk.id = aud.maker_id" + + " left join m_appuser ck on ck.id = aud.checker_id"; + } + + @Override + public AuditData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long id = rs.getLong("id"); + final String apiOperation = rs.getString("apiOperation"); + final String resource = rs.getString("resource"); + final Long resourceId = JdbcSupport.getLong(rs, "resourceId"); + final String maker = rs.getString("maker"); + final LocalDate madeOnDate = JdbcSupport.getLocalDate(rs, "madeOnDate"); + final String checker = rs.getString("checker"); + final LocalDate checkedOnDate = JdbcSupport.getLocalDate(rs, "checkedOnDate"); + String commandAsJson; + // commandAsJson might not be on the select list of columns + try { + commandAsJson = rs.getString("commandAsJson"); + } catch (SQLException e) { + commandAsJson = null; + } + return new AuditData(id, apiOperation, resource, resourceId, maker, madeOnDate, checker, checkedOnDate, commandAsJson); + } + } + + @Override + public Collection retrieveAuditEntries(String extraCriteria, boolean includeJson) { + context.authenticatedUser(); + + final AuditMapper rm = new AuditMapper(); + + String sql = "select " + rm.schema(includeJson); + if (StringUtils.isNotBlank(extraCriteria)) sql += " where (" + extraCriteria + ")"; + sql += " order by aud.id DESC"; + + return this.jdbcTemplate.query(sql, rm, new Object[] {}); + } + + @Override + public AuditData retrieveAuditEntry(Long auditId) { + context.authenticatedUser(); + + final AuditMapper rm = new AuditMapper(); + + String sql = "select " + rm.schema(true); + sql += " where aud.id = " + auditId; + + return this.jdbcTemplate.queryForObject(sql, rm, new Object[] {}); + } + + @Override + public AuditSearchData retrieveSearchTemplate() { + Collection appUsers = appUserReadPlatformService.retrieveSearchTemplate(); + + ApiOperationsMapper mapper = new ApiOperationsMapper(); + List apiOperations = this.jdbcTemplate.query(mapper.schema(), mapper, new Object[] {}); + + ApiResourcesMapper mapper2 = new ApiResourcesMapper(); + List resources = this.jdbcTemplate.query(mapper2.schema(), mapper2, new Object[] {}); + + return new AuditSearchData(appUsers, apiOperations, resources); + } + + private static final class ApiOperationsMapper implements RowMapper { + + @Override + public String mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + return rs.getString("apiOperation"); + } + + public String schema() { + + return " SELECT distinct(action_name) as apiOperation FROM m_permission " + + " where action_name is not null and action_name <> 'READ' " + + " order by if(action_name in ('CREATE', 'DELETE', 'UPDATE'), action_name, 'ZZZ'), action_name"; + } + + } + + private static final class ApiResourcesMapper implements RowMapper { + + @Override + public String mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + return rs.getString("resource"); + } + + public String schema() { + return " select distinct(api_resource) as resource from m_portfolio_command_source order by api_resource"; + } + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/api/CommandsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/api/CommandsApiResource.java index c4235cd2f..d7d9d6682 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/api/CommandsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/api/CommandsApiResource.java @@ -98,6 +98,6 @@ public class CommandsApiResource { final Long id = this.writePlatformService.deleteEntry(commandId); - return this.toApiJsonSerializer.serialize(EntityIdentifier.makerChecker(id)); + return this.toApiJsonSerializer.serialize(EntityIdentifier.commandOnlyResult(id)); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandSource.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandSource.java index 5c5d85a6b..08c20a6c8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandSource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandSource.java @@ -11,7 +11,8 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import org.apache.commons.lang.StringUtils; -import org.joda.time.LocalDate; +import org.joda.time.DateTime; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.data.jpa.domain.AbstractPersistable; @@ -19,24 +20,35 @@ import org.springframework.data.jpa.domain.AbstractPersistable; @Table(name = "m_portfolio_command_source") public class CommandSource extends AbstractPersistable { - @Column(name = "api_operation", length = 20) + @Column(name = "permission_code", length = 50) + private String permissionCode; + + @Column(name = "api_operation", length = 30) private String apiOperation; - @Column(name = "api_resource", length = 20) + @Column(name = "api_resource", length = 100) private String resource; @Column(name = "resource_id") private Long resourceId; + @Column(name = "api_subresource", length = 100) + private String subResource; + + @Column(name = "subresource_id") + private Long subResourceId; + @Column(name = "command_as_json", length = 1000) private String commandAsJson; + @SuppressWarnings("unused") @ManyToOne @JoinColumn(name = "maker_id", nullable = false) private AppUser maker; + @SuppressWarnings("unused") @Column(name = "made_on_date", nullable = false) - @Temporal(TemporalType.DATE) + @Temporal(TemporalType.TIMESTAMP) private Date madeOnDate; @SuppressWarnings("unused") @@ -46,37 +58,33 @@ public class CommandSource extends AbstractPersistable { @SuppressWarnings("unused") @Column(name = "checked_on_date", nullable = false) - @Temporal(TemporalType.DATE) + @Temporal(TemporalType.TIMESTAMP) private Date checkedOnDate; - public static CommandSource createdBy(final String apiOperation, final String resource, final Long resourceId, - final String commandSerializedAsJson, final AppUser maker, final LocalDate madeOnDate) { - return new CommandSource(apiOperation, resource, resourceId, commandSerializedAsJson, maker, madeOnDate); + public static CommandSource fullEntryFrom(final CommandWrapper wrapper, final JsonCommand command, final AppUser maker) { + return new CommandSource(wrapper.taskPermissionName(), wrapper.operation(), wrapper.resourceName(), command.resourceId(), + wrapper.subResourceName(), command.subResourceId(), command.json(), maker, DateTime.now()); } protected CommandSource() { // } - private CommandSource(final String apiOperation, final String resource, final Long resourceId, final String commandSerializedAsJson, final AppUser maker, - final LocalDate madeOnDate) { + private CommandSource(final String permissionCode, final String apiOperation, final String resource, final Long resourceId, + final String subResource, final Long subResourceId, final String commandSerializedAsJson, final AppUser maker, + final DateTime madeOnDateTime) { + this.permissionCode = permissionCode; this.apiOperation = StringUtils.defaultIfEmpty(apiOperation, null); this.resource = StringUtils.defaultIfEmpty(resource, null); this.resourceId = resourceId; + this.subResource = StringUtils.defaultIfEmpty(subResource, null); + this.subResourceId = subResourceId; this.commandAsJson = commandSerializedAsJson; this.maker = maker; - this.madeOnDate = madeOnDate.toDate(); + this.madeOnDate = madeOnDateTime.toDate(); } - public CommandSource copy() { - LocalDate madeOnLocalDate = null; - if (this.madeOnDate != null) { - madeOnLocalDate = new LocalDate(this.madeOnDate); - } - return new CommandSource(this.apiOperation, this.resource, this.resourceId, this.commandAsJson, this.maker, madeOnLocalDate); - } - - public void markAsChecked(final AppUser checker, final LocalDate checkedOnDate) { + public void markAsChecked(final AppUser checker, final DateTime checkedOnDate) { this.checker = checker; this.checkedOnDate = checkedOnDate.toDate(); } @@ -85,6 +93,10 @@ public class CommandSource extends AbstractPersistable { this.resourceId = resourceId; } + public void updateSubResourceId(final Long subResourceId) { + this.subResourceId = subResourceId; + } + public void updateJsonTo(final String json) { this.commandAsJson = json; } @@ -92,7 +104,7 @@ public class CommandSource extends AbstractPersistable { public Long resourceId() { return this.resourceId; } - + public boolean hasJson() { return StringUtils.isNotBlank(this.commandAsJson); } @@ -113,81 +125,23 @@ public class CommandSource extends AbstractPersistable { return this.apiOperation; } - public boolean isCreate() { - return this.apiOperation.equalsIgnoreCase("CREATE"); + public String getPermissionCode() { + return this.permissionCode; } - public boolean isUpdate() { - // permissions resource has special update which involves no resource. - return (isPermissionResource() && isUpdateOperation()) || (isCurrencyResource() && isUpdateOperation()) - || (isUpdateOperation() && this.resourceId != null); + public String getResource() { + return this.resource; } - private boolean isUpdateOperation() { - return this.apiOperation.equalsIgnoreCase("UPDATE"); + public Long getResourceId() { + return this.resourceId; } - public boolean isDelete() { - return this.apiOperation.equalsIgnoreCase("DELETE") && this.resourceId != null; + public String getSubResource() { + return this.subResource; } - public boolean isUpdateRolePermissions() { - return this.apiOperation.equalsIgnoreCase("UPDATEPERMISSIONS") && this.resourceId != null; - } - - public boolean isPermissionResource() { - return this.resource.equalsIgnoreCase("PERMISSIONS"); - } - - public boolean isRoleResource() { - return this.resource.equalsIgnoreCase("ROLES"); - } - - public boolean isUserResource() { - return this.resource.equalsIgnoreCase("USERS"); - } - - public boolean isCurrencyResource() { - return this.resource.equalsIgnoreCase("CURRENCIES"); - } - - public boolean isCodeResource() { - return this.resource.equalsIgnoreCase("CODES"); - } - - public boolean isStaffResource() { - return this.resource.equalsIgnoreCase("STAFF"); - } - - public boolean isFundResource() { - return this.resource.equalsIgnoreCase("FUNDS"); - } - - public boolean isOfficeResource() { - return this.resource.equalsIgnoreCase("OFFICES"); - } - - public boolean isOfficeTransactionResource() { - return this.resource.equalsIgnoreCase("OFFICETRANSACTIONS"); - } - - public boolean isChargeDefinitionResource() { - return this.resource.equalsIgnoreCase("CHARGES"); - } - - public boolean isLoanProductResource() { - return this.resource.equalsIgnoreCase("LOANPRODUCTS"); - } - - public boolean isClientResource() { - return this.resource.equalsIgnoreCase("CLIENTS"); - } - - public boolean isClientIdentifierResource() { - return this.resource.toUpperCase().startsWith("CLIENTS") && this.resource.toUpperCase().endsWith("IDENTIFIERS"); - } - - public boolean isClientNoteResource() { - return this.resource.toUpperCase().startsWith("CLIENTS") && this.resource.toUpperCase().endsWith("NOTES"); + public Long getSubResourceId() { + return this.subResourceId; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandSourceRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandSourceRepository.java index 2c094f980..bc0d005c6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandSourceRepository.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandSourceRepository.java @@ -3,8 +3,6 @@ package org.mifosplatform.commands.domain; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -public interface CommandSourceRepository extends - JpaRepository, - JpaSpecificationExecutor { - // no added behaviour +public interface CommandSourceRepository extends JpaRepository, JpaSpecificationExecutor { + // no added behaviour } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java new file mode 100644 index 000000000..8f2e15946 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java @@ -0,0 +1,156 @@ +package org.mifosplatform.commands.domain; + +public class CommandWrapper { + + private final Long commandId; + private final String apiOperation; + private final String resource; + private final Long resourceId; + private final String taskPermissionName; + private final String subResource; + private final Long subResourceId; + + public static CommandWrapper wrap(final String taskPermissionName, final String apiOperation, final String resource, + final Long resourceId) { + return new CommandWrapper(null, taskPermissionName, apiOperation, resource, resourceId, null, null); + } + + public static CommandWrapper wrap(final String taskPermissionName, final String apiOperation, final String resource, + final Long resourceId, final String subResource, final Long subRescourceId) { + return new CommandWrapper(null, taskPermissionName, apiOperation, resource, resourceId, subResource, subRescourceId); + } + + public static CommandWrapper fromExistingCommand(final Long commandId, final String taskPermissionName, final String apiOperation, final String resource, + final Long resourceId, final String subResource, final Long subRescourceId) { + return new CommandWrapper(commandId, taskPermissionName, apiOperation, resource, resourceId, subResource, subRescourceId); + } + + private CommandWrapper(final Long commandId, final String taskPermissionName, final String apiOperation, final String resource, + final Long resourceId, final String subResource, final Long subResourceId) { + this.commandId = commandId; + this.taskPermissionName = taskPermissionName; + this.apiOperation = apiOperation; + this.resource = resource; + this.resourceId = resourceId; + this.subResource = subResource; + this.subResourceId = subResourceId; + } + + public String commandName() { + return this.apiOperation + '-' + this.resource; + } + + public Long commandId() { + return this.commandId; + } + + public Long resourceId() { + return this.resourceId; + } + + public String resourceName() { + return this.resource; + } + + public Long subResourceId() { + return this.subResourceId; + } + + public String subResourceName() { + return this.subResource; + } + + public String taskPermissionName() { + return this.taskPermissionName; + } + + public String operation() { + return this.apiOperation; + } + + public boolean isCreate() { + return this.apiOperation.equalsIgnoreCase("CREATE"); + } + + public boolean isUpdate() { + // permissions resource has special update which involves no resource. + return (isPermissionResource() && isUpdateOperation()) || (isCurrencyResource() && isUpdateOperation()) + || (isUpdateOperation() && this.resourceId != null); + } + + private boolean isUpdateOperation() { + return this.apiOperation.equalsIgnoreCase("UPDATE"); + } + + public boolean isDelete() { + return this.apiOperation.equalsIgnoreCase("DELETE") && this.resourceId != null; + } + + public boolean isUpdateRolePermissions() { + return this.apiOperation.equalsIgnoreCase("UPDATEPERMISSIONS") && this.resourceId != null; + } + + public boolean isPermissionResource() { + return this.resource.equalsIgnoreCase("PERMISSIONS"); + } + + public boolean isRoleResource() { + return this.resource.equalsIgnoreCase("ROLES"); + } + + public boolean isUserResource() { + return this.resource.equalsIgnoreCase("USERS"); + } + + public boolean isCurrencyResource() { + return this.resource.equalsIgnoreCase("CURRENCIES"); + } + + public boolean isCodeResource() { + return this.resource.equalsIgnoreCase("CODES"); + } + + public boolean isStaffResource() { + return this.resource.equalsIgnoreCase("STAFF"); + } + + public boolean isFundResource() { + return this.resource.equalsIgnoreCase("FUNDS"); + } + + public boolean isOfficeResource() { + return this.resource.equalsIgnoreCase("OFFICES"); + } + + public boolean isOfficeTransactionResource() { + return this.resource.equalsIgnoreCase("OFFICETRANSACTIONS"); + } + + public boolean isChargeDefinitionResource() { + return this.resource.equalsIgnoreCase("CHARGES"); + } + + public boolean isLoanProductResource() { + return this.resource.equalsIgnoreCase("LOANPRODUCTS"); + } + + public boolean isClientResource() { + return this.resource.equalsIgnoreCase("CLIENTS"); + } + + public boolean isClientIdentifierResource() { + return isClientResource() && isIdentifiersSubResource(); + } + + public boolean isClientNoteResource() { + return isClientResource() && isNotesSubResource(); + } + + public boolean isNotesSubResource() { + return "NOTES".equalsIgnoreCase(this.subResource); + } + + public boolean isIdentifiersSubResource() { + return "IDENTIFIERS".equalsIgnoreCase(this.subResource); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ChargeDefinitionCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ChargeDefinitionCommandHandler.java deleted file mode 100644 index 6fb3574d3..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ChargeDefinitionCommandHandler.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.portfolio.charge.command.ChargeDefinitionCommand; -import org.mifosplatform.portfolio.charge.serialization.ChargeCommandFromCommandJsonDeserializer; -import org.mifosplatform.portfolio.charge.service.ChargeWritePlatformService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class ChargeDefinitionCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final ChargeCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer; - private final ChargeWritePlatformService writePlatformService; - - @Autowired - public ChargeDefinitionCommandHandler(final PlatformSecurityContext context, - final ChargeCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer, - final ChargeWritePlatformService writePlatformService) { - this.context = context; - this.commandFromCommandJsonDeserializer = commandFromCommandJsonDeserializer; - this.writePlatformService = writePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - CommandSource commandSourceResult = commandSource.copy(); - - final Long resourceId = commandSource.resourceId(); - final ChargeDefinitionCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson(resourceId, - commandSourceResult.json()); - - if (commandSource.isCreate()) { - try { - Long newResourceId = this.writePlatformService.createCharge(command); - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(newResourceId); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - try { - this.writePlatformService.updateCharge(command); - - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { - try { - this.writePlatformService.deleteCharge(command); - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - Long resourceId = commandSourceResult.resourceId(); - final ChargeDefinitionCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson(resourceId, - commandSourceResult.json(), true); - - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "CREATE_CHARGE_MAKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_CHARGE_MAKER", allowedPermissions); - - resourceId = this.writePlatformService.createCharge(command); - commandSourceResult.updateResourceId(resourceId); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "UPDATE_CHARGE_MAKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CHARGE_MAKER", allowedPermissions); - - this.writePlatformService.updateCharge(command); - - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "DELETE_CHARGE_MAKER"); - context.authenticatedUser().validateHasPermissionTo("DELETE_CHARGE_MAKER", allowedPermissions); - - this.writePlatformService.deleteCharge(command); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ClientCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ClientCommandHandler.java deleted file mode 100644 index c8bd30987..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ClientCommandHandler.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.infrastructure.core.api.JsonCommand; -import org.mifosplatform.infrastructure.core.data.EntityIdentifier; -import org.mifosplatform.infrastructure.core.serialization.ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.portfolio.client.service.ClientWritePlatformService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.google.gson.JsonElement; - -@Service -public class ClientCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final ClientWritePlatformService clientWritePlatformService; - private final FromJsonHelper fromApiJsonHelper; - private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer; - - @Autowired - public ClientCommandHandler(final PlatformSecurityContext context, final FromJsonHelper fromApiJsonHelper, - final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer, - final ClientWritePlatformService clientWritePlatformService) { - this.context = context; - this.fromApiJsonHelper = fromApiJsonHelper; - this.toApiJsonSerializer = toApiJsonSerializer; - this.clientWritePlatformService = clientWritePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSource.json()); - final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper); - - CommandSource commandSourceResult = commandSource.copy(); - if (commandSource.isCreate()) { - try { - Long newResourceId = this.clientWritePlatformService.createClient(command); - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(newResourceId); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - try { - EntityIdentifier result = this.clientWritePlatformService.updateClientDetails(commandSource.resourceId(), command); - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { - try { - this.clientWritePlatformService.deleteClient(commandSource.resourceId(), command); - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - final JsonElement parsedCommand = fromApiJsonHelper.parse(commandSourceResult.json()); - final JsonCommand command = JsonCommand.withMakerCheckerApproval(commandSourceResult.json(), parsedCommand, fromApiJsonHelper); - - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", - "CREATE_CLIENT_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_CLIENT_CHECKER", allowedPermissions); - - Long resourceId = this.clientWritePlatformService.createClient(command); - commandSourceResult.updateResourceId(resourceId); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", - "UPDATE_CLIENT_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CLIENT_CHECKER", allowedPermissions); - - EntityIdentifier result = this.clientWritePlatformService.updateClientDetails(commandSourceResult.resourceId(), command); - - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", - "DELETE_CLIENT_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("DELETE_CLIENT_CHECKER", allowedPermissions); - - this.clientWritePlatformService.deleteClient(commandSourceResult.resourceId(), command); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ClientIdentifierCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ClientIdentifierCommandHandler.java deleted file mode 100644 index beaf22718..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ClientIdentifierCommandHandler.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.portfolio.client.command.ClientIdentifierCommand; -import org.mifosplatform.portfolio.client.serialization.ClientIdentifierCommandFromCommandJsonDeserializer; -import org.mifosplatform.portfolio.client.service.ClientWritePlatformService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class ClientIdentifierCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final ClientWritePlatformService clientWritePlatformService; - private final ClientIdentifierCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer; - - @Autowired - public ClientIdentifierCommandHandler(final PlatformSecurityContext context, - final ClientIdentifierCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer, - final ClientWritePlatformService clientWritePlatformService) { - this.context = context; - this.commandFromCommandJsonDeserializer = commandFromCommandJsonDeserializer; - this.clientWritePlatformService = clientWritePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - final ClientIdentifierCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson(commandSource.resourceId(), - commandSource.json()); - CommandSource commandSourceResult = commandSource.copy(); - - if (commandSource.isCreate()) { - try { - Long newResourceId = this.clientWritePlatformService.addClientIdentifier(command); - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(newResourceId); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - try { - this.clientWritePlatformService.updateClientIdentifier(command); - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { - try { - this.clientWritePlatformService.deleteClientIdentifier(command); - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - final ClientIdentifierCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson( - commandSourceResult.resourceId(), commandSourceResult.json(), true); - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", - "CREATE_CLIENTIDENTIFIER_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_CLIENTIDENTIFIER_CHECKER", allowedPermissions); - - Long resourceId = this.clientWritePlatformService.addClientIdentifier(command); - commandSourceResult.updateResourceId(resourceId); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", - "UPDATE_CLIENTIDENTIFIER_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CLIENTIDENTIFIER_CHECKER", allowedPermissions); - - this.clientWritePlatformService.updateClientIdentifier(command); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", - "DELETE_CLIENTIDENTIFIER_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("DELETE_CLIENTIDENTIFIER_CHECKER", allowedPermissions); - - this.clientWritePlatformService.deleteClientIdentifier(command); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ClientNoteCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ClientNoteCommandHandler.java deleted file mode 100644 index cc06a6f9d..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/ClientNoteCommandHandler.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.commands.exception.UnsupportedCommandException; -import org.mifosplatform.infrastructure.core.data.EntityIdentifier; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.portfolio.client.command.ClientNoteCommand; -import org.mifosplatform.portfolio.client.serialization.ClientNoteCommandFromCommandJsonDeserializer; -import org.mifosplatform.portfolio.client.service.ClientWritePlatformService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class ClientNoteCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final ClientWritePlatformService clientWritePlatformService; - private final ClientNoteCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer; - - @Autowired - public ClientNoteCommandHandler(final PlatformSecurityContext context, - final ClientNoteCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer, - final ClientWritePlatformService clientWritePlatformService) { - this.context = context; - this.commandFromCommandJsonDeserializer = commandFromCommandJsonDeserializer; - this.clientWritePlatformService = clientWritePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - final ClientNoteCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson(commandSource.resourceId(), - commandSource.json()); - CommandSource commandSourceResult = commandSource.copy(); - - if (commandSource.isCreate()) { - try { - EntityIdentifier result = this.clientWritePlatformService.addClientNote(command); - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(result.getEntityId()); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - try { - this.clientWritePlatformService.updateNote(command); - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { throw new UnsupportedCommandException(commandSource.commandName()); } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - final ClientNoteCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson(commandSourceResult.resourceId(), - commandSourceResult.json(), true); - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", - "CREATE_CLIENTNOTE_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_CLIENTNOTE_CHECKER", allowedPermissions); - - EntityIdentifier result = this.clientWritePlatformService.addClientNote(command); - commandSourceResult.updateResourceId(result.getEntityId()); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", - "UPDATE_CLIENTNOTE_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CLIENTNOTE_CHECKER", allowedPermissions); - - this.clientWritePlatformService.updateNote(command); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { throw new UnsupportedCommandException(commandSourceResult.commandName()); } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CodeCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CodeCommandHandler.java deleted file mode 100644 index 0decf5145..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CodeCommandHandler.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.infrastructure.codes.service.CodeWritePlatformService; -import org.mifosplatform.infrastructure.core.api.JsonCommand; -import org.mifosplatform.infrastructure.core.data.EntityIdentifier; -import org.mifosplatform.infrastructure.core.serialization.ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.google.gson.JsonElement; - -@Service -public class CodeCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final FromJsonHelper fromApiJsonHelper; - private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer; - private final CodeWritePlatformService writePlatformService; - - @Autowired - public CodeCommandHandler(final PlatformSecurityContext context, - final FromJsonHelper fromApiJsonHelper, - final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer, - final CodeWritePlatformService writePlatformService) { - this.context = context; - this.fromApiJsonHelper = fromApiJsonHelper; - this.toApiJsonSerializer = toApiJsonSerializer; - this.writePlatformService = writePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - final Long resourceId = commandSource.resourceId(); - final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSource.json()); - final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper); - - CommandSource commandSourceResult = commandSource.copy(); - - if (commandSource.isCreate()) { - try { - Long newResourceId = this.writePlatformService.createCode(command); - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(newResourceId); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - try { - EntityIdentifier result = this.writePlatformService.updateCode(resourceId, command); - - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { - try { - this.writePlatformService.deleteCode(resourceId, command); - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - Long resourceId = commandSourceResult.resourceId(); - final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSourceResult.json()); - final JsonCommand command = JsonCommand.withMakerCheckerApproval(commandSourceResult.json(), parsedCommand, this.fromApiJsonHelper); - - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "CREATE_CODE_MAKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_CODE_MAKER", allowedPermissions); - - resourceId = this.writePlatformService.createCode(command); - commandSourceResult.updateResourceId(resourceId); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "UPDATE_CODE_MAKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CODE_MAKER", allowedPermissions); - - EntityIdentifier result = this.writePlatformService.updateCode(resourceId, command); - - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "DELETE_CODE_MAKER"); - context.authenticatedUser().validateHasPermissionTo("DELETE_CODE_MAKER", allowedPermissions); - - this.writePlatformService.deleteCode(resourceId, command); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CommandSourceHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CommandSourceHandler.java deleted file mode 100644 index 3f529654f..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CommandSourceHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.mifosplatform.commands.handler; - -import org.mifosplatform.commands.domain.CommandSource; - -public interface CommandSourceHandler { - - /* - * Used when users with 'create' capability create a command. If - * 'maker-checker' is not enabled for this specific command then the - * 'creator' is also marked 'as the checker' and command automatically is - * processed and changes state of system. - */ - CommandSource handleCommandWithSupportForRollback(CommandSource commandSource); - - /* - * Used when users with 'checker' capability approve a command. - */ - CommandSource handleCommandForCheckerApproval(CommandSource commandSourceResult); -} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CommandSourceHandlerDelegator.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CommandSourceHandlerDelegator.java deleted file mode 100644 index 8590d49b9..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CommandSourceHandlerDelegator.java +++ /dev/null @@ -1,140 +0,0 @@ -package org.mifosplatform.commands.handler; - -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.commands.exception.UnsupportedCommandException; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** - * A class to delegate handling of commands to appropriate handler. - */ -@Service -public class CommandSourceHandlerDelegator { - - private final PlatformSecurityContext context; - private final ClientCommandHandler clientCommandHandler; - private final RoleCommandHandler roleCommandHandler; - private final PermissionsCommandHandler permissionCommandHandler; - private final UserCommandHandler userCommandHandler; - private final CodeCommandHandler codeCommandHandler; - private final StaffCommandHandler staffCommandHandler; - private final FundCommandHandler fundCommandHandler; - private final OfficeCommandHandler officeCommandHandler; - private final OfficeTransactionCommandHandler officeTransactionCommandHandler; - private final CurrencyCommandHandler currencyCommandHandler; - private final ChargeDefinitionCommandHandler chargeDefinitionCommandHandler; - private final LoanProductCommandHandler loanProductCommandHandler; - private final ClientIdentifierCommandHandler clientIdentifierCommandHandler; - private final ClientNoteCommandHandler clientNoteCommandHandler; - - @Autowired - public CommandSourceHandlerDelegator(final PlatformSecurityContext context, - final ClientCommandHandler clientCommandHandler, - final ClientIdentifierCommandHandler clientIdentifierCommandHandler, - final ClientNoteCommandHandler clientNoteCommandHandler, - final RoleCommandHandler roleCommandHandler, - final PermissionsCommandHandler permissionCommandHandler, - final UserCommandHandler userCommandHandler, - final CodeCommandHandler codeCommandHandler, - final StaffCommandHandler staffCommandHandler, - final FundCommandHandler fundCommandHandler, - final OfficeCommandHandler officeCommandHandler, - final OfficeTransactionCommandHandler officeTransactionCommandHandler, - final CurrencyCommandHandler currencyCommandHandler, - final ChargeDefinitionCommandHandler chargeDefinitionCommandHandler, - final LoanProductCommandHandler loanProductCommandHandler) { - this.context = context; - this.clientCommandHandler = clientCommandHandler; - this.clientIdentifierCommandHandler = clientIdentifierCommandHandler; - this.clientNoteCommandHandler = clientNoteCommandHandler; - this.roleCommandHandler = roleCommandHandler; - this.permissionCommandHandler = permissionCommandHandler; - this.userCommandHandler = userCommandHandler; - this.codeCommandHandler = codeCommandHandler; - this.staffCommandHandler = staffCommandHandler; - this.fundCommandHandler = fundCommandHandler; - this.officeCommandHandler = officeCommandHandler; - this.officeTransactionCommandHandler = officeTransactionCommandHandler; - this.currencyCommandHandler = currencyCommandHandler; - this.chargeDefinitionCommandHandler = chargeDefinitionCommandHandler; - this.loanProductCommandHandler = loanProductCommandHandler; - } - - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - context.authenticatedUser(); - CommandSource commandSourceResult = null; - if (commandSource.isClientResource()) { - commandSourceResult = clientCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isClientIdentifierResource()) { - commandSourceResult = clientIdentifierCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isClientNoteResource()) { - commandSourceResult = clientNoteCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isRoleResource()) { - commandSourceResult = roleCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isPermissionResource()) { - commandSourceResult = permissionCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isUserResource()) { - commandSourceResult = userCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isCodeResource()) { - commandSourceResult = codeCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isStaffResource()) { - commandSourceResult = staffCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isFundResource()) { - commandSourceResult = fundCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isOfficeResource()) { - commandSourceResult = officeCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isOfficeTransactionResource()) { - commandSourceResult = officeTransactionCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isCurrencyResource()) { - commandSourceResult = currencyCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isChargeDefinitionResource()) { - commandSourceResult = chargeDefinitionCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else if (commandSource.isLoanProductResource()) { - commandSourceResult = loanProductCommandHandler.handleCommandWithSupportForRollback(commandSource); - } else { - throw new UnsupportedCommandException(commandSource.commandName()); - } - - return commandSourceResult; - } - - public CommandSource handleCommandForCheckerApproval(final CommandSource existingCommandSource) { - - CommandSource commandSourceResult = null; - if (existingCommandSource.isClientResource()) { - commandSourceResult = clientCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else if (existingCommandSource.isClientIdentifierResource()) { - commandSourceResult = clientIdentifierCommandHandler.handleCommandWithSupportForRollback(existingCommandSource); - } else if (existingCommandSource.isClientNoteResource()) { - commandSourceResult = clientNoteCommandHandler.handleCommandWithSupportForRollback(existingCommandSource); - } else if (existingCommandSource.isRoleResource()) { - commandSourceResult = roleCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else if (existingCommandSource.isPermissionResource()) { - commandSourceResult = permissionCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else if (existingCommandSource.isUserResource()) { - commandSourceResult = userCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else if (existingCommandSource.isCodeResource()) { - commandSourceResult = codeCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else if (existingCommandSource.isStaffResource()) { - commandSourceResult = staffCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else if (existingCommandSource.isFundResource()) { - commandSourceResult = fundCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else if (existingCommandSource.isOfficeResource()) { - commandSourceResult = officeCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else if (existingCommandSource.isOfficeTransactionResource()) { - commandSourceResult = officeTransactionCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else if (existingCommandSource.isCurrencyResource()) { - commandSourceResult = currencyCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else if (existingCommandSource.isChargeDefinitionResource()) { - commandSourceResult = chargeDefinitionCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else if (existingCommandSource.isLoanProductResource()) { - commandSourceResult = loanProductCommandHandler.handleCommandForCheckerApproval(existingCommandSource); - } else { - throw new UnsupportedCommandException(existingCommandSource.commandName()); - } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CurrencyCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CurrencyCommandHandler.java deleted file mode 100644 index ab4ab71cf..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/CurrencyCommandHandler.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.commands.exception.UnsupportedCommandException; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.monetary.command.CurrencyCommand; -import org.mifosplatform.organisation.monetary.serialization.CurrencyCommandFromCommandJsonDeserializer; -import org.mifosplatform.organisation.monetary.service.CurrencyWritePlatformService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class CurrencyCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final CurrencyCommandFromCommandJsonDeserializer fromApiJsonDeserializer; - private final CurrencyWritePlatformService writePlatformService; - - @Autowired - public CurrencyCommandHandler(final PlatformSecurityContext context, - final CurrencyCommandFromCommandJsonDeserializer fromApiJsonDeserializer, - final CurrencyWritePlatformService writePlatformService) { - this.context = context; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; - this.writePlatformService = writePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - CommandSource commandSourceResult = commandSource.copy(); - - if (commandSource.isCreate()) { - throw new UnsupportedCommandException(commandSource.commandName()); - } else if (commandSource.isUpdate()) { - try { - final CurrencyCommand command = this.fromApiJsonDeserializer.commandFromCommandJson(commandSource.json()); - this.writePlatformService.updateAllowedCurrencies(command); - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { throw new UnsupportedCommandException(commandSource.commandName()); } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - final CurrencyCommand command = this.fromApiJsonDeserializer.commandFromCommandJson(commandSourceResult.resourceId(), - commandSourceResult.json(), true); - if (commandSourceResult.isCreate()) { - throw new UnsupportedCommandException(commandSourceResult.commandName()); - } else if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "UPDATE_CURRENCY_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CURRENCY_CHECKER", allowedPermissions); - - this.writePlatformService.updateAllowedCurrencies(command); - - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { throw new UnsupportedCommandException(commandSourceResult.commandName()); } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/FundCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/FundCommandHandler.java deleted file mode 100644 index b45f06ed4..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/FundCommandHandler.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.commands.exception.UnsupportedCommandException; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.portfolio.fund.command.FundCommand; -import org.mifosplatform.portfolio.fund.serialization.FundCommandFromCommandJsonDeserializer; -import org.mifosplatform.portfolio.fund.service.FundWritePlatformService; -import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class FundCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final FundCommandFromCommandJsonDeserializer fromCommandJsonDeserializer; - private final FundWritePlatformService writePlatformService; - - @Autowired - public FundCommandHandler(final PlatformSecurityContext context, - final FundCommandFromCommandJsonDeserializer fromCommandJsonDeserializer, final FundWritePlatformService writePlatformService) { - this.context = context; - this.fromCommandJsonDeserializer = fromCommandJsonDeserializer; - this.writePlatformService = writePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - final Long resourceId = commandSource.resourceId(); - final FundCommand command = this.fromCommandJsonDeserializer.commandFromCommandJson(resourceId, commandSource.json()); - - CommandSource commandSourceResult = commandSource.copy(); - - Long newResourceId = null; - - if (commandSource.isCreate()) { - try { - newResourceId = this.writePlatformService.createFund(command); - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(newResourceId); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - try { - this.writePlatformService.updateFund(command); - - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { throw new UnsupportedCommandException(commandSource.commandName()); } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - Long resourceId = commandSourceResult.resourceId(); - final FundCommand command = this.fromCommandJsonDeserializer.commandFromCommandJson(resourceId, commandSourceResult.json(), true); - - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "CREATE_FUND_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_FUND_CHECKER", allowedPermissions); - - resourceId = this.writePlatformService.createFund(command); - commandSourceResult.updateResourceId(resourceId); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "UPDATE_FUND_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_FUND_CHECKER", allowedPermissions); - - resourceId = this.writePlatformService.updateFund(command); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { throw new UnsupportedCommandException(commandSourceResult.commandName()); } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/LoanProductCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/LoanProductCommandHandler.java deleted file mode 100644 index 969fff236..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/LoanProductCommandHandler.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.commands.exception.UnsupportedCommandException; -import org.mifosplatform.infrastructure.core.data.EntityIdentifier; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; -import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductCommandFromCommandJsonDeserializer; -import org.mifosplatform.portfolio.loanproduct.service.LoanProductWritePlatformService; -import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class LoanProductCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final LoanProductCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer; - private final LoanProductWritePlatformService writePlatformService; - - @Autowired - public LoanProductCommandHandler(final PlatformSecurityContext context, - final LoanProductCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer, - final LoanProductWritePlatformService writePlatformService) { - this.context = context; - this.commandFromCommandJsonDeserializer = commandFromCommandJsonDeserializer; - this.writePlatformService = writePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - final Long resourceId = commandSource.resourceId(); - final LoanProductCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson(resourceId, commandSource.json()); - CommandSource commandSourceResult = commandSource.copy(); - - if (commandSource.isCreate()) { - try { - EntityIdentifier result = this.writePlatformService.createLoanProduct(command); - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(result.getEntityId()); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - try { - this.writePlatformService.updateLoanProduct(command); - - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { throw new UnsupportedCommandException(commandSource.commandName()); } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - Long resourceId = commandSourceResult.resourceId(); - final LoanProductCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson(resourceId, - commandSourceResult.json(), true); - - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "CREATE_LOANPRODUCT_MAKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_LOANPRODUCT_MAKER", allowedPermissions); - - EntityIdentifier result = this.writePlatformService.createLoanProduct(command); - commandSourceResult.updateResourceId(result.getEntityId()); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "UPDATE_LOANPRODUCT_MAKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_LOANPRODUCT_MAKER", allowedPermissions); - - this.writePlatformService.updateLoanProduct(command); - - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { throw new UnsupportedCommandException(commandSourceResult.commandName()); } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/NewCommandSourceHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/NewCommandSourceHandler.java new file mode 100644 index 000000000..c9dd0850e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/NewCommandSourceHandler.java @@ -0,0 +1,9 @@ +package org.mifosplatform.commands.handler; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; + +public interface NewCommandSourceHandler { + + EntityIdentifier processCommand(JsonCommand command); +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/OfficeCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/OfficeCommandHandler.java deleted file mode 100644 index 3682e25db..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/OfficeCommandHandler.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.commands.exception.UnsupportedCommandException; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.office.command.OfficeCommand; -import org.mifosplatform.organisation.office.serialization.OfficeCommandFromCommandJsonDeserializer; -import org.mifosplatform.organisation.office.service.OfficeWritePlatformService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class OfficeCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final OfficeCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer; - private final OfficeWritePlatformService writePlatformService; - - @Autowired - public OfficeCommandHandler(final PlatformSecurityContext context, - final OfficeCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer, - final OfficeWritePlatformService writePlatformService) { - this.context = context; - this.commandFromCommandJsonDeserializer = commandFromCommandJsonDeserializer; - this.writePlatformService = writePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - final Long resourceId = commandSource.resourceId(); - final OfficeCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson(resourceId, commandSource.json()); - - CommandSource commandSourceResult = commandSource.copy(); - - Long newResourceId = null; - - if (commandSource.isCreate()) { - try { - newResourceId = this.writePlatformService.createOffice(command); - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(newResourceId); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - try { - this.writePlatformService.updateOffice(command); - - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { throw new UnsupportedCommandException(commandSource.commandName()); } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - Long resourceId = commandSourceResult.resourceId(); - final OfficeCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson(resourceId, - commandSourceResult.json(), true); - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "CREATE_OFFICE_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_OFFICE_CHECKER", allowedPermissions); - - resourceId = this.writePlatformService.createOffice(command); - commandSourceResult.updateResourceId(resourceId); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "UPDATE_OFFICE_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_OFFICE_CHECKER", allowedPermissions); - - resourceId = this.writePlatformService.updateOffice(command); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { throw new UnsupportedCommandException(commandSourceResult.commandName()); } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/OfficeTransactionCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/OfficeTransactionCommandHandler.java deleted file mode 100644 index 134793d03..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/OfficeTransactionCommandHandler.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.commands.exception.UnsupportedCommandException; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.office.command.BranchMoneyTransferCommand; -import org.mifosplatform.organisation.office.serialization.BranchMoneyTransferCommandFromCommandJsonDeserializer; -import org.mifosplatform.organisation.office.service.OfficeWritePlatformService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class OfficeTransactionCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final BranchMoneyTransferCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer; - private final OfficeWritePlatformService writePlatformService; - - @Autowired - public OfficeTransactionCommandHandler(final PlatformSecurityContext context, - final BranchMoneyTransferCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer, - final OfficeWritePlatformService writePlatformService) { - this.context = context; - this.commandFromCommandJsonDeserializer = commandFromCommandJsonDeserializer; - this.writePlatformService = writePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - Long resourceId = commandSource.resourceId(); - final BranchMoneyTransferCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson(resourceId, - commandSource.json()); - CommandSource commandSourceResult = commandSource.copy(); - - Long newResourceId = null; - if (commandSource.isCreate()) { - try { - newResourceId = this.writePlatformService.externalBranchMoneyTransfer(command); - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(newResourceId); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - throw new UnsupportedCommandException(commandSource.commandName()); - } else if (commandSource.isDelete()) { throw new UnsupportedCommandException(commandSource.commandName()); } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - Long resourceId = commandSourceResult.resourceId(); - final BranchMoneyTransferCommand command = this.commandFromCommandJsonDeserializer.commandFromCommandJson(resourceId, - commandSourceResult.json(), true); - - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "CREATE_OFFICETRANSACTION_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_OFFICETRANSACTION_CHECKER", allowedPermissions); - - resourceId = this.writePlatformService.externalBranchMoneyTransfer(command); - commandSourceResult.updateResourceId(resourceId); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdate()) { - throw new UnsupportedCommandException(commandSourceResult.commandName()); - } else if (commandSourceResult.isDelete()) { throw new UnsupportedCommandException(commandSourceResult.commandName()); } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/PermissionsCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/PermissionsCommandHandler.java deleted file mode 100644 index 3daba1a7b..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/PermissionsCommandHandler.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.commands.exception.UnsupportedCommandException; -import org.mifosplatform.infrastructure.core.api.JsonCommand; -import org.mifosplatform.infrastructure.core.data.EntityIdentifier; -import org.mifosplatform.infrastructure.core.serialization.ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.mifosplatform.useradministration.service.PermissionWritePlatformService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.google.gson.JsonElement; - -@Service -public class PermissionsCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final FromJsonHelper fromApiJsonHelper; - private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer; - private final PermissionWritePlatformService permissionWritePlatformService; - - @Autowired - public PermissionsCommandHandler(final PlatformSecurityContext context, - final FromJsonHelper fromApiJsonHelper, - final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer, - final PermissionWritePlatformService permissionWritePlatformService) { - this.context = context; - this.fromApiJsonHelper = fromApiJsonHelper; - this.toApiJsonSerializer = toApiJsonSerializer; - this.permissionWritePlatformService = permissionWritePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSource.json()); - final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper); - - CommandSource commandSourceResult = commandSource.copy(); - - if (commandSource.isUpdate()) { - try { - EntityIdentifier result = this.permissionWritePlatformService.updateMakerCheckerPermissions(command); - - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else { - throw new UnsupportedCommandException(commandSource.commandName()); - } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSourceResult.json()); - final JsonCommand command = JsonCommand.withMakerCheckerApproval(commandSourceResult.json(), parsedCommand, this.fromApiJsonHelper); - - if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", - "UPDATE_PERMISSION_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_PERMISSION_CHECKER", allowedPermissions); - - EntityIdentifier result = this.permissionWritePlatformService.updateMakerCheckerPermissions(command); - - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else { - throw new UnsupportedCommandException(commandSourceResult.commandName()); - } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/RoleCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/RoleCommandHandler.java deleted file mode 100644 index 00ec71274..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/RoleCommandHandler.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.commands.exception.UnsupportedCommandException; -import org.mifosplatform.infrastructure.core.api.JsonCommand; -import org.mifosplatform.infrastructure.core.data.EntityIdentifier; -import org.mifosplatform.infrastructure.core.serialization.ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.mifosplatform.useradministration.service.RoleWritePlatformService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.google.gson.JsonElement; - -@Service -public class RoleCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final RoleWritePlatformService writePlatformService; - private final FromJsonHelper fromApiJsonHelper; - private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer; - - @Autowired - public RoleCommandHandler(final PlatformSecurityContext context, - final FromJsonHelper fromApiJsonHelper, - final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer, - final RoleWritePlatformService writePlatformService) { - this.context = context; - this.fromApiJsonHelper = fromApiJsonHelper; - this.toApiJsonSerializer = toApiJsonSerializer; - this.writePlatformService = writePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - CommandSource commandSourceResult = commandSource.copy(); - - final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSource.json()); - final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper); - final Long resourceId = commandSource.resourceId(); - if (commandSource.isCreate()) { - try { - - final Long newResourceId = this.writePlatformService.createRole(command); - - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(newResourceId); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - try { - final EntityIdentifier result = this.writePlatformService.updateRole(resourceId, command); - - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdateRolePermissions()) { - try { - final EntityIdentifier result = this.writePlatformService.updateRolePermissions(resourceId, command); - - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { throw new UnsupportedCommandException(commandSource.commandName()); } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSourceResult.json()); - final JsonCommand command = JsonCommand.withMakerCheckerApproval(commandSourceResult.json(), parsedCommand, this.fromApiJsonHelper); - final Long resourceId = commandSourceResult.resourceId(); - - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "CREATE_ROLE_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_ROLE_CHECKER", allowedPermissions); - - final Long newResourceId = this.writePlatformService.createRole(command); - - commandSourceResult.updateResourceId(newResourceId); - commandSourceResult.markAsChecked(checker, new LocalDate()); - - } else if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "UPDATE_ROLE_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_ROLE_CHECKER", allowedPermissions); - - final EntityIdentifier result = this.writePlatformService.updateRole(resourceId, command); - - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdateRolePermissions()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", - "PERMISSIONS_ROLE_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("PERMISSIONS_ROLE_CHECKER", allowedPermissions); - - EntityIdentifier result = this.writePlatformService.updateRolePermissions(resourceId, command); - - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { throw new UnsupportedCommandException(commandSourceResult.commandName()); } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/StaffCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/StaffCommandHandler.java deleted file mode 100644 index eb83a80d5..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/StaffCommandHandler.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.commands.exception.UnsupportedCommandException; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.staff.command.StaffCommand; -import org.mifosplatform.organisation.staff.serialization.StaffCommandFromCommandJsonDeserializer; -import org.mifosplatform.organisation.staff.service.StaffWritePlatformService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class StaffCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final StaffCommandFromCommandJsonDeserializer fromCommandJsonDeserializer; - private final StaffWritePlatformService writePlatformService; - - @Autowired - public StaffCommandHandler(final PlatformSecurityContext context, - final StaffCommandFromCommandJsonDeserializer fromCommandJsonDeserializer, final StaffWritePlatformService writePlatformService) { - this.context = context; - this.fromCommandJsonDeserializer = fromCommandJsonDeserializer; - this.writePlatformService = writePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - final Long resourceId = commandSource.resourceId(); - final StaffCommand command = this.fromCommandJsonDeserializer.commandFromCommandJson(resourceId, commandSource.json()); - CommandSource commandSourceResult = commandSource.copy(); - - Long newResourceId = null; - if (commandSource.isCreate()) { - try { - newResourceId = this.writePlatformService.createStaff(command); - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(newResourceId); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - try { - this.writePlatformService.updateStaff(command); - - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { throw new UnsupportedCommandException(commandSource.commandName()); } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - Long resourceId = commandSourceResult.resourceId(); - final StaffCommand command = this.fromCommandJsonDeserializer.commandFromCommandJson(resourceId, commandSourceResult.json(), true); - - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "CREATE_STAFF_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_STAFF_CHECKER", allowedPermissions); - - resourceId = this.writePlatformService.createStaff(command); - commandSourceResult.updateResourceId(resourceId); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "UPDATE_STAFF_CHECKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_STAFF_CHECKER", allowedPermissions); - - resourceId = this.writePlatformService.updateStaff(command); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { throw new UnsupportedCommandException(commandSourceResult.commandName()); } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/UserCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/UserCommandHandler.java deleted file mode 100644 index 8eea8953e..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/handler/UserCommandHandler.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.mifosplatform.commands.handler; - -import java.util.Arrays; -import java.util.List; - -import org.joda.time.LocalDate; -import org.mifosplatform.commands.domain.CommandSource; -import org.mifosplatform.infrastructure.core.api.JsonCommand; -import org.mifosplatform.infrastructure.core.data.EntityIdentifier; -import org.mifosplatform.infrastructure.core.serialization.ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; -import org.mifosplatform.useradministration.domain.AppUser; -import org.mifosplatform.useradministration.service.AppUserWritePlatformService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.google.gson.JsonElement; - -@Service -public class UserCommandHandler implements CommandSourceHandler { - - private final PlatformSecurityContext context; - private final FromJsonHelper fromApiJsonHelper; - private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer; - private final AppUserWritePlatformService writePlatformService; - - @Autowired - public UserCommandHandler(final PlatformSecurityContext context, final FromJsonHelper fromApiJsonHelper, - final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer, - final AppUserWritePlatformService writePlatformService) { - this.context = context; - this.fromApiJsonHelper = fromApiJsonHelper; - this.toApiJsonSerializer = toApiJsonSerializer; - this.writePlatformService = writePlatformService; - } - - @Override - public CommandSource handleCommandWithSupportForRollback(final CommandSource commandSource) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - final Long resourceId = commandSource.resourceId(); - final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSource.json()); - final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper); - - CommandSource commandSourceResult = commandSource.copy(); - if (commandSource.isCreate()) { - try { - final Long newResourceId = this.writePlatformService.createUser(command); - - commandSourceResult.markAsChecked(maker, asToday); - commandSourceResult.updateResourceId(newResourceId); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isUpdate()) { - try { - EntityIdentifier result = null; - if (maker.hasIdOf(resourceId)) { - result = this.writePlatformService.updateUsersOwnAccountDetails(resourceId, command); - } else { - result = this.writePlatformService.updateUser(resourceId, command); - } - - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } else if (commandSource.isDelete()) { - try { - this.writePlatformService.deleteUser(resourceId, command); - commandSourceResult.markAsChecked(maker, asToday); - } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { - // swallow this rollback transaction by design - } - } - - return commandSourceResult; - } - - @Override - public CommandSource handleCommandForCheckerApproval(final CommandSource commandSourceResult) { - - final AppUser checker = context.authenticatedUser(); - - final Long resourceId = commandSourceResult.resourceId(); - final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSourceResult.json()); - final JsonCommand command = JsonCommand.withMakerCheckerApproval(commandSourceResult.json(), parsedCommand, this.fromApiJsonHelper); - - if (commandSourceResult.isUserResource()) { - if (commandSourceResult.isCreate()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", - "CREATE_USER_MAKER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_USER_MAKER", allowedPermissions); - - final Long newResourceId = this.writePlatformService.createUser(command); - commandSourceResult.updateResourceId(newResourceId); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isUpdate()) { - EntityIdentifier result = null; - if (checker.hasIdOf(resourceId)) { - result = this.writePlatformService.updateUsersOwnAccountDetails(resourceId, command); - } else { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", - "UPDATE_USER_MAKER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_USER_MAKER", allowedPermissions); - - result = this.writePlatformService.updateUser(resourceId, command); - } - - final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); - commandSourceResult.updateJsonTo(jsonOfChangesOnly); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } else if (commandSourceResult.isDelete()) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", - "DELETE_USER_MAKER"); - context.authenticatedUser().validateHasPermissionTo("DELETE_USER_MAKER", allowedPermissions); - - this.writePlatformService.deleteUser(resourceId, command); - commandSourceResult.markAsChecked(checker, new LocalDate()); - } - } - - return commandSourceResult; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandProcessingService.java new file mode 100644 index 000000000..f13e6fc19 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandProcessingService.java @@ -0,0 +1,13 @@ +package org.mifosplatform.commands.service; + +import org.mifosplatform.commands.domain.CommandWrapper; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; + +public interface CommandProcessingService { + + EntityIdentifier processAndLogCommand(CommandWrapper wrapper, JsonCommand command, boolean isApprovedByChecker); + + EntityIdentifier logCommand(CommandWrapper wrapper, JsonCommand command); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandSourceWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandSourceWritePlatformService.java index 88a5e9ea8..99543763a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandSourceWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandSourceWritePlatformService.java @@ -4,7 +4,10 @@ import org.mifosplatform.infrastructure.core.data.EntityIdentifier; public interface PortfolioCommandSourceWritePlatformService { - EntityIdentifier logCommandSource(String apiOperation, String resource, Long resourceId, String commandSerializedAsJson); + EntityIdentifier logCommandSource(String taskPermissionName, String apiOperation, String resource, Long resourceId, String subResource, + Long subRescourceId, String json); + + EntityIdentifier logCommandSource(String taskPermissionName, String apiOperation, String resource, Long resourceId, String json); EntityIdentifier approveEntry(Long id); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java index 79d8b86db..ac87f8be2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java @@ -1,62 +1,107 @@ package org.mifosplatform.commands.service; -import org.joda.time.LocalDate; +import org.apache.commons.lang.StringUtils; import org.mifosplatform.commands.domain.CommandSource; import org.mifosplatform.commands.domain.CommandSourceRepository; -import org.mifosplatform.commands.handler.CommandSourceHandlerDelegator; +import org.mifosplatform.commands.domain.CommandWrapper; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.useradministration.domain.AppUser; +import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import com.google.gson.JsonElement; + @Service public class PortfolioCommandSourceWritePlatformServiceImpl implements PortfolioCommandSourceWritePlatformService { private final PlatformSecurityContext context; private final CommandSourceRepository commandSourceRepository; - private final CommandSourceHandlerDelegator commandSourceHandlerDelegator; + private final FromJsonHelper fromApiJsonHelper; + private final CommandProcessingService processAndLogCommandService; @Autowired public PortfolioCommandSourceWritePlatformServiceImpl(final PlatformSecurityContext context, - final CommandSourceRepository makerCheckerRepository, final CommandSourceHandlerDelegator commandSourceHandlerDelegator) { + final CommandSourceRepository commandSourceRepository, final FromJsonHelper fromApiJsonHelper, + final CommandProcessingService processAndLogCommandService) { this.context = context; - this.commandSourceRepository = makerCheckerRepository; - this.commandSourceHandlerDelegator = commandSourceHandlerDelegator; + this.commandSourceRepository = commandSourceRepository; + this.fromApiJsonHelper = fromApiJsonHelper; + this.processAndLogCommandService = processAndLogCommandService; } - - // NOT TRANSACTIONAL BY DESIGN FOR NOW + @Override - public EntityIdentifier logCommandSource(final String apiOperation, final String resource, final Long resourceId, - final String commandSerializedAsJson) { - - final AppUser maker = context.authenticatedUser(); - final LocalDate asToday = new LocalDate(); - - final CommandSource commandSourceInput = CommandSource.createdBy(apiOperation, resource, resourceId, commandSerializedAsJson, maker, asToday); - final CommandSource commandSourceResult = this.commandSourceHandlerDelegator.handleCommandWithSupportForRollback(commandSourceInput); + public EntityIdentifier logCommandSource(final String taskPermissionName, final String apiOperation, final String resource, + final Long resourceId, final String subResource, final Long subRescourceId, final String json) { - if (commandSourceResult.hasJson()) { - commandSourceRepository.save(commandSourceResult); + context.authenticatedUser().validateHasPermissionTo(taskPermissionName); + + final CommandWrapper wrapper = CommandWrapper.wrap(taskPermissionName, apiOperation, resource, resourceId, subResource, subRescourceId); + EntityIdentifier result = null; + try { + final JsonElement parsedCommand = this.fromApiJsonHelper.parse(json); + final JsonCommand command = JsonCommand.from(json, parsedCommand, this.fromApiJsonHelper, resourceId, subRescourceId); + final boolean isApprovedByChecker = false; + result = this.processAndLogCommandService.processAndLogCommand(wrapper, command, isApprovedByChecker); + } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { + + final String jsonToUse = StringUtils.defaultIfEmpty(e.getJsonOfChangesOnly(), json); + + final JsonElement parsedCommand = this.fromApiJsonHelper.parse(jsonToUse); + final JsonCommand command = JsonCommand.from(jsonToUse, parsedCommand, this.fromApiJsonHelper, resourceId, subRescourceId); + + result = this.processAndLogCommandService.logCommand(wrapper, command); } - return EntityIdentifier.makerChecker(commandSourceResult.resourceId(), commandSourceResult.getId()); + return result; } - @Transactional @Override - public EntityIdentifier approveEntry(final Long id) { + public EntityIdentifier logCommandSource(final String taskPermissionName, final String apiOperation, final String resource, + final Long resourceId, final String json) { - context.authenticatedUser(); + context.authenticatedUser().validateHasPermissionTo(taskPermissionName); - final CommandSource commandSourceInput = this.commandSourceRepository.findOne(id); - final CommandSource commandSourceResult = this.commandSourceHandlerDelegator.handleCommandForCheckerApproval(commandSourceInput); - if (commandSourceResult.hasJson()) { - commandSourceRepository.save(commandSourceResult); + final CommandWrapper wrapper = CommandWrapper.wrap(taskPermissionName, apiOperation, resource, resourceId); + + EntityIdentifier result = null; + try { + final JsonElement parsedCommand = this.fromApiJsonHelper.parse(json); + final JsonCommand command = JsonCommand.from(json, parsedCommand, this.fromApiJsonHelper, resourceId, null); + + final boolean isApprovedByChecker = false; + result = this.processAndLogCommandService.processAndLogCommand(wrapper, command, isApprovedByChecker); + } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { + + final String jsonToUse = StringUtils.defaultIfEmpty(e.getJsonOfChangesOnly(), json); + + final JsonElement parsedCommand = this.fromApiJsonHelper.parse(jsonToUse); + final JsonCommand command = JsonCommand.from(jsonToUse, parsedCommand, this.fromApiJsonHelper, resourceId, null); + + result = this.processAndLogCommandService.logCommand(wrapper, command); } - return EntityIdentifier.makerChecker(commandSourceResult.resourceId(), commandSourceResult.getId()); + return result; + } + + @Override + public EntityIdentifier approveEntry(final Long commandId) { + + final CommandSource commandSourceInput = this.commandSourceRepository.findOne(commandId); + + context.authenticatedUser().validateHasCheckerPermissionTo(commandSourceInput.getPermissionCode()); + + final CommandWrapper wrapper = CommandWrapper.fromExistingCommand(commandId, commandSourceInput.getPermissionCode(), commandSourceInput.operation(), + commandSourceInput.resourceName(), commandSourceInput.resourceId(), commandSourceInput.getSubResource(), commandSourceInput.getSubResourceId()); + + final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSourceInput.json()); + final JsonCommand command = JsonCommand.fromExistingCommand(commandId, commandSourceInput.json(), parsedCommand, this.fromApiJsonHelper, commandSourceInput.resourceId(), commandSourceInput.getSubResourceId()); + + final boolean makerCheckerApproval = true; + return this.processAndLogCommandService.processAndLogCommand(wrapper, command, makerCheckerApproval); } @Transactional diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java new file mode 100644 index 000000000..b31fafb12 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java @@ -0,0 +1,218 @@ +package org.mifosplatform.commands.service; + +import java.util.Map; + +import org.joda.time.DateTime; +import org.mifosplatform.commands.domain.CommandSource; +import org.mifosplatform.commands.domain.CommandSourceRepository; +import org.mifosplatform.commands.domain.CommandWrapper; +import org.mifosplatform.commands.exception.UnsupportedCommandException; +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; +import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; +import org.mifosplatform.useradministration.domain.AppUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class SynchronousCommandProcessingService implements CommandProcessingService { + + private PlatformSecurityContext context; + private final ApplicationContext applicationContext; + private final ToApiJsonSerializer> toApiJsonSerializer; + private CommandSourceRepository commandSourceRepository; + private final ConfigurationDomainService configurationDomainService; + + @Autowired + public SynchronousCommandProcessingService(final PlatformSecurityContext context, final ApplicationContext applicationContext, + final ToApiJsonSerializer> toApiJsonSerializer, final CommandSourceRepository commandSourceRepository, + final ConfigurationDomainService configurationDomainService) { + this.context = context; + this.context = context; + this.applicationContext = applicationContext; + this.toApiJsonSerializer = toApiJsonSerializer; + this.commandSourceRepository = commandSourceRepository; + this.commandSourceRepository = commandSourceRepository; + this.configurationDomainService = configurationDomainService; + } + + @Transactional + @Override + public EntityIdentifier processAndLogCommand(final CommandWrapper wrapper, final JsonCommand command, final boolean isApprovedByChecker) { + + final NewCommandSourceHandler handler = findCommandHandler(wrapper); + final EntityIdentifier result = handler.processCommand(command); + + final AppUser maker = context.authenticatedUser(); + + CommandSource commandSourceResult = null; + if (command.commandId() != null) { + commandSourceResult = this.commandSourceRepository.findOne(command.commandId()); + commandSourceResult.markAsChecked(maker, DateTime.now()); + } else { + commandSourceResult = CommandSource.fullEntryFrom(wrapper, command, maker); + } + commandSourceResult.updateResourceId(result.resourceId()); + commandSourceResult.updateSubResourceId(result.subResourceId()); + + String changesOnlyJson = null; + if (result.hasChanges()) { + changesOnlyJson = this.toApiJsonSerializer.serializeResult(result.getChanges()); + commandSourceResult.updateJsonTo(changesOnlyJson); + } + + if (!result.hasChanges() && wrapper.isUpdate()) { + commandSourceResult.updateJsonTo(null); + } + + if (commandSourceResult.hasJson()) { + commandSourceRepository.save(commandSourceResult); + } + + if (this.configurationDomainService.isMakerCheckerEnabledForTask(wrapper.taskPermissionName()) && !isApprovedByChecker) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(changesOnlyJson); } + + return result; + } + + @Transactional + @Override + public EntityIdentifier logCommand(final CommandWrapper wrapper, final JsonCommand command) { + + final AppUser maker = context.authenticatedUser(); + + final CommandSource commandSourceResult = CommandSource.fullEntryFrom(wrapper, command, maker); + if (commandSourceResult.hasJson()) { + commandSourceRepository.save(commandSourceResult); + } + + return EntityIdentifier.resourceResult(commandSourceResult.resourceId(), commandSourceResult.getId()); + } + + private NewCommandSourceHandler findCommandHandler(final CommandWrapper wrapper) { + NewCommandSourceHandler handler = null; + + if (wrapper.isClientNoteResource()) { + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createClientNoteCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = applicationContext.getBean("updateClientNoteCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + } else if (wrapper.isClientIdentifierResource()) { + + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createClientIdentifierCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = applicationContext.getBean("updateClientIdentifierCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isDelete()) { + handler = applicationContext.getBean("deleteClientIdentifierCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + } else if (wrapper.isClientResource() && !wrapper.isNotesSubResource() && !wrapper.isIdentifiersSubResource()) { + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createClientCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = applicationContext.getBean("updateClientCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isDelete()) { + handler = applicationContext.getBean("deleteClientCommandHandler", NewCommandSourceHandler.class); + } + // end of client + } else if (wrapper.isUpdateRolePermissions()) { + handler = applicationContext.getBean("updateRolePermissionsCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isPermissionResource()) { + handler = applicationContext.getBean("updateMakerCheckerPermissionsCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isRoleResource()) { + + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createRoleCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = applicationContext.getBean("updateRoleCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + + } else if (wrapper.isUserResource()) { + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createUserCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = applicationContext.getBean("updateUserCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isDelete()) { + handler = applicationContext.getBean("deleteUserCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + } else if (wrapper.isStaffResource()) { + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createStaffCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = applicationContext.getBean("updateStaffCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + } else if (wrapper.isCodeResource()) { + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createCodeCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = applicationContext.getBean("updateCodeCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isDelete()) { + handler = applicationContext.getBean("deleteCodeCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + } else if (wrapper.isCurrencyResource()) { + handler = applicationContext.getBean("updateCurrencyCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isFundResource()) { + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createFundCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = applicationContext.getBean("updateFundCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + } else if (wrapper.isOfficeResource()) { + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createOfficeCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = applicationContext.getBean("updateOfficeCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + } else if (wrapper.isOfficeTransactionResource()) { + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createOfficeTransactionCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + } else if (wrapper.isChargeDefinitionResource()) { + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createChargeDefinitionCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = applicationContext.getBean("updateChargeDefinitionCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isDelete()) { + handler = applicationContext.getBean("deleteChargeDefinitionCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + } else if (wrapper.isLoanProductResource()) { + if (wrapper.isCreate()) { + handler = applicationContext.getBean("createLoanProductCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = applicationContext.getBean("updateLoanProductCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + + return handler; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/api/CodesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/api/CodesApiResource.java index 79eb42034..f80c79d4e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/api/CodesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/api/CodesApiResource.java @@ -3,7 +3,6 @@ package org.mifosplatform.infrastructure.codes.api; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; @@ -76,10 +75,7 @@ public class CodesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String createCode(final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "CREATE_CODE"); - context.authenticatedUser().validateHasPermissionTo("CREATE_CODE", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "codes", null, + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_CODE", "CREATE", "codes", null, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); @@ -103,10 +99,7 @@ public class CodesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updateCode(@PathParam("codeId") final Long codeId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "UPDATE_CODE"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CODE", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "codes", codeId, + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_CODE", "UPDATE", "codes", codeId, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); @@ -118,10 +111,8 @@ public class CodesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String deleteCodeApplication(@PathParam("codeId") final Long codeId) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "DELETE_CODE"); - context.authenticatedUser().validateHasPermissionTo("DELETE_CODE", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", "codes", codeId, "{}"); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE_CODE", "DELETE", "codes", codeId, + "{}"); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/handler/CreateCodeCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/handler/CreateCodeCommandHandler.java new file mode 100644 index 000000000..ef2faa1cb --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/handler/CreateCodeCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.infrastructure.codes.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.codes.service.CodeWritePlatformService; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateCodeCommandHandler implements NewCommandSourceHandler { + + private final CodeWritePlatformService writePlatformService; + + @Autowired + public CreateCodeCommandHandler(final CodeWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.createCode(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/handler/DeleteCodeCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/handler/DeleteCodeCommandHandler.java new file mode 100644 index 000000000..abd298a3c --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/handler/DeleteCodeCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.infrastructure.codes.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.codes.service.CodeWritePlatformService; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class DeleteCodeCommandHandler implements NewCommandSourceHandler { + + private final CodeWritePlatformService writePlatformService; + + @Autowired + public DeleteCodeCommandHandler(final CodeWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.deleteCode(command.resourceId()); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/handler/UpdateCodeCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/handler/UpdateCodeCommandHandler.java new file mode 100644 index 000000000..2510be4df --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/handler/UpdateCodeCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.infrastructure.codes.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.codes.service.CodeWritePlatformService; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateCodeCommandHandler implements NewCommandSourceHandler { + + private final CodeWritePlatformService writePlatformService; + + @Autowired + public UpdateCodeCommandHandler(final CodeWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.updateCode(command.resourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/serialization/CodeCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/serialization/CodeCommandFromApiJsonDeserializer.java index cb9b15d5a..dd5d9967b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/serialization/CodeCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/serialization/CodeCommandFromApiJsonDeserializer.java @@ -6,9 +6,10 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import org.apache.commons.lang.StringUtils; import org.mifosplatform.infrastructure.codes.command.CodeCommand; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.springframework.beans.factory.annotation.Autowired; @@ -30,16 +31,16 @@ public final class CodeCommandFromApiJsonDeserializer extends AbstractFromApiJso private final FromJsonHelper fromApiJsonHelper; @Autowired - public CodeCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, final CommandSerializer commandSerializerService) { - super(commandSerializerService); + public CodeCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; } @Override - public CodeCommand commandFromApiJson(@SuppressWarnings("unused") final Long codeId, final String json) { - + public CodeCommand commandFromApiJson(final String json) { + + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); final JsonElement element = fromApiJsonHelper.parse(json); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/service/CodeWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/service/CodeWritePlatformService.java index 42623cf62..1b8e005e9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/service/CodeWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/service/CodeWritePlatformService.java @@ -5,9 +5,9 @@ import org.mifosplatform.infrastructure.core.data.EntityIdentifier; public interface CodeWritePlatformService { - Long createCode(JsonCommand command); + EntityIdentifier createCode(JsonCommand command); EntityIdentifier updateCode(Long codeId, JsonCommand command); - EntityIdentifier deleteCode(Long codeId, JsonCommand command); + EntityIdentifier deleteCode(Long codeId); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/service/CodeWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/service/CodeWritePlatformServiceJpaRepositoryImpl.java index 2455fa581..c8d70ce26 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/service/CodeWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/service/CodeWritePlatformServiceJpaRepositoryImpl.java @@ -12,8 +12,6 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -28,37 +26,32 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf private final PlatformSecurityContext context; private final CodeRepository codeRepository; - private final ConfigurationDomainService configurationDomainService; private final CodeCommandFromApiJsonDeserializer fromApiJsonDeserializer; @Autowired public CodeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final CodeRepository codeRepository, - final ConfigurationDomainService configurationDomainService, final CodeCommandFromApiJsonDeserializer fromApiJsonDeserializer) { this.context = context; this.codeRepository = codeRepository; - this.configurationDomainService = configurationDomainService; this.fromApiJsonDeserializer = fromApiJsonDeserializer; } @Transactional @Override - public Long createCode(final JsonCommand command) { + public EntityIdentifier createCode(final JsonCommand command) { try { context.authenticatedUser(); - + final CodeCommand codeCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); codeCommand.validateForCreate(); final Code code = Code.fromJson(command); this.codeRepository.save(code); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_CODE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return code.getId(); + return EntityIdentifier.resourceResult(code.getId(), null); } catch (DataIntegrityViolationException dve) { - return Long.valueOf(-1); + return EntityIdentifier.empty(); } } @@ -78,8 +71,6 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf this.codeRepository.save(code); } - if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_CODE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - return EntityIdentifier.withChanges(codeId, changes); } catch (DataIntegrityViolationException dve) { handleCodeDataIntegrityIssues(command, dve); @@ -89,19 +80,15 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf @Transactional @Override - public EntityIdentifier deleteCode(final Long codeId, final JsonCommand command) { + public EntityIdentifier deleteCode(final Long codeId) { context.authenticatedUser(); final Code code = retrieveCodeBy(codeId); - if (code.isSystemDefined()) { - throw new SystemDefinedCodeCannotBeChangedException(); - } - + if (code.isSystemDefined()) { throw new SystemDefinedCodeCannotBeChangedException(); } + this.codeRepository.delete(code); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("DELETE_CODE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - return new EntityIdentifier(code.getId()); } @@ -110,17 +97,17 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf if (code == null) { throw new CodeNotFoundException(codeId.toString()); } return code; } - + /* * Guaranteed to throw an exception no matter what the data integrity issue * is. */ private void handleCodeDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { Throwable realCause = dve.getMostSpecificCause(); - if (realCause.getMessage().contains("code_name_org")) { + if (realCause.getMessage().contains("code_name_org")) { final String name = command.stringValueOfParameterNamed("name"); - throw new PlatformDataIntegrityException("error.msg.code.duplicate.name", - "A code with name '" + name + "' already exists"); } + throw new PlatformDataIntegrityException("error.msg.code.duplicate.name", "A code with name '" + name + "' already exists"); + } logger.error(dve.getMessage(), dve); throw new PlatformDataIntegrityException("error.msg.cund.unknown.data.integrity.issue", diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/JsonCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/JsonCommand.java index 11e68a850..13239e9b6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/JsonCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/JsonCommand.java @@ -1,9 +1,11 @@ package org.mifosplatform.infrastructure.core.api; import java.lang.reflect.Type; +import java.math.BigDecimal; import java.util.Arrays; import java.util.Map; +import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; @@ -23,36 +25,49 @@ import com.google.gson.reflect.TypeToken; public final class JsonCommand { private final String jsonCommand; - private final transient boolean approvedByChecker; private final JsonElement parsedCommand; private final FromJsonHelper fromApiJsonHelper; + private final Long commandId; + private final Long resourceId; + private final Long subResourceId; - public static JsonCommand from(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper) { - return new JsonCommand(jsonCommand, parsedCommand, fromApiJsonHelper, false); + public static JsonCommand from(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper, + final Long resourceId, final Long subResourceId) { + return new JsonCommand(null, jsonCommand, parsedCommand, fromApiJsonHelper, resourceId, subResourceId); + } + + public static JsonCommand fromExistingCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper, + final Long resourceId, final Long subResourceId) { + return new JsonCommand(commandId, jsonCommand, parsedCommand, fromApiJsonHelper, resourceId, subResourceId); } - public static JsonCommand withMakerCheckerApproval(final String jsonCommand, final JsonElement parsedCommand, - final FromJsonHelper fromApiJsonHelper) { - return new JsonCommand(jsonCommand, parsedCommand, fromApiJsonHelper, true); - } - - public JsonCommand(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper, - final boolean approvedByChecker) { + public JsonCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper, + final Long resourceId, final Long subResourceId) { + this.commandId = commandId; this.jsonCommand = jsonCommand; this.parsedCommand = parsedCommand; this.fromApiJsonHelper = fromApiJsonHelper; - this.approvedByChecker = approvedByChecker; + this.resourceId = resourceId; + this.subResourceId = subResourceId; } public String json() { return this.jsonCommand; } - - public boolean isApprovedByChecker() { - return this.approvedByChecker; + + public Long commandId() { + return this.commandId; + } + + public Long resourceId() { + return this.resourceId; + } + + public Long subResourceId() { + return this.subResourceId; } - private boolean differenceExists(LocalDate baseValue, LocalDate workingCopyValue) { + private boolean differenceExists(final LocalDate baseValue, final LocalDate workingCopyValue) { boolean differenceExists = false; if (baseValue != null) { @@ -82,7 +97,31 @@ public final class JsonCommand { return !Arrays.equals(baseValue, workingCopyValue); } - private boolean differenceExists(final Long baseValue, final Long workingCopyValue) { + private boolean differenceExists(final Number baseValue, final Number workingCopyValue) { + boolean differenceExists = false; + + if (baseValue != null) { + differenceExists = !baseValue.equals(workingCopyValue); + } else { + differenceExists = workingCopyValue != null; + } + + return differenceExists; + } + + private boolean differenceExists(final BigDecimal baseValue, final BigDecimal workingCopyValue) { + boolean differenceExists = false; + + if (baseValue != null) { + differenceExists = baseValue.compareTo(workingCopyValue) != 0; + } else { + differenceExists = workingCopyValue != null; + } + + return differenceExists; + } + + private boolean differenceExists(final Boolean baseValue, final Boolean workingCopyValue) { boolean differenceExists = false; if (baseValue != null) { @@ -97,7 +136,7 @@ public final class JsonCommand { private boolean parameterExists(final String parameterName) { return this.fromApiJsonHelper.parameterExists(parameterName, parsedCommand); } - + public boolean hasParameter(final String parameterName) { return parameterExists(parameterName); } @@ -160,6 +199,56 @@ public final class JsonCommand { return StringUtils.defaultIfEmpty(value, ""); } + public boolean isChangeInBigDecimalParameterNamed(final String parameterName, final BigDecimal existingValue) { + boolean isChanged = false; + if (parameterExists(parameterName)) { + final BigDecimal workingValue = bigDecimalValueOfParameterNamed(parameterName); + isChanged = differenceExists(existingValue, workingValue); + } + return isChanged; + } + + public BigDecimal bigDecimalValueOfParameterNamed(final String parameterName) { + return this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(parameterName, parsedCommand); + } + + public boolean isChangeInIntegerParameterNamed(final String parameterName, final Integer existingValue) { + boolean isChanged = false; + if (parameterExists(parameterName)) { + final Integer workingValue = integerValueOfParameterNamed(parameterName); + isChanged = differenceExists(existingValue, workingValue); + } + return isChanged; + } + + public Integer integerValueOfParameterNamed(final String parameterName) { + return this.fromApiJsonHelper.extractIntegerWithLocaleNamed(parameterName, parsedCommand); + } + + public boolean isChangeInBooleanParameterNamed(final String parameterName, final Boolean existingValue) { + boolean isChanged = false; + if (parameterExists(parameterName)) { + final Boolean workingValue = booleanObjectValueOfParameterNamed(parameterName); + isChanged = differenceExists(existingValue, workingValue); + } + return isChanged; + } + + /** + * Returns {@link Boolean} that could possibly be null. + */ + public Boolean booleanObjectValueOfParameterNamed(final String parameterName) { + return this.fromApiJsonHelper.extractBooleanNamed(parameterName, parsedCommand); + } + + /** + * always returns true or false + */ + public boolean booleanPrimitiveValueOfParameterNamed(final String parameterName) { + final Boolean value = this.fromApiJsonHelper.extractBooleanNamed(parameterName, parsedCommand); + return (Boolean) ObjectUtils.defaultIfNull(value, Boolean.FALSE); + } + public boolean isChangeInArrayParameterNamed(final String parameterName, final String[] existingValue) { boolean isChanged = false; if (parameterExists(parameterName)) { @@ -173,7 +262,8 @@ public final class JsonCommand { return this.fromApiJsonHelper.extractArrayNamed(parameterName, parsedCommand); } - public boolean isChangeInPasswordParameterNamed(final String parameterName, final String existingValue, final PlatformPasswordEncoder platformPasswordEncoder, final Long saltValue) { + public boolean isChangeInPasswordParameterNamed(final String parameterName, final String existingValue, + final PlatformPasswordEncoder platformPasswordEncoder, final Long saltValue) { boolean isChanged = false; if (parameterExists(parameterName)) { final String workingValue = passwordValueOfParameterNamed(parameterName, platformPasswordEncoder, saltValue); @@ -181,10 +271,11 @@ public final class JsonCommand { } return isChanged; } - - public String passwordValueOfParameterNamed(final String parameterName, final PlatformPasswordEncoder platformPasswordEncoder, final Long saltValue) { + + public String passwordValueOfParameterNamed(final String parameterName, final PlatformPasswordEncoder platformPasswordEncoder, + final Long saltValue) { final String passwordPlainText = stringValueOfParameterNamed(parameterName); - + final PlatformUser dummyPlatformUser = new BasicPasswordEncodablePlatformUser(saltValue, "", passwordPlainText); return platformPasswordEncoder.encode(dummyPlatformUser); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiDataConversionServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiDataConversionServiceImpl.java index 75b8d6e9c..3ee33aa4a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiDataConversionServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiDataConversionServiceImpl.java @@ -134,7 +134,7 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo @Override public ClientData convertInternalJsonFormatToClientDataChange(final Long resourceIdentifier, final String json) { - final ClientCommand command = this.clientCommandFromApiJsonDeserializer.commandFromApiJson(resourceIdentifier, json); + final ClientCommand command = this.clientCommandFromApiJsonDeserializer.commandFromApiJson(json); return ClientData.dataChangeInstance(resourceIdentifier, command.getOfficeId(), command.getExternalId(), command.getFirstname(), command.getLastname(), command.getClientOrBusinessName(), command.getJoiningDate()); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/EntityIdentifier.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/EntityIdentifier.java index ac81e29a6..b6adda8eb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/EntityIdentifier.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/EntityIdentifier.java @@ -5,55 +5,71 @@ import java.util.Map; /** * Represents the successful result of an REST API call. + * + * FIXME - KW - Rename to CommandProcessingResult - make immutable */ public class EntityIdentifier { - private Long entityId; - - // TODO - Rename variable to commandId or taskId or something that shows - // this is the id of a command in a table/queue for processing. - @SuppressWarnings("unused") - private Long makerCheckerId; + private Long commandId; + private Long resourceId; + private Long subResourceId; private Map changes; - public static EntityIdentifier makerChecker(final Long makerCheckerId) { - return new EntityIdentifier(null, makerCheckerId, null); + public static EntityIdentifier commandOnlyResult(final Long commandId) { + return new EntityIdentifier(null, null, commandId, null); } - public static EntityIdentifier makerChecker(final Long resourceId, final Long makerCheckerId) { - return new EntityIdentifier(resourceId, makerCheckerId, null); + public static EntityIdentifier resourceResult(final Long resourceId, final Long commandId) { + return new EntityIdentifier(resourceId, null, commandId, null); + } + + public static EntityIdentifier resourceResult(final Long resourceId, final Long commandId, final Map changes) { + return new EntityIdentifier(resourceId, null, commandId, changes); + } + + public static EntityIdentifier subResourceResult(final Long resourceId, final Long subResourceId, final Long commandId) { + return new EntityIdentifier(resourceId, subResourceId, commandId, null); + } + + public static EntityIdentifier subResourceResult(final Long resourceId, final Long subResourceId, final Long commandId, final Map changes) { + return new EntityIdentifier(resourceId, subResourceId, commandId, changes); } public static EntityIdentifier withChanges(final Long resourceId, final Map changes) { - return new EntityIdentifier(resourceId, null, changes); - } - - public static EntityIdentifier empty() { - return new EntityIdentifier(Long.valueOf(-1), null, null); + return new EntityIdentifier(resourceId, null, null, changes); } - public EntityIdentifier() { + public static EntityIdentifier empty() { + return new EntityIdentifier(Long.valueOf(-1), Long.valueOf(-1), Long.valueOf(-1), null); + } + + protected EntityIdentifier() { // } public EntityIdentifier(final Long entityId) { - this.entityId = entityId; + this.resourceId = entityId; this.changes = new HashMap(); } - private EntityIdentifier(final Long entityId, final Long makerCheckerId, final Map changesOnly) { - this.entityId = entityId; - this.makerCheckerId = makerCheckerId; + private EntityIdentifier(final Long resourceId, final Long subResourceId, final Long commandId, final Map changesOnly) { + this.resourceId = resourceId; + this.subResourceId = subResourceId; + this.commandId = commandId; this.changes = changesOnly; } - public Long getEntityId() { - return this.entityId; + public Long commandId() { + return this.commandId; } - public void setEntityId(final Long entityId) { - this.entityId = entityId; + public Long resourceId() { + return this.resourceId; + } + + public Long subResourceId() { + return this.subResourceId; } public Map getChanges() { @@ -63,4 +79,9 @@ public class EntityIdentifier { } return checkIfEmpty; } -} + + public boolean hasChanges() { + final boolean noChanges = this.changes == null || this.changes.isEmpty(); + return !noChanges; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/AbstractFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/AbstractFromApiJsonDeserializer.java index 9b7a96c07..2b2dea7ee 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/AbstractFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/AbstractFromApiJsonDeserializer.java @@ -6,29 +6,6 @@ package org.mifosplatform.infrastructure.core.serialization; */ public abstract class AbstractFromApiJsonDeserializer implements FromApiJsonDeserializer { - private final CommandSerializer commandSerializerService; - - public AbstractFromApiJsonDeserializer(final CommandSerializer commandSerializerService) { - this.commandSerializerService = commandSerializerService; - } - @Override - public T commandFromApiJson(final String json) { - return commandFromApiJson(null, json); - } - - @Override - public abstract T commandFromApiJson(final Long resourceId, final String json); - - @Override - public String serializedCommandJsonFromApiJson(final String json) { - final T command = commandFromApiJson(json); - return this.commandSerializerService.serializeCommandToJson(command); - } - - @Override - public String serializedCommandJsonFromApiJson(final Long resourceId, final String json) { - final T command = commandFromApiJson(resourceId, json); - return this.commandSerializerService.serializeCommandToJson(command); - } + public abstract T commandFromApiJson(final String json); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/CommandProcessingResultJsonSerializer.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/CommandProcessingResultJsonSerializer.java new file mode 100644 index 000000000..73a32ce1f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/CommandProcessingResultJsonSerializer.java @@ -0,0 +1,39 @@ +package org.mifosplatform.infrastructure.core.serialization; + +import org.joda.time.DateTime; +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.api.JodaDateTimeAdapter; +import org.mifosplatform.infrastructure.core.api.JodaLocalDateAdapter; +import org.springframework.stereotype.Component; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +/** + *

A google gson implementation of {@link ExcludeNothingJsonSerializer} contract.

+ * + *

It serializes all fields of any Java {@link Object} passed to it.

+ */ +@Component +public final class CommandProcessingResultJsonSerializer { + + private final Gson gson; + + public CommandProcessingResultJsonSerializer() { + GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(LocalDate.class, new JodaLocalDateAdapter()); + builder.registerTypeAdapter(DateTime.class, new JodaDateTimeAdapter()); + builder.serializeNulls(); + + this.gson = builder.create(); + } + + public String serialize(final Object result) { + String returnedResult = null; + final String serializedResult = this.gson.toJson(result); + if (!"null".equalsIgnoreCase(serializedResult)) { + returnedResult = serializedResult; + } + return returnedResult; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/DefaultToApiJsonSerializer.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/DefaultToApiJsonSerializer.java index c15e63e7f..6e242e9a6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/DefaultToApiJsonSerializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/DefaultToApiJsonSerializer.java @@ -17,17 +17,25 @@ public final class DefaultToApiJsonSerializer implements ToApiJsonSerializer< private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson excludeNothingWithPrettyPrintingOff; private final ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson excludeNothingWithPrettyPrintingOn; + private final CommandProcessingResultJsonSerializer commandProcessingResultSerializer; private final GoogleGsonSerializerHelper helper; @Autowired public DefaultToApiJsonSerializer( final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson excludeNothingWithPrettyPrintingOff, final ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson excludeNothingWithPrettyPrintingOn, + final CommandProcessingResultJsonSerializer commandProcessingResultSerializer, final GoogleGsonSerializerHelper helper) { this.excludeNothingWithPrettyPrintingOff = excludeNothingWithPrettyPrintingOff; this.excludeNothingWithPrettyPrintingOn = excludeNothingWithPrettyPrintingOn; + this.commandProcessingResultSerializer = commandProcessingResultSerializer; this.helper = helper; } + + @Override + public String serializeResult(final Object object) { + return this.commandProcessingResultSerializer.serialize(object); + } @Override public String serialize(final Object object) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/FromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/FromApiJsonDeserializer.java index a42c55b9f..229f9780a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/FromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/FromApiJsonDeserializer.java @@ -6,10 +6,4 @@ package org.mifosplatform.infrastructure.core.serialization; public interface FromApiJsonDeserializer { T commandFromApiJson(final String json); - - T commandFromApiJson(final Long resourceId, final String json); - - String serializedCommandJsonFromApiJson(final String json); - - String serializedCommandJsonFromApiJson(final Long resourceId, final String json); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/FromJsonHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/FromJsonHelper.java index 63dbd5565..c2a09deb4 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/FromJsonHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/FromJsonHelper.java @@ -86,6 +86,10 @@ public class FromJsonHelper { public String[] extractArrayNamed(final String parameterName, final JsonElement element, final Set parametersPassedInRequest) { return helperDelegator.extractArrayNamed(parameterName, element, parametersPassedInRequest); } + + public Boolean extractBooleanNamed(final String parameterName, final JsonElement element) { + return helperDelegator.extractBooleanNamed(parameterName, element, new HashSet()); + } public Boolean extractBooleanNamed(final String parameterName, final JsonElement element, final Set parametersPassedInRequest) { return helperDelegator.extractBooleanNamed(parameterName, element, parametersPassedInRequest); @@ -105,6 +109,10 @@ public class FromJsonHelper { return helperDelegator.extractLocalDateAsArrayNamed(parameterName, element, parametersPassedInRequest); } + public BigDecimal extractBigDecimalWithLocaleNamed(final String parameterName, final JsonElement element) { + return helperDelegator.extractBigDecimalWithLocaleNamed(parameterName, element, new HashSet()); + } + public BigDecimal extractBigDecimalWithLocaleNamed(final String parameterName, final JsonElement element, final Set parametersPassedInRequest) { return helperDelegator.extractBigDecimalWithLocaleNamed(parameterName, element, parametersPassedInRequest); @@ -115,6 +123,10 @@ public class FromJsonHelper { return helperDelegator.extractBigDecimalNamed(parameterName, element.getAsJsonObject(), Locale.US, parametersPassedInRequest); } + public Integer extractIntegerWithLocaleNamed(final String parameterName, final JsonElement element) { + return helperDelegator.extractIntegerWithLocaleNamed(parameterName, element.getAsJsonObject(), new HashSet()); + } + public Integer extractIntegerWithLocaleNamed(final String parameterName, final JsonElement element, final Set parametersPassedInRequest) { return helperDelegator.extractIntegerWithLocaleNamed(parameterName, element.getAsJsonObject(), parametersPassedInRequest); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/ToApiJsonSerializer.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/ToApiJsonSerializer.java index 41d3a68a6..73f89837b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/ToApiJsonSerializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/ToApiJsonSerializer.java @@ -6,6 +6,8 @@ import java.util.Set; public interface ToApiJsonSerializer { String serialize(final Object object); + + String serializeResult(final Object object); String serialize(final ApiRequestJsonSerializationSettings settings, Collection collection, Set supportedResponseParameters); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/api/DataTableApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/api/DataTableApiResource.java index 11c4bac6d..de1e44232 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/api/DataTableApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/api/DataTableApiResource.java @@ -77,8 +77,7 @@ public class DataTableApiResource { this.readWriteNonCoreDataService.registerDatatable(datatable, apptable); - EntityIdentifier entityIdentifier = new EntityIdentifier(); - return Response.ok().entity(entityIdentifier).build(); + return Response.ok().entity(EntityIdentifier.empty()).build(); } @POST @@ -89,8 +88,7 @@ public class DataTableApiResource { this.readWriteNonCoreDataService.deregisterDatatable(datatable); - EntityIdentifier entityIdentifier = new EntityIdentifier(); - return Response.ok().entity(entityIdentifier).build(); + return Response.ok().entity(EntityIdentifier.empty()).build(); } @GET diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/api/CurrenciesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/api/CurrenciesApiResource.java index e4347d4ab..9b15240c0 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/api/CurrenciesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/api/CurrenciesApiResource.java @@ -2,7 +2,6 @@ package org.mifosplatform.organisation.monetary.api; import java.util.Arrays; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; @@ -21,7 +20,6 @@ import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSeriali import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.monetary.data.ConfigurationData; -import org.mifosplatform.organisation.monetary.serialization.CurrencyCommandFromApiJsonDeserializer; import org.mifosplatform.organisation.monetary.service.OrganisationCurrencyReadPlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; @@ -38,20 +36,17 @@ public class CurrenciesApiResource { private final PlatformSecurityContext context; private final OrganisationCurrencyReadPlatformService readPlatformService; - private final CurrencyCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @Autowired public CurrenciesApiResource(final PlatformSecurityContext context, final OrganisationCurrencyReadPlatformService readPlatformService, - final CurrencyCommandFromApiJsonDeserializer fromApiJsonDeserializer, final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { this.context = context; this.readPlatformService = readPlatformService; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.toApiJsonSerializer = toApiJsonSerializer; this.apiRequestParameterHelper = apiRequestParameterHelper; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; @@ -75,13 +70,8 @@ public class CurrenciesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updateCurrencies(final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", "UPDATE_CURRENCY"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CURRENCY", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "currencies", null, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_CURRENCY", "UPDATE", "currencies", + null, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/command/CurrencyCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/command/CurrencyCommand.java index b7b52ee99..a59d750c5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/command/CurrencyCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/command/CurrencyCommand.java @@ -5,16 +5,18 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; + /** * Immutable command for updating allowed currencies. */ public class CurrencyCommand { private String[] currencies; - private final transient boolean makerCheckerApproval; - public CurrencyCommand(final boolean makerCheckerApproval, final String[] currencies) { - this.makerCheckerApproval = makerCheckerApproval; + public CurrencyCommand(final String[] currencies) { final List listOfCurrencyCodes = new ArrayList(Arrays.asList(currencies)); Collections.sort(listOfCurrencyCodes); this.currencies = listOfCurrencyCodes.toArray(new String[listOfCurrencyCodes.size()]); @@ -23,8 +25,14 @@ public class CurrencyCommand { public String[] getCurrencies() { return currencies; } - - public boolean isApprovedByChecker() { - return this.makerCheckerApproval; + + public void validateForUpdate() { + List dataValidationErrors = new ArrayList(); + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("currencies"); + + baseDataValidator.reset().parameter("currencies").value(this.currencies).arrayNotEmpty(); + + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/handler/UpdateCurrencyCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/handler/UpdateCurrencyCommandHandler.java new file mode 100644 index 000000000..45eaec31a --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/handler/UpdateCurrencyCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.organisation.monetary.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.organisation.monetary.service.CurrencyWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateCurrencyCommandHandler implements NewCommandSourceHandler { + + private final CurrencyWritePlatformService writePlatformService; + + @Autowired + public UpdateCurrencyCommandHandler(final CurrencyWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.updateAllowedCurrencies(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/serialization/CurrencyCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/serialization/CurrencyCommandFromApiJsonDeserializer.java index 24a13c693..224a4b6bb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/serialization/CurrencyCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/serialization/CurrencyCommandFromApiJsonDeserializer.java @@ -6,13 +6,16 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; +import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.organisation.monetary.command.CurrencyCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import com.google.gson.JsonElement; import com.google.gson.reflect.TypeToken; /** @@ -20,7 +23,7 @@ import com.google.gson.reflect.TypeToken; * 's. */ @Component -public final class CurrencyCommandFromApiJsonDeserializer implements FromApiJsonDeserializer { +public final class CurrencyCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer { /** * The parameters supported for this command. @@ -28,42 +31,22 @@ public final class CurrencyCommandFromApiJsonDeserializer implements FromApiJson private final Set supportedParameters = new HashSet(Arrays.asList("currencies")); private final FromJsonHelper fromApiJsonHelper; - private final CurrencyCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer; - private final CommandSerializer commandSerializerService; @Autowired - public CurrencyCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, - final CurrencyCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer, - final CommandSerializer commandSerializerService) { + public CurrencyCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; - this.commandFromCommandJsonDeserializer = commandFromCommandJsonDeserializer; - this.commandSerializerService = commandSerializerService; } @Override public CurrencyCommand commandFromApiJson(final String json) { - return commandFromApiJson(null, json); - } - @Override - public CurrencyCommand commandFromApiJson(final Long resourceId, final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - return this.commandFromCommandJsonDeserializer.commandFromCommandJson(resourceId, json); - } - - @Override - public String serializedCommandJsonFromApiJson(final String json) { - final CurrencyCommand command = commandFromApiJson(json); - return this.commandSerializerService.serializeCommandToJson(command); - } - - @Override - public String serializedCommandJsonFromApiJson(final Long roleId, final String json) { - final CurrencyCommand command = commandFromApiJson(roleId, json); - return this.commandSerializerService.serializeCommandToJson(command); + final JsonElement element = fromApiJsonHelper.parse(json); + final String[] currencies = fromApiJsonHelper.extractArrayNamed("currencies", element); + return new CurrencyCommand(currencies); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/serialization/CurrencyCommandFromCommandJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/serialization/CurrencyCommandFromCommandJsonDeserializer.java deleted file mode 100644 index 0011e48b9..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/serialization/CurrencyCommandFromCommandJsonDeserializer.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.mifosplatform.organisation.monetary.serialization; - -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.serialization.FromCommandJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.organisation.monetary.command.CurrencyCommand; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.google.gson.JsonElement; - -@Component -public final class CurrencyCommandFromCommandJsonDeserializer implements FromCommandJsonDeserializer { - - private final FromJsonHelper fromJsonHelper; - - @Autowired - public CurrencyCommandFromCommandJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { - this.fromJsonHelper = fromApiJsonHelper; - } - - @Override - public CurrencyCommand commandFromCommandJson(final String commandAsJson) { - return commandFromCommandJson(null, commandAsJson); - } - - @Override - public CurrencyCommand commandFromCommandJson(final Long resourceId, final String commandAsJson) { - return commandFromCommandJson(resourceId, commandAsJson, false); - } - - @Override - public CurrencyCommand commandFromCommandJson(@SuppressWarnings("unused") final Long resourceId, final String commandAsJson, - final boolean makerCheckerApproval) { - if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); } - - final Set parametersPassedInRequest = new HashSet(); - - final JsonElement element = fromJsonHelper.parse(commandAsJson); - final String[] currencies = fromJsonHelper.extractArrayNamed("currencies", element, parametersPassedInRequest); - return new CurrencyCommand(makerCheckerApproval, currencies); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/ConfigurationDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/ConfigurationDomainServiceJpa.java index 6cbdacfde..f6643d831 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/ConfigurationDomainServiceJpa.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/ConfigurationDomainServiceJpa.java @@ -1,5 +1,6 @@ package org.mifosplatform.organisation.monetary.service; +import org.apache.commons.lang.StringUtils; import org.mifosplatform.useradministration.domain.Permission; import org.mifosplatform.useradministration.domain.PermissionRepository; import org.mifosplatform.useradministration.exception.PermissionNotFoundException; @@ -10,7 +11,7 @@ import org.springframework.stereotype.Service; public class ConfigurationDomainServiceJpa implements ConfigurationDomainService { private final PermissionRepository permissionRepository; - + /* * hard code to false to disable maker checker across the board. */ @@ -20,14 +21,14 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService public ConfigurationDomainServiceJpa(final PermissionRepository permissionRepository) { this.permissionRepository = permissionRepository; } - + @Override public boolean isMakerCheckerEnabledForTask(final String taskPermissionCode) { + if (StringUtils.isBlank(taskPermissionCode)) { throw new PermissionNotFoundException(taskPermissionCode); } + final Permission thisTask = this.permissionRepository.findOneByCode(taskPermissionCode); - if (thisTask == null) { - throw new PermissionNotFoundException(taskPermissionCode); - } - + if (thisTask == null) { throw new PermissionNotFoundException(taskPermissionCode); } + return thisTask.hasMakerCheckerEnabled() && this.makerCheckerGloablConfigurationEnabled; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/CurrencyWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/CurrencyWritePlatformService.java index ae0bf56f0..cc9601b08 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/CurrencyWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/CurrencyWritePlatformService.java @@ -1,9 +1,10 @@ package org.mifosplatform.organisation.monetary.service; -import org.mifosplatform.organisation.monetary.command.CurrencyCommand; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; public interface CurrencyWritePlatformService { - void updateAllowedCurrencies(CurrencyCommand command); + EntityIdentifier updateAllowedCurrencies(JsonCommand command); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/CurrencyWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/CurrencyWritePlatformServiceJpaRepositoryImpl.java index c1cbe412d..0733a06da 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/CurrencyWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/service/CurrencyWritePlatformServiceJpaRepositoryImpl.java @@ -2,19 +2,21 @@ package org.mifosplatform.organisation.monetary.service; import java.util.ArrayList; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; -import org.mifosplatform.infrastructure.core.data.ApiParameterError; -import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; -import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.monetary.command.CurrencyCommand; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepository; +import org.mifosplatform.organisation.monetary.exception.CurrencyNotFoundException; +import org.mifosplatform.organisation.monetary.serialization.CurrencyCommandFromApiJsonDeserializer; import org.mifosplatform.organisation.office.domain.OrganisationCurrency; import org.mifosplatform.organisation.office.domain.OrganisationCurrencyRepository; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -25,54 +27,48 @@ public class CurrencyWritePlatformServiceJpaRepositoryImpl implements CurrencyWr private final PlatformSecurityContext context; private final ApplicationCurrencyRepository applicationCurrencyRepository; private final OrganisationCurrencyRepository organisationCurrencyRepository; - private final ConfigurationDomainService configurationDomainService; + private final CurrencyCommandFromApiJsonDeserializer fromApiJsonDeserializer; @Autowired public CurrencyWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, + final CurrencyCommandFromApiJsonDeserializer fromApiJsonDeserializer, final ApplicationCurrencyRepository applicationCurrencyRepository, - final OrganisationCurrencyRepository organisationCurrencyRepository, final ConfigurationDomainService configurationDomainService) { + final OrganisationCurrencyRepository organisationCurrencyRepository) { this.context = context; + this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.applicationCurrencyRepository = applicationCurrencyRepository; this.organisationCurrencyRepository = organisationCurrencyRepository; - this.configurationDomainService = configurationDomainService; } @Transactional @Override - public void updateAllowedCurrencies(final CurrencyCommand command) { + public EntityIdentifier updateAllowedCurrencies(final JsonCommand command) { context.authenticatedUser(); - List dataValidationErrors = new ArrayList(); - DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("configuration"); + final CurrencyCommand currencyCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); + currencyCommand.validateForUpdate(); - baseDataValidator.reset().parameter("currencies").value(command.getCurrencies()).arrayNotEmpty(); + final Map changes = new LinkedHashMap(); + final List allowedCurrencyCodes = new ArrayList(); + final Set allowedCurrencies = new HashSet(); + for (final String currencyCode : currencyCommand.getCurrencies()) { - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); } + final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(currencyCode); + if (currency == null) { throw new CurrencyNotFoundException(currencyCode); } - Set allowedCurrencies = new HashSet(); + final OrganisationCurrency allowedCurrency = new OrganisationCurrency(currency.getCode(), currency.getName(), + currency.getDecimalPlaces(), currency.getNameCode(), currency.getDisplaySymbol()); - for (String currencyCode : command.getCurrencies()) { - - ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(currencyCode); - if (currency == null) { - baseDataValidator.reset().parameter("currencies").value(command.getCurrencies()) - .inValidValue("currency.code", currencyCode); - } else { - OrganisationCurrency allowedCurrency = new OrganisationCurrency(currency.getCode(), currency.getName(), - currency.getDecimalPlaces(), currency.getNameCode(), currency.getDisplaySymbol()); - - allowedCurrencies.add(allowedCurrency); - } + allowedCurrencyCodes.add(currencyCode); + allowedCurrencies.add(allowedCurrency); } + changes.put("currencies", allowedCurrencyCodes.toArray(new String[allowedCurrencyCodes.size()])); + this.organisationCurrencyRepository.deleteAll(); this.organisationCurrencyRepository.save(allowedCurrencies); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_CURRENCY") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); } + return EntityIdentifier.withChanges(null, changes); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficeTransactionsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficeTransactionsApiResource.java index 3d020bf62..038e241bd 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficeTransactionsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficeTransactionsApiResource.java @@ -3,7 +3,6 @@ package org.mifosplatform.organisation.office.api; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; @@ -22,7 +21,6 @@ import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSeriali import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.office.data.OfficeTransactionData; -import org.mifosplatform.organisation.office.serialization.BranchMoneyTransferCommandFromApiJsonDeserializer; import org.mifosplatform.organisation.office.service.OfficeReadPlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; @@ -38,24 +36,20 @@ public class OfficeTransactionsApiResource { "allowedOffices", "currencyOptions")); private final String resourceNameForReadPermissions = "OFFICE"; - private final String resourceNameForPermissions = "OFFICETRANSACTION"; private final PlatformSecurityContext context; private final OfficeReadPlatformService readPlatformService; - private final BranchMoneyTransferCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @Autowired public OfficeTransactionsApiResource(final PlatformSecurityContext context, final OfficeReadPlatformService readPlatformService, - final BranchMoneyTransferCommandFromApiJsonDeserializer fromApiJsonDeserializer, final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { this.context = context; this.readPlatformService = readPlatformService; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.toApiJsonSerializer = toApiJsonSerializer; this.apiRequestParameterHelper = apiRequestParameterHelper; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; @@ -93,19 +87,8 @@ public class OfficeTransactionsApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String transferMoneyFrom(final String apiRequestBodyAsJson) { - // TODO - complete permissions for office transactions when more - // functionality add or it is replaced by simple accounting equivalent - // (JPW) - context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); - - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "CREATE_OFFICETRANSACTION"); - context.authenticatedUser().validateHasPermissionTo("CREATE_OFFICETRANSACTION", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "officetransactions", null, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_OFFICETRANSACTION", "CREATE", + "officetransactions", null, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficesApiResource.java index 794ae6d9d..b3524a496 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficesApiResource.java @@ -27,7 +27,6 @@ import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSeria import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.office.data.OfficeData; import org.mifosplatform.organisation.office.data.OfficeLookup; -import org.mifosplatform.organisation.office.serialization.OfficeCommandFromApiJsonDeserializer; import org.mifosplatform.organisation.office.service.OfficeReadPlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; @@ -48,19 +47,16 @@ public class OfficesApiResource { private final PlatformSecurityContext context; private final OfficeReadPlatformService readPlatformService; - private final OfficeCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @Autowired public OfficesApiResource(final PlatformSecurityContext context, final OfficeReadPlatformService readPlatformService, - final OfficeCommandFromApiJsonDeserializer fromApiJsonDeserializer, final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { this.context = context; this.readPlatformService = readPlatformService; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.toApiJsonSerializer = toApiJsonSerializer; this.apiRequestParameterHelper = apiRequestParameterHelper; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; @@ -101,13 +97,8 @@ public class OfficesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String createOffice(final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", "CREATE_OFFICE"); - context.authenticatedUser().validateHasPermissionTo("CREATE_OFFICE", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "offices", null, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_OFFICE", "CREATE", "offices", + null, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } @@ -137,13 +128,8 @@ public class OfficesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updateOffice(@PathParam("officeId") final Long officeId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", "UPDATE_OFFICE"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_OFFICE", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "offices", officeId, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_OFFICE", "UPDATE", "offices", + officeId, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/command/BranchMoneyTransferCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/command/BranchMoneyTransferCommand.java index 6dd2e1f72..815e74bad 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/command/BranchMoneyTransferCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/command/BranchMoneyTransferCommand.java @@ -3,7 +3,6 @@ package org.mifosplatform.organisation.office.command; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; -import java.util.Set; import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.data.ApiParameterError; @@ -22,14 +21,8 @@ public class BranchMoneyTransferCommand { private final BigDecimal transactionAmount; private final String description; - private final transient Set parametersPassedInRequest; - private final transient boolean makerCheckerApproval; - - public BranchMoneyTransferCommand(final Set parametersPassedInRequest, final boolean makerCheckerApproval, - final Long fromOfficeId, final Long toOfficeId, final LocalDate transactionDate, final String currencyCode, - final BigDecimal transactionAmount, final String description) { - this.parametersPassedInRequest = parametersPassedInRequest; - this.makerCheckerApproval = makerCheckerApproval; + public BranchMoneyTransferCommand(final Long fromOfficeId, final Long toOfficeId, final LocalDate transactionDate, + final String currencyCode, final BigDecimal transactionAmount, final String description) { this.fromOfficeId = fromOfficeId; this.toOfficeId = toOfficeId; this.transactionDate = transactionDate; @@ -62,14 +55,6 @@ public class BranchMoneyTransferCommand { return description; } - public boolean isFromOfficeIdChanged() { - return this.parametersPassedInRequest.contains("fromOfficeId"); - } - - public boolean isApprovedByChecker() { - return this.makerCheckerApproval; - } - public void validateBranchTransfer() { List dataValidationErrors = new ArrayList(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/command/OfficeCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/command/OfficeCommand.java index c8ae213fd..becd5ec70 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/command/OfficeCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/command/OfficeCommand.java @@ -2,7 +2,6 @@ package org.mifosplatform.organisation.office.command; import java.util.ArrayList; import java.util.List; -import java.util.Set; import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.data.ApiParameterError; @@ -14,31 +13,18 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation */ public class OfficeCommand { - private final String name; private final String externalId; private final LocalDate openingDate; private final Long parentId; - private final transient Set modifiedParameters; - private final transient boolean makerCheckerApproval; - private final transient Long id; - - public OfficeCommand(final Set modifiedParameters, final boolean makerCheckerApproval, final Long id, final String officeName, - final String externalId, final Long parentId, final LocalDate openingDate) { - this.modifiedParameters = modifiedParameters; - this.makerCheckerApproval = makerCheckerApproval; - this.id = id; + public OfficeCommand(final String officeName, final String externalId, final Long parentId, final LocalDate openingDate) { this.name = officeName; this.externalId = externalId; this.parentId = parentId; this.openingDate = openingDate; } - public Long getId() { - return id; - } - public String getName() { return name; } @@ -55,26 +41,6 @@ public class OfficeCommand { return parentId; } - public boolean isNameChanged() { - return this.modifiedParameters.contains("name"); - } - - public boolean isExternalIdChanged() { - return this.modifiedParameters.contains("externalId"); - } - - public boolean isOpeningDateChanged() { - return this.modifiedParameters.contains("openingDate"); - } - - public boolean isParentChanged() { - return this.modifiedParameters.contains("parentId"); - } - - public boolean isApprovedByChecker() { - return this.makerCheckerApproval; - } - public void validateForCreate() { List dataValidationErrors = new ArrayList(); @@ -94,7 +60,6 @@ public class OfficeCommand { DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("office"); - baseDataValidator.reset().parameter("id").value(this.id).notNull(); baseDataValidator.reset().parameter("name").value(this.name).ignoreIfNull().notBlank(); baseDataValidator.reset().parameter("openingDate").value(this.openingDate).ignoreIfNull().notBlank(); baseDataValidator.reset().parameter("externalId").value(this.externalId).ignoreIfNull().notExceedingLengthOf(100); @@ -103,6 +68,6 @@ public class OfficeCommand { baseDataValidator.reset().anyOfNotNull(this.name, this.openingDate, this.externalId, this.parentId); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); } + "Validation errors exist.", dataValidationErrors); } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/Office.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/Office.java index 74a199843..ff668176f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/Office.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/Office.java @@ -1,8 +1,10 @@ package org.mifosplatform.organisation.office.domain; import java.util.Date; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import javax.persistence.Column; import javax.persistence.Entity; @@ -17,17 +19,15 @@ import javax.persistence.UniqueConstraint; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; -import org.mifosplatform.organisation.office.command.OfficeCommand; import org.mifosplatform.organisation.office.exception.CannotUpdateOfficeWithParentOfficeSameAsSelf; import org.mifosplatform.organisation.office.exception.RootOfficeParentCannotBeUpdated; import org.mifosplatform.useradministration.domain.AppUser; @Entity -@Table(name = "m_office", uniqueConstraints={ - @UniqueConstraint(columnNames = {"name"}, name="name_org"), - @UniqueConstraint(columnNames = {"external_id"}, name="externalid_org") -}) +@Table(name = "m_office", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "name_org"), + @UniqueConstraint(columnNames = { "external_id" }, name = "externalid_org") }) public class Office extends AbstractAuditableCustom { @OneToMany(fetch = FetchType.EAGER) @@ -36,30 +36,32 @@ public class Office extends AbstractAuditableCustom { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_id") - private Office parent; + private Office parent; - @Column(name = "name", nullable = false, length=100) - private String name; - - @Column(name = "hierarchy", nullable = false, length=50) - private String hierarchy; + @Column(name = "name", nullable = false, length = 100) + private String name; - @SuppressWarnings("unused") - @Column(name = "opening_date", nullable = false) + @Column(name = "hierarchy", nullable = false, length = 50) + private String hierarchy; + + @Column(name = "opening_date", nullable = false) @Temporal(TemporalType.DATE) - private Date openingDate; + private Date openingDate; - @SuppressWarnings("unused") - @Column(name = "external_id", length=100) - private String externalId; + @Column(name = "external_id", length = 100) + private String externalId; public static Office headOffice(final String name, final LocalDate openingDate, final String externalId) { return new Office(null, name, openingDate, externalId); } - - public static Office createNew(final Office parent, final String name, final LocalDate openingDate, final String externalId) { - return new Office(parent, name, openingDate, externalId); - } + + public static Office fromJson(final Office parentOffice, final JsonCommand command) { + + final String name = command.stringValueOfParameterNamed("name"); + final LocalDate openingDate = command.localDateValueOfParameterNamed("openingDate"); + final String externalId = command.stringValueOfParameterNamed("externalId"); + return new Office(parentOffice, name, openingDate, externalId); + } protected Office() { this.openingDate = null; @@ -73,113 +75,139 @@ public class Office extends AbstractAuditableCustom { this.openingDate = openingDate.toDateMidnight().toDate(); if (parent != null) { this.parent.addChild(this); - } - - if (StringUtils.isNotBlank(name)) { - this.name = name.trim(); - } else { - this.name = null; } - if (StringUtils.isNotBlank(externalId)) { - this.externalId = externalId.trim(); - } else { - this.externalId = null; - } + + if (StringUtils.isNotBlank(name)) { + this.name = name.trim(); + } else { + this.name = null; + } + if (StringUtils.isNotBlank(externalId)) { + this.externalId = externalId.trim(); + } else { + this.externalId = null; + } } - private void addChild(final Office office) { + private void addChild(final Office office) { this.children.add(office); } - - public void update(final OfficeCommand command) { - - if (command.isNameChanged()) { - this.name = StringUtils.defaultIfEmpty(command.getName(), null); - } - - if (command.isExternalIdChanged()) { - this.externalId = StringUtils.defaultIfEmpty(command.getExternalId(), null); - } - - if (command.isOpeningDateChanged()) { - if (command.getOpeningDate() != null) { - this.openingDate = command.getOpeningDate().toDate(); - } else { - this.openingDate = null; - } - } - } - - public void update(final Office newParent) { - - if (this.parent == null) { - throw new RootOfficeParentCannotBeUpdated(); - } - - if (this.identifiedBy(newParent.getId())) { - throw new CannotUpdateOfficeWithParentOfficeSameAsSelf(this.getId(), newParent.getId()); - } - - this.parent = newParent; - generateHierarchy(); - } - public boolean identifiedBy(final Long id) { - return getId().equals(id); - } + public Map update(final JsonCommand command) { - public void generateHierarchy() { - - if (parent != null) { - this.hierarchy = this.parent.hierarchyOf(this.getId()); - } else { - this.hierarchy = "."; - } - } + final Map actualChanges = new LinkedHashMap(7); - private String hierarchyOf(Long id) { - return this.hierarchy + id.toString() + "."; - } - - public String getName() { - return this.name; + final String dateFormatAsInput = command.dateFormat(); + final String localeAsInput = command.locale(); + + final String parentIdParamName = "parentId"; + if (command.isChangeInLongParameterNamed(parentIdParamName, this.parent.getId())) { + final Long newValue = command.longValueOfParameterNamed(parentIdParamName); + actualChanges.put(parentIdParamName, newValue); + } + + final String openingDateParamName = "openingDate"; + if (command.isChangeInLocalDateParameterNamed(openingDateParamName, getOpeningLocalDate())) { + final String valueAsInput = command.stringValueOfParameterNamed(openingDateParamName); + actualChanges.put(openingDateParamName, valueAsInput); + actualChanges.put("dateFormat", dateFormatAsInput); + actualChanges.put("locale", localeAsInput); + + final LocalDate newValue = command.localDateValueOfParameterNamed(openingDateParamName); + this.openingDate = newValue.toDate(); + } + + final String nameParamName = "name"; + if (command.isChangeInStringParameterNamed(nameParamName, this.name)) { + final String newValue = command.stringValueOfParameterNamed(nameParamName); + actualChanges.put(nameParamName, newValue); + this.name = newValue; + } + + final String externalIdParamName = "externalId"; + if (command.isChangeInStringParameterNamed(externalIdParamName, this.externalId)) { + final String newValue = command.stringValueOfParameterNamed(externalIdParamName); + actualChanges.put(externalIdParamName, newValue); + this.externalId = StringUtils.defaultIfEmpty(newValue, null); + } + + return actualChanges; } - public String getHierarchy() { - return hierarchy; - } + private LocalDate getOpeningLocalDate() { + LocalDate openingLocalDate = null; + if (this.openingDate != null) { + openingLocalDate = LocalDate.fromDateFields(this.openingDate); + } + return openingLocalDate; + } - public boolean hasParentOf(final Office office) { - boolean isParent = false; - if (this.parent != null) { - isParent = this.parent.equals(office); - } - return isParent; - } - - public boolean doesNotHaveAnOfficeInHierarchyWithId(Long officeId) { - return !this.hasAnOfficeInHierarchyWithId(officeId); - } - - private boolean hasAnOfficeInHierarchyWithId(Long officeId) { - - boolean match = false; - - if (identifiedBy(officeId)) { - match = true; - } - - if (!match) { - for (Office child : this.children) { - boolean result = child.hasAnOfficeInHierarchyWithId(officeId); - - if (result) { - match = result; - break; - } - } - } - - return match; - } + public void update(final Office newParent) { + + if (this.parent == null) { throw new RootOfficeParentCannotBeUpdated(); } + + if (this.identifiedBy(newParent.getId())) { throw new CannotUpdateOfficeWithParentOfficeSameAsSelf(this.getId(), newParent.getId()); } + + this.parent = newParent; + generateHierarchy(); + } + + public boolean identifiedBy(final Long id) { + return getId().equals(id); + } + + public void generateHierarchy() { + + if (parent != null) { + this.hierarchy = this.parent.hierarchyOf(this.getId()); + } else { + this.hierarchy = "."; + } + } + + private String hierarchyOf(Long id) { + return this.hierarchy + id.toString() + "."; + } + + public String getName() { + return this.name; + } + + public String getHierarchy() { + return hierarchy; + } + + public boolean hasParentOf(final Office office) { + boolean isParent = false; + if (this.parent != null) { + isParent = this.parent.equals(office); + } + return isParent; + } + + public boolean doesNotHaveAnOfficeInHierarchyWithId(Long officeId) { + return !this.hasAnOfficeInHierarchyWithId(officeId); + } + + private boolean hasAnOfficeInHierarchyWithId(Long officeId) { + + boolean match = false; + + if (identifiedBy(officeId)) { + match = true; + } + + if (!match) { + for (Office child : this.children) { + boolean result = child.hasAnOfficeInHierarchyWithId(officeId); + + if (result) { + match = result; + break; + } + } + } + + return match; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/OfficeTransaction.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/OfficeTransaction.java index 9238df490..bc296972c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/OfficeTransaction.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/OfficeTransaction.java @@ -14,6 +14,7 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.Money; @@ -23,53 +24,54 @@ import org.mifosplatform.useradministration.domain.AppUser; @Table(name = "m_office_transaction") public class OfficeTransaction extends AbstractAuditableCustom { - @SuppressWarnings("unused") - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "from_office_id") - private Office from; + @SuppressWarnings("unused") + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "from_office_id") + private Office from; - @SuppressWarnings("unused") - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "to_office_id") - private Office to; + @SuppressWarnings("unused") + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "to_office_id") + private Office to; - @SuppressWarnings("unused") - @Column(name = "transaction_date", nullable = false) - @Temporal(TemporalType.DATE) - private Date transactionDate; + @SuppressWarnings("unused") + @Column(name = "transaction_date", nullable = false) + @Temporal(TemporalType.DATE) + private Date transactionDate; - @SuppressWarnings("unused") - @Embedded - private MonetaryCurrency currency; + @SuppressWarnings("unused") + @Embedded + private MonetaryCurrency currency; - @SuppressWarnings("unused") - @Column(name = "transaction_amount", scale = 6, precision = 19, nullable = false) - private BigDecimal transactionAmount; - - @SuppressWarnings("unused") - @Column(name = "description", nullable=true, length=100) - private String description; + @SuppressWarnings("unused") + @Column(name = "transaction_amount", scale = 6, precision = 19, nullable = false) + private BigDecimal transactionAmount; - protected OfficeTransaction() { - this.transactionDate = null; - } + @SuppressWarnings("unused") + @Column(name = "description", nullable = true, length = 100) + private String description; - public static OfficeTransaction create(Office fromOffice, Office toOffice, LocalDate transactionLocalDate, Money amount, String description) { + public static OfficeTransaction fromJson(final Office fromOffice, final Office toOffice, final Money amount, final JsonCommand command) { - Date transactionDate = null; - if (transactionLocalDate != null) { - transactionDate = transactionLocalDate.toDate(); - } + final LocalDate transactionLocalDate = command.localDateValueOfParameterNamed("transactionDate"); + final String description = command.stringValueOfParameterNamed("description"); - return new OfficeTransaction(fromOffice, toOffice, transactionDate, amount, description); - } + return new OfficeTransaction(fromOffice, toOffice, transactionLocalDate, amount, description); + } - private OfficeTransaction(final Office fromOffice,final Office toOffice, final Date transactionDate, final Money amount, String description) { - this.from = fromOffice; - this.to = toOffice; - this.transactionDate = transactionDate; - this.currency = amount.getCurrency(); - this.transactionAmount = amount.getAmount(); - this.description = description; - } + protected OfficeTransaction() { + this.transactionDate = null; + } + + private OfficeTransaction(final Office fromOffice, final Office toOffice, final LocalDate transactionLocalDate, final Money amount, + final String description) { + this.from = fromOffice; + this.to = toOffice; + if (transactionLocalDate != null) { + this.transactionDate = transactionLocalDate.toDate(); + } + this.currency = amount.getCurrency(); + this.transactionAmount = amount.getAmount(); + this.description = description; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/handler/CreateOfficeCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/handler/CreateOfficeCommandHandler.java new file mode 100644 index 000000000..60c9c97af --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/handler/CreateOfficeCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.organisation.office.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.organisation.office.service.OfficeWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateOfficeCommandHandler implements NewCommandSourceHandler { + + private final OfficeWritePlatformService writePlatformService; + + @Autowired + public CreateOfficeCommandHandler(final OfficeWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.createOffice(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/handler/CreateOfficeTransactionCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/handler/CreateOfficeTransactionCommandHandler.java new file mode 100644 index 000000000..786edd6cc --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/handler/CreateOfficeTransactionCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.organisation.office.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.organisation.office.service.OfficeWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateOfficeTransactionCommandHandler implements NewCommandSourceHandler { + + private final OfficeWritePlatformService writePlatformService; + + @Autowired + public CreateOfficeTransactionCommandHandler(final OfficeWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.externalBranchMoneyTransfer(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/handler/UpdateOfficeCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/handler/UpdateOfficeCommandHandler.java new file mode 100644 index 000000000..6e36b8d35 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/handler/UpdateOfficeCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.organisation.office.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.organisation.office.service.OfficeWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateOfficeCommandHandler implements NewCommandSourceHandler { + + private final OfficeWritePlatformService writePlatformService; + + @Autowired + public UpdateOfficeCommandHandler(final OfficeWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.updateOffice(command.resourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/BranchMoneyTransferCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/BranchMoneyTransferCommandFromApiJsonDeserializer.java index 69bf5bfbc..b28e1a427 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/BranchMoneyTransferCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/BranchMoneyTransferCommandFromApiJsonDeserializer.java @@ -7,9 +7,10 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.organisation.office.command.BranchMoneyTransferCommand; @@ -35,33 +36,28 @@ public final class BranchMoneyTransferCommandFromApiJsonDeserializer extends Abs private final FromJsonHelper fromApiJsonHelper; @Autowired - public BranchMoneyTransferCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, - final CommandSerializer commandSerializerService) { - super(commandSerializerService); + public BranchMoneyTransferCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; } @Override - public BranchMoneyTransferCommand commandFromApiJson(@SuppressWarnings("unused") final Long resourceId, final String json) { + public BranchMoneyTransferCommand commandFromApiJson(final String json) { + + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final Set parametersPassedInRequest = new HashSet(); - final JsonElement element = fromApiJsonHelper.parse(json); - final Long fromOfficeId = fromApiJsonHelper.extractLongNamed("fromOfficeId", element, parametersPassedInRequest); - final Long toOfficeId = fromApiJsonHelper.extractLongNamed("toOfficeId", element, parametersPassedInRequest); - final LocalDate transactionLocalDate = fromApiJsonHelper.extractLocalDateNamed("transactionDate", element, - parametersPassedInRequest); + final Long fromOfficeId = fromApiJsonHelper.extractLongNamed("fromOfficeId", element); + final Long toOfficeId = fromApiJsonHelper.extractLongNamed("toOfficeId", element); + final LocalDate transactionLocalDate = fromApiJsonHelper.extractLocalDateNamed("transactionDate", element); - final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element, parametersPassedInRequest); - final BigDecimal transactionAmountValue = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("transactionAmount", element, - parametersPassedInRequest); - final String description = fromApiJsonHelper.extractStringNamed("description", element, parametersPassedInRequest); + final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element); + final BigDecimal transactionAmountValue = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("transactionAmount", element); + final String description = fromApiJsonHelper.extractStringNamed("description", element); - return new BranchMoneyTransferCommand(parametersPassedInRequest, false, fromOfficeId, toOfficeId, transactionLocalDate, - currencyCode, transactionAmountValue, description); + return new BranchMoneyTransferCommand(fromOfficeId, toOfficeId, transactionLocalDate, currencyCode, transactionAmountValue, + description); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/BranchMoneyTransferCommandFromCommandJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/BranchMoneyTransferCommandFromCommandJsonDeserializer.java deleted file mode 100644 index 5790e18ba..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/BranchMoneyTransferCommandFromCommandJsonDeserializer.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.mifosplatform.organisation.office.serialization; - -import java.math.BigDecimal; -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.joda.time.LocalDate; -import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.serialization.AbstractFromCommandJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.organisation.office.command.BranchMoneyTransferCommand; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.google.gson.JsonElement; - -@Component -public final class BranchMoneyTransferCommandFromCommandJsonDeserializer extends - AbstractFromCommandJsonDeserializer { - - private final FromJsonHelper fromJsonHelper; - - @Autowired - public BranchMoneyTransferCommandFromCommandJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { - this.fromJsonHelper = fromApiJsonHelper; - } - - @Override - public BranchMoneyTransferCommand commandFromCommandJson(@SuppressWarnings("unused") final Long resourceId, final String commandAsJson, - final boolean makerCheckerApproval) { - if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); } - - final Set parametersPassedInRequest = new HashSet(); - - final JsonElement element = fromJsonHelper.parse(commandAsJson); - final Long fromOfficeId = fromJsonHelper.extractLongNamed("fromOfficeId", element, parametersPassedInRequest); - final Long toOfficeId = fromJsonHelper.extractLongNamed("toOfficeId", element, parametersPassedInRequest); - final LocalDate transactionLocalDate = fromJsonHelper.extractLocalDateAsArrayNamed("transactionDate", element, - parametersPassedInRequest); - final String currencyCode = fromJsonHelper.extractStringNamed("currencyCode", element, parametersPassedInRequest); - final BigDecimal transactionAmountValue = fromJsonHelper.extractBigDecimalNamed("transactionAmount", element, - parametersPassedInRequest); - final String description = fromJsonHelper.extractStringNamed("description", element, parametersPassedInRequest); - - return new BranchMoneyTransferCommand(parametersPassedInRequest, makerCheckerApproval, fromOfficeId, toOfficeId, - transactionLocalDate, currencyCode, transactionAmountValue, description); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/OfficeCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/OfficeCommandFromApiJsonDeserializer.java index cb3a3cf8e..5e618a312 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/OfficeCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/OfficeCommandFromApiJsonDeserializer.java @@ -6,9 +6,10 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.organisation.office.command.OfficeCommand; @@ -28,31 +29,29 @@ public final class OfficeCommandFromApiJsonDeserializer extends AbstractFromApiJ /** * The parameters supported for this command. */ - private final Set supportedParameters = new HashSet(Arrays.asList("name", "parentId", "openingDate", "externalId", "locale", "dateFormat")); + private final Set supportedParameters = new HashSet(Arrays.asList("name", "parentId", "openingDate", "externalId", + "locale", "dateFormat")); private final FromJsonHelper fromApiJsonHelper; @Autowired - public OfficeCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, final CommandSerializer commandSerializerService) { - super(commandSerializerService); + public OfficeCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; } @Override - public OfficeCommand commandFromApiJson(final Long officeId, final String json) { + public OfficeCommand commandFromApiJson(final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final Set parametersPassedInRequest = new HashSet(); - final JsonElement element = fromApiJsonHelper.parse(json); - final String name = fromApiJsonHelper.extractStringNamed("name", element, parametersPassedInRequest); - final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element, parametersPassedInRequest); - final Long parentId = fromApiJsonHelper.extractLongNamed("parentId", element, parametersPassedInRequest); - final LocalDate openingLocalDate = fromApiJsonHelper.extractLocalDateNamed("openingDate", element, parametersPassedInRequest); + final String name = fromApiJsonHelper.extractStringNamed("name", element); + final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element); + final Long parentId = fromApiJsonHelper.extractLongNamed("parentId", element); + final LocalDate openingLocalDate = fromApiJsonHelper.extractLocalDateNamed("openingDate", element); - return new OfficeCommand(parametersPassedInRequest, false, officeId, name, externalId, parentId, openingLocalDate); + return new OfficeCommand(name, externalId, parentId, openingLocalDate); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/OfficeCommandFromCommandJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/OfficeCommandFromCommandJsonDeserializer.java deleted file mode 100644 index 7983f4cdb..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/serialization/OfficeCommandFromCommandJsonDeserializer.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.mifosplatform.organisation.office.serialization; - -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.joda.time.LocalDate; -import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.serialization.AbstractFromCommandJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.organisation.office.command.OfficeCommand; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.google.gson.JsonElement; - -@Component -public final class OfficeCommandFromCommandJsonDeserializer extends AbstractFromCommandJsonDeserializer { - - private final FromJsonHelper fromJsonHelper; - - @Autowired - public OfficeCommandFromCommandJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { - this.fromJsonHelper = fromApiJsonHelper; - } - - @Override - public OfficeCommand commandFromCommandJson(final Long officeId, final String commandAsJson, final boolean makerCheckerApproval) { - if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); } - - final Set parametersPassedInRequest = new HashSet(); - - final JsonElement element = fromJsonHelper.parse(commandAsJson); - - final String name = fromJsonHelper.extractStringNamed("name", element, parametersPassedInRequest); - final String externalId = fromJsonHelper.extractStringNamed("externalId", element, parametersPassedInRequest); - final Long parentId = fromJsonHelper.extractLongNamed("parentId", element, parametersPassedInRequest); - final LocalDate openingLocalDate = fromJsonHelper.extractLocalDateAsArrayNamed("openingDate", element, parametersPassedInRequest); - - return new OfficeCommand(parametersPassedInRequest, makerCheckerApproval, officeId, name, externalId, parentId, openingLocalDate); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeWritePlatformService.java index b22f61324..16712569e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeWritePlatformService.java @@ -1,13 +1,13 @@ package org.mifosplatform.organisation.office.service; -import org.mifosplatform.organisation.office.command.BranchMoneyTransferCommand; -import org.mifosplatform.organisation.office.command.OfficeCommand; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; public interface OfficeWritePlatformService { - Long createOffice(OfficeCommand command); + EntityIdentifier createOffice(JsonCommand command); - Long updateOffice(OfficeCommand command); + EntityIdentifier updateOffice(Long officeId, JsonCommand command); - Long externalBranchMoneyTransfer(BranchMoneyTransferCommand command); + EntityIdentifier externalBranchMoneyTransfer(JsonCommand command); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java index 7f2de151d..f70a64e08 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeWritePlatformServiceJpaRepositoryImpl.java @@ -1,5 +1,9 @@ package org.mifosplatform.organisation.office.service; +import java.util.Map; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; @@ -8,7 +12,6 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyReposit import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.monetary.exception.CurrencyNotFoundException; -import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; import org.mifosplatform.organisation.office.command.BranchMoneyTransferCommand; import org.mifosplatform.organisation.office.command.OfficeCommand; import org.mifosplatform.organisation.office.domain.Office; @@ -16,7 +19,8 @@ import org.mifosplatform.organisation.office.domain.OfficeRepository; import org.mifosplatform.organisation.office.domain.OfficeTransaction; import org.mifosplatform.organisation.office.domain.OfficeTransactionRepository; import org.mifosplatform.organisation.office.exception.OfficeNotFoundException; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; +import org.mifosplatform.organisation.office.serialization.BranchMoneyTransferCommandFromApiJsonDeserializer; +import org.mifosplatform.organisation.office.serialization.OfficeCommandFromApiJsonDeserializer; import org.mifosplatform.useradministration.domain.AppUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,33 +35,39 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP private final static Logger logger = LoggerFactory.getLogger(OfficeWritePlatformServiceJpaRepositoryImpl.class); private final PlatformSecurityContext context; + private final OfficeCommandFromApiJsonDeserializer fromApiJsonDeserializer; + private final BranchMoneyTransferCommandFromApiJsonDeserializer moneyTransferCommandFromApiJsonDeserializer; private final OfficeRepository officeRepository; private final OfficeTransactionRepository officeMonetaryTransferRepository; private final ApplicationCurrencyRepository applicationCurrencyRepository; - private final ConfigurationDomainService configurationDomainService; @Autowired - public OfficeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final OfficeRepository officeRepository, - final OfficeTransactionRepository officeMonetaryTransferRepository, - final ApplicationCurrencyRepository applicationCurrencyRepository, final ConfigurationDomainService configurationDomainService) { + public OfficeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, + final OfficeCommandFromApiJsonDeserializer fromApiJsonDeserializer, + final BranchMoneyTransferCommandFromApiJsonDeserializer moneyTransferCommandFromApiJsonDeserializer, + final OfficeRepository officeRepository, final OfficeTransactionRepository officeMonetaryTransferRepository, + final ApplicationCurrencyRepository applicationCurrencyRepository) { this.context = context; + this.fromApiJsonDeserializer = fromApiJsonDeserializer; + this.moneyTransferCommandFromApiJsonDeserializer = moneyTransferCommandFromApiJsonDeserializer; this.officeRepository = officeRepository; this.officeMonetaryTransferRepository = officeMonetaryTransferRepository; this.applicationCurrencyRepository = applicationCurrencyRepository; - this.configurationDomainService = configurationDomainService; } @Transactional @Override - public Long createOffice(final OfficeCommand command) { + public EntityIdentifier createOffice(final JsonCommand command) { try { final AppUser currentUser = context.authenticatedUser(); - command.validateForCreate(); - final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, command.getParentId()); + final OfficeCommand officeCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); + officeCommand.validateForCreate(); - final Office office = Office.createNew(parent, command.getName(), command.getOpeningDate(), command.getExternalId()); + final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeCommand.getParentId()); + + final Office office = Office.fromJson(parent, command); // pre save to generate id for use in office hierarchy this.officeRepository.save(office); @@ -66,90 +76,94 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP this.officeRepository.save(office); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_OFFICE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return office.getId(); + return EntityIdentifier.resourceResult(office.getId(), null); } catch (DataIntegrityViolationException dve) { handleOfficeDataIntegrityIssues(command, dve); - return Long.valueOf(-1); + return EntityIdentifier.empty(); } } @Transactional @Override - public Long updateOffice(final OfficeCommand command) { + public EntityIdentifier updateOffice(final Long officeId, final JsonCommand command) { try { final AppUser currentUser = context.authenticatedUser(); - command.validateForUpdate(); - final Office office = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, command.getId()); + final OfficeCommand officeCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); + officeCommand.validateForUpdate(); - office.update(command); + final Office office = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeId); - if (command.isParentChanged()) { - final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, command.getParentId()); + final Map changes = office.update(command); + + if (changes.containsKey("parentId")) { + final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeCommand.getParentId()); office.update(parent); } - this.officeRepository.save(office); + if (!changes.isEmpty()) { + this.officeRepository.saveAndFlush(office); + } - if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_OFFICE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return office.getId(); + return EntityIdentifier.withChanges(office.getId(), changes); } catch (DataIntegrityViolationException dve) { handleOfficeDataIntegrityIssues(command, dve); - return Long.valueOf(-1); + return EntityIdentifier.empty(); } } @Transactional @Override - public Long externalBranchMoneyTransfer(final BranchMoneyTransferCommand command) { + public EntityIdentifier externalBranchMoneyTransfer(final JsonCommand command) { context.authenticatedUser(); - command.validateBranchTransfer(); + + final BranchMoneyTransferCommand moneyTransferCommand = this.moneyTransferCommandFromApiJsonDeserializer.commandFromApiJson(command + .json()); + moneyTransferCommand.validateBranchTransfer(); Office fromOffice = null; - if (command.getFromOfficeId() != null) { - fromOffice = this.officeRepository.findOne(command.getFromOfficeId()); + if (moneyTransferCommand.getFromOfficeId() != null) { + fromOffice = this.officeRepository.findOne(moneyTransferCommand.getFromOfficeId()); } Office toOffice = null; - if (command.getToOfficeId() != null) { - toOffice = this.officeRepository.findOne(command.getToOfficeId()); + if (moneyTransferCommand.getToOfficeId() != null) { + toOffice = this.officeRepository.findOne(moneyTransferCommand.getToOfficeId()); } - if (fromOffice == null && toOffice == null) { throw new OfficeNotFoundException(command.getToOfficeId()); } + if (fromOffice == null && toOffice == null) { throw new OfficeNotFoundException(moneyTransferCommand.getToOfficeId()); } - final String currencyCode = command.getCurrencyCode(); + final String currencyCode = moneyTransferCommand.getCurrencyCode(); final ApplicationCurrency appCurrency = this.applicationCurrencyRepository.findOneByCode(currencyCode); if (appCurrency == null) { throw new CurrencyNotFoundException(currencyCode); } final MonetaryCurrency currency = new MonetaryCurrency(appCurrency.getCode(), appCurrency.getDecimalPlaces()); - final Money amount = Money.of(currency, command.getTransactionAmount()); + final Money amount = Money.of(currency, moneyTransferCommand.getTransactionAmount()); - final OfficeTransaction entity = OfficeTransaction.create(fromOffice, toOffice, command.getTransactionDate(), amount, - command.getDescription()); + final OfficeTransaction entity = OfficeTransaction.fromJson(fromOffice, toOffice, amount, command); this.officeMonetaryTransferRepository.save(entity); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_OFFICETRANSACTION") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return entity.getId(); + return EntityIdentifier.resourceResult(entity.getId(), null); } /* * Guaranteed to throw an exception no matter what the data integrity issue * is. */ - private void handleOfficeDataIntegrityIssues(final OfficeCommand command, DataIntegrityViolationException dve) { + private void handleOfficeDataIntegrityIssues(final JsonCommand command, DataIntegrityViolationException dve) { Throwable realCause = dve.getMostSpecificCause(); if (realCause.getMessage().contains("externalid_org")) { - throw new PlatformDataIntegrityException("error.msg.office.duplicate.externalId", "Office with externalId {0} already exists", - "externalId", command.getExternalId()); - } else if (realCause.getMessage().contains("name_org")) { throw new PlatformDataIntegrityException( - "error.msg.office.duplicate.name", "Office with name {0} already exists", "name", command.getName()); } + final String externalId = command.stringValueOfParameterNamed("externalId"); + throw new PlatformDataIntegrityException("error.msg.office.duplicate.externalId", "Office with externalId `" + externalId + + "` already exists", "externalId", externalId); + } else if (realCause.getMessage().contains("name_org")) { + final String name = command.stringValueOfParameterNamed("name"); + throw new PlatformDataIntegrityException("error.msg.office.duplicate.name", "Office with name `" + name + "` already exists", + "name", name); + } logger.error(dve.getMessage(), dve); throw new PlatformDataIntegrityException("error.msg.office.unknown.data.integrity.issue", @@ -160,10 +174,11 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP * used to restrict modifying operations to office that are either the users * office or lower (child) in the office hierarchy */ - private Office validateUserPriviledgeOnOfficeAndRetrieve(AppUser currentUser, Long officeId) { + private Office validateUserPriviledgeOnOfficeAndRetrieve(final AppUser currentUser, final Long officeId) { - Office userOffice = this.officeRepository.findOne(currentUser.getOffice().getId()); - if (userOffice == null) { throw new OfficeNotFoundException(currentUser.getOffice().getId()); } + final Long userOfficeId = currentUser.getOffice().getId(); + final Office userOffice = this.officeRepository.findOne(userOfficeId); + if (userOffice == null) { throw new OfficeNotFoundException(userOfficeId); } if (userOffice.doesNotHaveAnOfficeInHierarchyWithId(officeId)) { throw new NoAuthorizationException( "User does not have sufficient priviledges to act on the provided office."); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/api/StaffApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/api/StaffApiResource.java index c9d183ccb..accd97fc7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/api/StaffApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/api/StaffApiResource.java @@ -3,7 +3,6 @@ package org.mifosplatform.organisation.staff.api; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; @@ -20,7 +19,6 @@ import javax.ws.rs.core.UriInfo; import org.apache.commons.lang.StringUtils; import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; -import org.mifosplatform.infrastructure.codes.data.CodeData; import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; @@ -29,7 +27,6 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext import org.mifosplatform.organisation.office.data.OfficeLookup; import org.mifosplatform.organisation.office.service.OfficeReadPlatformService; import org.mifosplatform.organisation.staff.data.StaffData; -import org.mifosplatform.organisation.staff.serialization.StaffCommandFromApiJsonDeserializer; import org.mifosplatform.organisation.staff.service.StaffReadPlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; @@ -41,7 +38,8 @@ import org.springframework.stereotype.Component; public class StaffApiResource { /** - * The set of parameters that are supported in response for {@link CodeData} + * The set of parameters that are supported in response for + * {@link StaffData}. */ private final Set RESPONSE_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "firstname", "lastname", "displayName", "officeId", "officeName", "loanOfficerFlag", "allowedOffices")); @@ -51,20 +49,18 @@ public class StaffApiResource { private final PlatformSecurityContext context; private final StaffReadPlatformService readPlatformService; private final OfficeReadPlatformService officeReadPlatformService; - private final StaffCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @Autowired public StaffApiResource(final PlatformSecurityContext context, final StaffReadPlatformService readPlatformService, - final OfficeReadPlatformService officeReadPlatformService, final StaffCommandFromApiJsonDeserializer fromApiJsonDeserializer, - final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, + final OfficeReadPlatformService officeReadPlatformService, final DefaultToApiJsonSerializer toApiJsonSerializer, + final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { this.context = context; this.readPlatformService = readPlatformService; this.officeReadPlatformService = officeReadPlatformService; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.toApiJsonSerializer = toApiJsonSerializer; this.apiRequestParameterHelper = apiRequestParameterHelper; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; @@ -90,13 +86,8 @@ public class StaffApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String createStaff(final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", "CREATE_STAFF"); - context.authenticatedUser().validateHasPermissionTo("CREATE_STAFF", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "staff", null, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_STAFF", "CREATE", "staff", null, + apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } @@ -126,13 +117,8 @@ public class StaffApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updateStaff(@PathParam("staffId") final Long staffId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", "UPDATE_STAFF"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_STAFF", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(staffId, apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "staff", staffId, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_STAFF", "UPDATE", "staff", + staffId, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/command/StaffCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/command/StaffCommand.java index b92fb3390..e968fa0c5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/command/StaffCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/command/StaffCommand.java @@ -2,7 +2,6 @@ package org.mifosplatform.organisation.staff.command; import java.util.ArrayList; import java.util.List; -import java.util.Set; import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; @@ -18,61 +17,13 @@ public class StaffCommand { private final Long officeId; private final Boolean isLoanOfficer; - private final transient Set parametersPassedInRequest; - private final transient boolean makerCheckerApproval; - private final transient Long id; - - public StaffCommand(final Set parametersPassedInRequest, final boolean makerCheckerApproval, final Long id, - final Long officeId, final String firstName, final String lastName, final Boolean isLoanOfficer) { - this.parametersPassedInRequest = parametersPassedInRequest; - this.makerCheckerApproval = makerCheckerApproval; - this.id = id; + public StaffCommand(final Long officeId, final String firstName, final String lastName, final Boolean isLoanOfficer) { this.firstname = firstName; this.lastname = lastName; this.officeId = officeId; this.isLoanOfficer = isLoanOfficer; } - public Long getId() { - return id; - } - - public String getFirstname() { - return this.firstname; - } - - public String getLastname() { - return this.lastname; - } - - public Long getOfficeId() { - return officeId; - } - - public Boolean getIsLoanOfficer() { - return this.isLoanOfficer; - } - - public boolean isFirstnameChanged() { - return this.parametersPassedInRequest.contains("firstname"); - } - - public boolean isLastnameChanged() { - return this.parametersPassedInRequest.contains("lastname"); - } - - public boolean isLoanOfficerFlagChanged() { - return this.parametersPassedInRequest.contains("isLoanOfficer"); - } - - public boolean isOfficeChanged() { - return this.parametersPassedInRequest.contains("officeId"); - } - - public boolean isApprovedByChecker() { - return this.makerCheckerApproval; - } - public void validateForCreate() { List dataValidationErrors = new ArrayList(); @@ -91,7 +42,6 @@ public class StaffCommand { DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("staff"); - baseDataValidator.reset().parameter("id").value(this.id).notNull(); baseDataValidator.reset().parameter("officeId").value(this.officeId).ignoreIfNull().integerGreaterThanZero(); baseDataValidator.reset().parameter("firstname").value(this.firstname).ignoreIfNull().notBlank().notExceedingLengthOf(50); baseDataValidator.reset().parameter("lastname").value(this.lastname).ignoreIfNull().notBlank().notExceedingLengthOf(50); @@ -101,6 +51,6 @@ public class StaffCommand { baseDataValidator.reset().anyOfNotNull(this.firstname, this.lastname, this.officeId, this.isLoanOfficer); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); } + "Validation errors exist.", dataValidationErrors); } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/Staff.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/Staff.java index baa701b17..6072e6a90 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/Staff.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/Staff.java @@ -1,5 +1,8 @@ package org.mifosplatform.organisation.staff.domain; +import java.util.LinkedHashMap; +import java.util.Map; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.JoinColumn; @@ -8,9 +11,9 @@ import javax.persistence.Table; import javax.persistence.UniqueConstraint; import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; import org.mifosplatform.organisation.office.domain.Office; -import org.mifosplatform.organisation.staff.command.StaffCommand; import org.mifosplatform.useradministration.domain.AppUser; @Entity @@ -28,7 +31,6 @@ public class Staff extends AbstractAuditableCustom { private String displayName; // Office to which this employee belongs - @SuppressWarnings("unused") @ManyToOne @JoinColumn(name = "office_id", nullable = false) private Office office; @@ -37,6 +39,20 @@ public class Staff extends AbstractAuditableCustom { @Column(name = "is_loan_officer ", nullable = false) private boolean loanOfficer; + public static Staff fromJson(final Office staffOffice, final JsonCommand command) { + + final String firstnameParamName = "firstname"; + String firstname = command.stringValueOfParameterNamed(firstnameParamName); + + final String lastnameParamName = "lastname"; + String lastname = command.stringValueOfParameterNamed(lastnameParamName); + + final String isLoanOfficerParamName = "isLoanOfficer"; + final boolean isLoanOfficer = command.booleanPrimitiveValueOfParameterNamed(isLoanOfficerParamName); + + return new Staff(staffOffice, firstname, lastname, isLoanOfficer); + } + public static Staff createNew(Office staffOffice, final String firstname, final String lastname, boolean isLoanOfficer) { return new Staff(staffOffice, firstname, lastname, isLoanOfficer); } @@ -53,32 +69,56 @@ public class Staff extends AbstractAuditableCustom { deriveDisplayName(firstname); } - public void update(final StaffCommand command, final Office staffOffice) { - if (command.isOfficeChanged()) { - this.office = staffOffice; - } - - if (command.isFirstnameChanged()) { - this.firstname = StringUtils.defaultIfEmpty(command.getFirstname(), null); - } - - if (command.isLastnameChanged()) { - this.lastname = StringUtils.defaultIfEmpty(command.getLastname(), null); - } - - if (command.isLastnameChanged() || command.isFirstnameChanged()) { - deriveDisplayName(firstname); - } - - if (command.isLoanOfficerFlagChanged()) { - this.loanOfficer = command.getIsLoanOfficer(); - } + public void changeOffice(final Office newOffice) { + this.office = newOffice; } - + + public Map update(final JsonCommand command) { + + final Map actualChanges = new LinkedHashMap(7); + + final String officeIdParamName = "officeId"; + if (command.isChangeInLongParameterNamed(officeIdParamName, this.office.getId())) { + final Long newValue = command.longValueOfParameterNamed(officeIdParamName); + actualChanges.put(officeIdParamName, newValue); + } + + boolean firstnameChanged = false; + final String firstnameParamName = "firstname"; + if (command.isChangeInStringParameterNamed(firstnameParamName, this.firstname)) { + final String newValue = command.stringValueOfParameterNamed(firstnameParamName); + actualChanges.put(firstnameParamName, newValue); + this.firstname = newValue; + firstnameChanged = true; + } + + boolean lastnameChanged = false; + final String lastnameParamName = "lastname"; + if (command.isChangeInStringParameterNamed(lastnameParamName, this.lastname)) { + final String newValue = command.stringValueOfParameterNamed(lastnameParamName); + actualChanges.put(lastnameParamName, newValue); + this.lastname = newValue; + lastnameChanged = true; + } + + if (firstnameChanged || lastnameChanged) { + deriveDisplayName(this.firstname); + } + + final String isLoanOfficerParamName = "isLoanOfficer"; + if (command.isChangeInBooleanParameterNamed(isLoanOfficerParamName, this.loanOfficer)) { + final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isLoanOfficerParamName); + actualChanges.put(isLoanOfficerParamName, newValue); + this.loanOfficer = newValue; + } + + return actualChanges; + } + public boolean isNotLoanOfficer() { return !isLoanOfficer(); } - + public boolean isLoanOfficer() { return this.loanOfficer; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/handler/CreateStaffCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/handler/CreateStaffCommandHandler.java new file mode 100644 index 000000000..c87f6a33a --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/handler/CreateStaffCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.organisation.staff.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.organisation.staff.service.StaffWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateStaffCommandHandler implements NewCommandSourceHandler { + + private final StaffWritePlatformService writePlatformService; + + @Autowired + public CreateStaffCommandHandler(final StaffWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.createStaff(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/handler/UpdateStaffCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/handler/UpdateStaffCommandHandler.java new file mode 100644 index 000000000..ded418cba --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/handler/UpdateStaffCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.organisation.staff.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.organisation.staff.service.StaffWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateStaffCommandHandler implements NewCommandSourceHandler { + + private final StaffWritePlatformService writePlatformService; + + @Autowired + public UpdateStaffCommandHandler(final StaffWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.updateStaff(command.resourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/serialization/StaffCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/serialization/StaffCommandFromApiJsonDeserializer.java index 6ab3a0737..e921081d0 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/serialization/StaffCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/serialization/StaffCommandFromApiJsonDeserializer.java @@ -6,20 +6,23 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; +import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.organisation.staff.command.StaffCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import com.google.gson.JsonElement; import com.google.gson.reflect.TypeToken; /** * Implementation of {@link FromApiJsonDeserializer} for {@link StaffCommand}'s. */ @Component -public final class StaffCommandFromApiJsonDeserializer implements FromApiJsonDeserializer { +public final class StaffCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer { /** * The parameters supported for this command. @@ -27,42 +30,26 @@ public final class StaffCommandFromApiJsonDeserializer implements FromApiJsonDes private final Set supportedParameters = new HashSet(Arrays.asList("firstname", "lastname", "officeId", "isLoanOfficer")); private final FromJsonHelper fromApiJsonHelper; - private final StaffCommandFromCommandJsonDeserializer fromCommandJsonDeserializer; - private final CommandSerializer commandSerializerService; @Autowired - public StaffCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, - final StaffCommandFromCommandJsonDeserializer fromCommandJsonDeserializer, - final CommandSerializer commandSerializerService) { + public StaffCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; - this.fromCommandJsonDeserializer = fromCommandJsonDeserializer; - this.commandSerializerService = commandSerializerService; } @Override public StaffCommand commandFromApiJson(final String json) { - return commandFromApiJson(null, json); - } - - @Override - public StaffCommand commandFromApiJson(final Long roleId, final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - return this.fromCommandJsonDeserializer.commandFromCommandJson(roleId, json); - } + final JsonElement element = fromApiJsonHelper.parse(json); - @Override - public String serializedCommandJsonFromApiJson(final String json) { - final StaffCommand command = commandFromApiJson(json); - return this.commandSerializerService.serializeCommandToJson(command); - } + final String firstname = fromApiJsonHelper.extractStringNamed("firstname", element); + final String lastname = fromApiJsonHelper.extractStringNamed("lastname", element); + final Boolean isLoanOfficer = fromApiJsonHelper.extractBooleanNamed("isLoanOfficer", element); + final Long officeId = fromApiJsonHelper.extractLongNamed("officeId", element); - @Override - public String serializedCommandJsonFromApiJson(final Long roleId, final String json) { - final StaffCommand command = commandFromApiJson(roleId, json); - return this.commandSerializerService.serializeCommandToJson(command); + return new StaffCommand(officeId, firstname, lastname, isLoanOfficer); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/serialization/StaffCommandFromCommandJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/serialization/StaffCommandFromCommandJsonDeserializer.java deleted file mode 100644 index c17b5ae05..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/serialization/StaffCommandFromCommandJsonDeserializer.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.mifosplatform.organisation.staff.serialization; - -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.serialization.FromCommandJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.organisation.staff.command.StaffCommand; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.google.gson.JsonElement; - -@Component -public final class StaffCommandFromCommandJsonDeserializer implements FromCommandJsonDeserializer { - - private final FromJsonHelper fromJsonHelper; - - @Autowired - public StaffCommandFromCommandJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { - this.fromJsonHelper = fromApiJsonHelper; - } - - @Override - public StaffCommand commandFromCommandJson(final String commandAsJson) { - return commandFromCommandJson(null, commandAsJson); - } - - @Override - public StaffCommand commandFromCommandJson(final Long staffId, final String commandAsJson) { - return commandFromCommandJson(staffId, commandAsJson, false); - } - - @Override - public StaffCommand commandFromCommandJson(final Long staffId, final String commandAsJson, final boolean makerCheckerApproval) { - if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); } - - final Set parametersPassedInRequest = new HashSet(); - - final JsonElement element = fromJsonHelper.parse(commandAsJson); - - final String firstname = fromJsonHelper.extractStringNamed("firstname", element, parametersPassedInRequest); - final String lastname = fromJsonHelper.extractStringNamed("lastname", element, parametersPassedInRequest); - final Boolean isLoanOfficer = fromJsonHelper.extractBooleanNamed("isLoanOfficer", element, parametersPassedInRequest); - final Long officeId = fromJsonHelper.extractLongNamed("officeId", element, parametersPassedInRequest); - - return new StaffCommand(parametersPassedInRequest, makerCheckerApproval, staffId, officeId, firstname, lastname, isLoanOfficer); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/service/StaffWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/service/StaffWritePlatformService.java index 619fa9600..29432c6e9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/service/StaffWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/service/StaffWritePlatformService.java @@ -1,10 +1,11 @@ package org.mifosplatform.organisation.staff.service; -import org.mifosplatform.organisation.staff.command.StaffCommand; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; public interface StaffWritePlatformService { - Long createStaff(final StaffCommand command); + EntityIdentifier createStaff(final JsonCommand command); - Long updateStaff(final StaffCommand command); + EntityIdentifier updateStaff(final Long staffId, final JsonCommand command); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/service/StaffWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/service/StaffWritePlatformServiceJpaRepositoryImpl.java index c7fec3513..c10b6f943 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/service/StaffWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/service/StaffWritePlatformServiceJpaRepositoryImpl.java @@ -1,9 +1,12 @@ package org.mifosplatform.organisation.staff.service; +import java.util.Map; + import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; import org.mifosplatform.organisation.office.domain.Office; import org.mifosplatform.organisation.office.domain.OfficeRepository; import org.mifosplatform.organisation.office.exception.OfficeNotFoundException; @@ -11,7 +14,7 @@ import org.mifosplatform.organisation.staff.command.StaffCommand; import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.StaffRepository; import org.mifosplatform.organisation.staff.exception.StaffNotFoundException; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; +import org.mifosplatform.organisation.staff.serialization.StaffCommandFromApiJsonDeserializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -25,72 +28,77 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements StaffWritePla private final static Logger logger = LoggerFactory.getLogger(StaffWritePlatformServiceJpaRepositoryImpl.class); private final PlatformSecurityContext context; + private final StaffCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final StaffRepository staffRepository; private final OfficeRepository officeRepository; - private final ConfigurationDomainService configurationDomainService; @Autowired - public StaffWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final StaffRepository staffRepository, - final OfficeRepository officeRepository, final ConfigurationDomainService configurationDomainService) { + public StaffWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, + final StaffCommandFromApiJsonDeserializer fromApiJsonDeserializer, final StaffRepository staffRepository, + final OfficeRepository officeRepository) { this.context = context; + this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.staffRepository = staffRepository; this.officeRepository = officeRepository; - this.configurationDomainService = configurationDomainService; } @Transactional @Override - public Long createStaff(final StaffCommand command) { + public EntityIdentifier createStaff(final JsonCommand command) { try { context.authenticatedUser(); - command.validateForCreate(); - final Office staffOffice = this.officeRepository.findOne(command.getOfficeId()); - if (staffOffice == null) { throw new OfficeNotFoundException(command.getOfficeId()); } + final StaffCommand staffCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); + staffCommand.validateForCreate(); - final Staff staff = Staff.createNew(staffOffice, command.getFirstname(), command.getLastname(), command.getIsLoanOfficer()); + final Long officeId = command.longValueOfParameterNamed("officeId"); + + final Office staffOffice = this.officeRepository.findOne(officeId); + if (staffOffice == null) { throw new OfficeNotFoundException(officeId); } + + final Staff staff = Staff.fromJson(staffOffice, command); this.staffRepository.save(staff); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_STAFF") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return staff.getId(); + return EntityIdentifier.resourceResult(staff.getId(), null); } catch (DataIntegrityViolationException dve) { handleStaffDataIntegrityIssues(command, dve); - return Long.valueOf(-1); + return EntityIdentifier.empty(); } } @Transactional @Override - public Long updateStaff(final StaffCommand command) { + public EntityIdentifier updateStaff(final Long staffId, final JsonCommand command) { try { context.authenticatedUser(); - command.validateForUpdate(); - final Long staffId = command.getId(); - Staff staff = this.staffRepository.findOne(staffId); - if (staff == null) { throw new StaffNotFoundException(staffId); } + final StaffCommand staffCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); + staffCommand.validateForUpdate(); - Office staffOffice = null; - Long officeId = command.getOfficeId(); - if (command.isOfficeChanged() && officeId != null) { - staffOffice = this.officeRepository.findOne(officeId); - if (staffOffice == null) { throw new OfficeNotFoundException(command.getOfficeId()); } + Staff staffForUpdate = this.staffRepository.findOne(staffId); + if (staffForUpdate == null) { throw new StaffNotFoundException(staffId); } + + final Map changesOnly = staffForUpdate.update(command); + + if (changesOnly.containsKey("officeId")) { + final Long officeId = (Long) changesOnly.get("officeId"); + final Office newOffice = this.officeRepository.findOne(officeId); + if (newOffice == null) { throw new OfficeNotFoundException(officeId); } + + staffForUpdate.changeOffice(newOffice); } - staff.update(command, staffOffice); + if (!changesOnly.isEmpty()) { + this.staffRepository.save(staffForUpdate); + } - this.staffRepository.save(staff); - - if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_STAFF") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return staff.getId(); + return EntityIdentifier.withChanges(staffForUpdate.getId(), changesOnly); } catch (DataIntegrityViolationException dve) { handleStaffDataIntegrityIssues(command, dve); - return Long.valueOf(-1); + return EntityIdentifier.empty(); } } @@ -98,12 +106,14 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements StaffWritePla * Guaranteed to throw an exception no matter what the data integrity issue * is. */ - private void handleStaffDataIntegrityIssues(final StaffCommand command, DataIntegrityViolationException dve) { + private void handleStaffDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { Throwable realCause = dve.getMostSpecificCause(); if (realCause.getMessage().contains("display_name")) { - String displayName = command.getLastname(); - if (!StringUtils.isBlank(command.getFirstname())) { - displayName = command.getLastname() + ", " + command.getFirstname(); + final String lastname = command.stringValueOfParameterNamed("lastname"); + String displayName = lastname; + if (!StringUtils.isBlank(displayName)) { + final String firstname = command.stringValueOfParameterNamed("firstname"); + displayName = lastname + ", " + firstname; } throw new PlatformDataIntegrityException("error.msg.staff.duplicate.displayName", "A staff with the given display name '" + displayName + "' already exists", "displayName", displayName); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/api/ChargesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/api/ChargesApiResource.java index 5b84add6f..66241ef2e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/api/ChargesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/api/ChargesApiResource.java @@ -3,7 +3,6 @@ package org.mifosplatform.portfolio.charge.api; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; @@ -25,7 +24,6 @@ import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSeriali import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.portfolio.charge.data.ChargeData; -import org.mifosplatform.portfolio.charge.serialization.ChargeDefinitionCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; @@ -46,17 +44,14 @@ public class ChargesApiResource { private final ChargeReadPlatformService readPlatformService; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; - private final ChargeDefinitionCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @Autowired public ChargesApiResource(final PlatformSecurityContext context, final ChargeReadPlatformService readPlatformService, - final ChargeDefinitionCommandFromApiJsonDeserializer fromApiJsonDeserializer, final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { this.context = context; this.readPlatformService = readPlatformService; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.toApiJsonSerializer = toApiJsonSerializer; this.apiRequestParameterHelper = apiRequestParameterHelper; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; @@ -113,13 +108,8 @@ public class ChargesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String createCharge(final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", "CREATE_CHARGE"); - context.authenticatedUser().validateHasPermissionTo("CREATE_CHARGE", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "charges", null, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_CHARGE", "CREATE", "charges", null, + apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } @@ -130,14 +120,8 @@ public class ChargesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updateCharge(@PathParam("chargeId") final Long chargeId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", "UPDATE_CHARGE"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CHARGE", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer - .serializedCommandJsonFromApiJson(chargeId, apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "charges", chargeId, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_CHARGE", "UPDATE", "charges", chargeId, + apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } @@ -148,10 +132,7 @@ public class ChargesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String deleteCharge(@PathParam("chargeId") final Long chargeId) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", "DELETE_CHARGE"); - context.authenticatedUser().validateHasPermissionTo("DELETE_CHARGE", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", "charges", chargeId, "{}"); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE_CHARGE", "DELETE", "charges", chargeId, "{}"); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/command/ChargeDefinitionCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/command/ChargeDefinitionCommand.java index 43d292dca..a61cda3a2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/command/ChargeDefinitionCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/command/ChargeDefinitionCommand.java @@ -3,7 +3,6 @@ package org.mifosplatform.portfolio.charge.command; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; -import java.util.Set; import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; @@ -23,30 +22,18 @@ public class ChargeDefinitionCommand { private final Boolean penalty; private final Boolean active; - private final transient Set parametersPassedInRequest; - private final transient boolean makerCheckerApproval; - private final transient Long id; - - public ChargeDefinitionCommand(final Set parametersPassedInRequest, final boolean makerCheckerApproval, final Long id, - final String name, final BigDecimal amount, final String currencyCode, final Integer chargeTimeType, + public ChargeDefinitionCommand(final String name, final BigDecimal amount, final String currencyCode, final Integer chargeTimeType, final Integer chargeAppliesTo, final Integer chargeCalculationType, final Boolean penalty, final Boolean active) { - this.makerCheckerApproval = makerCheckerApproval; - this.id = id; this.name = name; this.amount = amount; this.currencyCode = currencyCode; this.chargeTimeType = chargeTimeType; this.chargeAppliesTo = chargeAppliesTo; this.chargeCalculationType = chargeCalculationType; - this.parametersPassedInRequest = parametersPassedInRequest; this.penalty = penalty; this.active = active; } - public Long getId() { - return id; - } - public String getName() { return name; } @@ -55,10 +42,6 @@ public class ChargeDefinitionCommand { return amount; } - public Set getModifiedParameters() { - return parametersPassedInRequest; - } - public String getCurrencyCode() { return currencyCode; } @@ -87,42 +70,6 @@ public class ChargeDefinitionCommand { return active; } - public boolean isNameChanged() { - return this.parametersPassedInRequest.contains("name"); - } - - public boolean isAmountChanged() { - return this.parametersPassedInRequest.contains("amount"); - } - - public boolean isCurrencyCodeChanged() { - return this.parametersPassedInRequest.contains("currencyCode"); - } - - public boolean isChargeTimeTypeChanged() { - return this.parametersPassedInRequest.contains("chargeTimeType"); - } - - public boolean isChargeAppliesToChanged() { - return this.parametersPassedInRequest.contains("chargeAppliesTo"); - } - - public boolean isChargeCalculationTypeChanged() { - return this.parametersPassedInRequest.contains("chargeCalculationType"); - } - - public boolean isPenaltyChanged() { - return this.parametersPassedInRequest.contains("penalty"); - } - - public boolean isActiveChanged() { - return this.parametersPassedInRequest.contains("active"); - } - - public boolean isApprovedByChecker() { - return this.makerCheckerApproval; - } - public void validateForCreate() { List dataValidationErrors = new ArrayList(); @@ -148,10 +95,11 @@ public class ChargeDefinitionCommand { DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charge"); - baseDataValidator.reset().parameter("id").value(this.id).notNull(); baseDataValidator.reset().parameter("name").value(this.name).ignoreIfNull().notBlank().notExceedingLengthOf(100); baseDataValidator.reset().parameter("amount").value(this.amount).ignoreIfNull().positiveAmount(); baseDataValidator.reset().parameter("currencyCode").value(this.currencyCode).ignoreIfNull().notBlank(); + + // FIXME - kw - need to check if parameter exists in update and if so that its not null baseDataValidator.reset().parameter("chargeAppliesTo").value(this.chargeAppliesTo).ignoreIfNull().notNull().inMinMaxRange(1, 1); baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType).ignoreIfNull().notNull().inMinMaxRange(1, 2); baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculationType).ignoreIfNull().notNull() diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java index fd871e532..25d7fbd83 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/Charge.java @@ -1,11 +1,17 @@ package org.mifosplatform.portfolio.charge.domain; -import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; -import org.mifosplatform.portfolio.charge.command.ChargeDefinitionCommand; -import org.mifosplatform.useradministration.domain.AppUser; - -import javax.persistence.*; import java.math.BigDecimal; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; +import org.mifosplatform.useradministration.domain.AppUser; @Entity @Table(name = "m_charge", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "name") }) @@ -20,7 +26,6 @@ public class Charge extends AbstractAuditableCustom { @Column(name = "currency_code", length = 3) private String currencyCode; - @SuppressWarnings("unused") @Column(name = "charge_applies_to_enum", nullable = false) private Integer chargeAppliesTo; @@ -39,10 +44,21 @@ public class Charge extends AbstractAuditableCustom { @Column(name = "is_deleted", nullable = false) private boolean deleted = false; - public static Charge createNew(final String name, final BigDecimal amount, final String currencyCode, - final ChargeAppliesTo chargeAppliesTo, final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculationType, - final boolean penalty, final boolean active) { - return new Charge(name, amount, currencyCode, chargeAppliesTo, chargeTime, chargeCalculationType, penalty, active); + public static Charge fromJson(final JsonCommand command) { + + final String name = command.stringValueOfParameterNamed("name"); + final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount"); + final String currencyCode = command.stringValueOfParameterNamed("currencyCode"); + + final ChargeAppliesTo chargeAppliesTo = ChargeAppliesTo.fromInt(command.integerValueOfParameterNamed("chargeAppliesTo")); + final ChargeTimeType chargeTimeType = ChargeTimeType.fromInt(command.integerValueOfParameterNamed("chargeTimeType")); + final ChargeCalculationType chargeCalculationType = ChargeCalculationType.fromInt(command + .integerValueOfParameterNamed("chargeCalculationType")); + + final boolean penalty = command.booleanPrimitiveValueOfParameterNamed("penalty"); + final boolean active = command.booleanPrimitiveValueOfParameterNamed("active"); + + return new Charge(name, amount, currencyCode, chargeAppliesTo, chargeTimeType, chargeCalculationType, penalty, active); } protected Charge() { @@ -93,34 +109,73 @@ public class Charge extends AbstractAuditableCustom { return deleted; } - public void update(final ChargeDefinitionCommand command) { - if (command.isNameChanged()) { - this.name = command.getName(); + public Map update(final JsonCommand command) { + + final Map actualChanges = new LinkedHashMap(7); + + final String localeAsInput = command.locale(); + + final String nameParamName = "name"; + if (command.isChangeInStringParameterNamed(nameParamName, this.name)) { + final String newValue = command.stringValueOfParameterNamed(nameParamName); + actualChanges.put(nameParamName, newValue); + this.name = newValue; } - if (command.isAmountChanged()) { - this.amount = command.getAmount(); + final String currencyCodeParamName = "currencyCode"; + if (command.isChangeInStringParameterNamed(currencyCodeParamName, this.currencyCode)) { + final String newValue = command.stringValueOfParameterNamed(currencyCodeParamName); + actualChanges.put(currencyCodeParamName, newValue); + this.currencyCode = newValue; } - if (command.isCurrencyCodeChanged()) { - this.currencyCode = command.getCurrencyCode(); + final String amountParamName = "amount"; + if (command.isChangeInBigDecimalParameterNamed(amountParamName, this.amount)) { + final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountParamName); + actualChanges.put(amountParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.amount = newValue; } - if (command.isChargeTimeTypeChanged()) { - this.chargeTime = ChargeTimeType.fromInt(command.getChargeTimeType()).getValue(); + final String chargeTimeParamName = "chargeTime"; + if (command.isChangeInIntegerParameterNamed(chargeTimeParamName, this.chargeTime)) { + final Integer newValue = command.integerValueOfParameterNamed(chargeTimeParamName); + actualChanges.put(chargeTimeParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.chargeTime = ChargeTimeType.fromInt(newValue).getValue(); } - if (command.isChargeAppliesToChanged()) { - this.chargeAppliesTo = ChargeAppliesTo.fromInt(command.getChargeAppliesTo()).getValue(); + final String chargeAppliesToParamName = "chargeAppliesTo"; + if (command.isChangeInIntegerParameterNamed(chargeAppliesToParamName, this.chargeAppliesTo)) { + final Integer newValue = command.integerValueOfParameterNamed(chargeAppliesToParamName); + actualChanges.put(chargeAppliesToParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.chargeAppliesTo = ChargeAppliesTo.fromInt(newValue).getValue(); } - if (command.isChargeCalculationTypeChanged()) { - this.chargeCalculation = ChargeCalculationType.fromInt(command.getChargeCalculationType()).getValue(); + final String chargeCalculationParamName = "chargeCalculation"; + if (command.isChangeInIntegerParameterNamed(chargeCalculationParamName, this.chargeCalculation)) { + final Integer newValue = command.integerValueOfParameterNamed(chargeCalculationParamName); + actualChanges.put(chargeCalculationParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.chargeCalculation = ChargeCalculationType.fromInt(newValue).getValue(); } - if (command.isActiveChanged()) { - this.active = command.isActive(); + final String penaltyParamName = "penalty"; + if (command.isChangeInBooleanParameterNamed(penaltyParamName, this.penalty)) { + final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(penaltyParamName); + actualChanges.put(penaltyParamName, newValue); + this.penalty = newValue; } + + final String activeParamName = "active"; + if (command.isChangeInBooleanParameterNamed(activeParamName, this.active)) { + final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(activeParamName); + actualChanges.put(activeParamName, newValue); + this.active = newValue; + } + + return actualChanges; } /** diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/handler/CreateChargeDefinitionCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/handler/CreateChargeDefinitionCommandHandler.java new file mode 100644 index 000000000..2d41f75aa --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/handler/CreateChargeDefinitionCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.charge.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.charge.service.ChargeWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateChargeDefinitionCommandHandler implements NewCommandSourceHandler { + + private final ChargeWritePlatformService clientWritePlatformService; + + @Autowired + public CreateChargeDefinitionCommandHandler(final ChargeWritePlatformService clientWritePlatformService) { + this.clientWritePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.clientWritePlatformService.createCharge(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/handler/DeleteChargeDefinitionCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/handler/DeleteChargeDefinitionCommandHandler.java new file mode 100644 index 000000000..7679a4026 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/handler/DeleteChargeDefinitionCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.charge.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.charge.service.ChargeWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class DeleteChargeDefinitionCommandHandler implements NewCommandSourceHandler { + + private final ChargeWritePlatformService clientWritePlatformService; + + @Autowired + public DeleteChargeDefinitionCommandHandler(final ChargeWritePlatformService clientWritePlatformService) { + this.clientWritePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.clientWritePlatformService.deleteCharge(command.resourceId()); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/handler/UpdateChargeDefinitionCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/handler/UpdateChargeDefinitionCommandHandler.java new file mode 100644 index 000000000..c53109b38 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/handler/UpdateChargeDefinitionCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.charge.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.charge.service.ChargeWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateChargeDefinitionCommandHandler implements NewCommandSourceHandler { + + private final ChargeWritePlatformService clientWritePlatformService; + + @Autowired + public UpdateChargeDefinitionCommandHandler(final ChargeWritePlatformService clientWritePlatformService) { + this.clientWritePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.clientWritePlatformService.updateCharge(command.resourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeCommandFromCommandJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeCommandFromCommandJsonDeserializer.java deleted file mode 100644 index 59a61a484..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeCommandFromCommandJsonDeserializer.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.mifosplatform.portfolio.charge.serialization; - -import java.math.BigDecimal; -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.serialization.FromCommandJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.portfolio.charge.command.ChargeDefinitionCommand; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.google.gson.JsonElement; - -@Component -public final class ChargeCommandFromCommandJsonDeserializer implements FromCommandJsonDeserializer { - - private final FromJsonHelper fromJsonHelper; - - @Autowired - public ChargeCommandFromCommandJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { - this.fromJsonHelper = fromApiJsonHelper; - } - - @Override - public ChargeDefinitionCommand commandFromCommandJson(final String commandAsJson) { - return commandFromCommandJson(null, commandAsJson); - } - - @Override - public ChargeDefinitionCommand commandFromCommandJson(final Long chargeDefinitionId, final String commandAsJson) { - return commandFromCommandJson(chargeDefinitionId, commandAsJson, false); - } - - @Override - public ChargeDefinitionCommand commandFromCommandJson(final Long chargeDefinitionId, final String commandAsJson, - final boolean makerCheckerApproval) { - if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); } - - final Set parametersPassedInRequest = new HashSet(); - - final JsonElement element = fromJsonHelper.parse(commandAsJson); - - final String name = fromJsonHelper.extractStringNamed("name", element, parametersPassedInRequest); - final String currencyCode = fromJsonHelper.extractStringNamed("currencyCode", element, parametersPassedInRequest); - final BigDecimal amount = fromJsonHelper.extractBigDecimalNamed("amount", element.getAsJsonObject(), parametersPassedInRequest); - final Integer chargeTimeType = fromJsonHelper.extractIntegerNamed("chargeTimeType", element, parametersPassedInRequest); - final Integer chargeAppliesTo = fromJsonHelper.extractIntegerNamed("chargeAppliesTo", element, parametersPassedInRequest); - final Integer chargeCalculationType = fromJsonHelper.extractIntegerNamed("chargeCalculationType", element, - parametersPassedInRequest); - final Boolean penalty = fromJsonHelper.extractBooleanNamed("penalty", element, parametersPassedInRequest); - final Boolean active = fromJsonHelper.extractBooleanNamed("active", element, parametersPassedInRequest); - - return new ChargeDefinitionCommand(parametersPassedInRequest, makerCheckerApproval, chargeDefinitionId, name, amount, currencyCode, - chargeTimeType, chargeAppliesTo, chargeCalculationType, penalty, active); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java index 797bf2824..3bc9881aa 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/serialization/ChargeDefinitionCommandFromApiJsonDeserializer.java @@ -7,7 +7,9 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; +import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.portfolio.charge.command.ChargeDefinitionCommand; @@ -22,7 +24,7 @@ import com.google.gson.reflect.TypeToken; * Implementation of {@link FromApiJsonDeserializer} for {@link FundCommand}'s. */ @Component -public final class ChargeDefinitionCommandFromApiJsonDeserializer implements FromApiJsonDeserializer { +public final class ChargeDefinitionCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer { /** * The parameters supported for this command. @@ -32,59 +34,33 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer implements Fro "active")); private final FromJsonHelper fromApiJsonHelper; - private final CommandSerializer commandSerializerService; @Autowired - public ChargeDefinitionCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, - final CommandSerializer commandSerializerService) { + public ChargeDefinitionCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; - this.commandSerializerService = commandSerializerService; } @Override public ChargeDefinitionCommand commandFromApiJson(final String json) { - return commandFromApiJson(null, json); - } - - @Override - public ChargeDefinitionCommand commandFromApiJson(final Long chargeId, final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final Set parametersPassedInRequest = new HashSet(); - final JsonElement element = fromApiJsonHelper.parse(json); - final String name = fromApiJsonHelper.extractStringNamed("name", element, parametersPassedInRequest); - final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element, parametersPassedInRequest); - final BigDecimal amount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("amount", element.getAsJsonObject(), - parametersPassedInRequest); + final String name = fromApiJsonHelper.extractStringNamed("name", element); + final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element); + final BigDecimal amount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("amount", element.getAsJsonObject()); - final Integer chargeTimeType = fromApiJsonHelper - .extractIntegerWithLocaleNamed("chargeTimeType", element, parametersPassedInRequest); - final Integer chargeAppliesTo = fromApiJsonHelper.extractIntegerWithLocaleNamed("chargeAppliesTo", element, - parametersPassedInRequest); - final Integer chargeCalculationType = fromApiJsonHelper.extractIntegerWithLocaleNamed("chargeCalculationType", element, - parametersPassedInRequest); + final Integer chargeTimeType = fromApiJsonHelper.extractIntegerWithLocaleNamed("chargeTimeType", element); + final Integer chargeAppliesTo = fromApiJsonHelper.extractIntegerWithLocaleNamed("chargeAppliesTo", element); + final Integer chargeCalculationType = fromApiJsonHelper.extractIntegerWithLocaleNamed("chargeCalculationType", element); - final Boolean penalty = fromApiJsonHelper.extractBooleanNamed("penalty", element, parametersPassedInRequest); - final Boolean active = fromApiJsonHelper.extractBooleanNamed("active", element, parametersPassedInRequest); + final Boolean penalty = fromApiJsonHelper.extractBooleanNamed("penalty", element); + final Boolean active = fromApiJsonHelper.extractBooleanNamed("active", element); - return new ChargeDefinitionCommand(parametersPassedInRequest, false, chargeId, name, amount, currencyCode, chargeTimeType, - chargeAppliesTo, chargeCalculationType, penalty, active); - } - - @Override - public String serializedCommandJsonFromApiJson(final String json) { - final ChargeDefinitionCommand command = commandFromApiJson(json); - return this.commandSerializerService.serializeCommandToJson(command); - } - - @Override - public String serializedCommandJsonFromApiJson(final Long roleId, final String json) { - final ChargeDefinitionCommand command = commandFromApiJson(roleId, json); - return this.commandSerializerService.serializeCommandToJson(command); + return new ChargeDefinitionCommand(name, amount, currencyCode, chargeTimeType, chargeAppliesTo, chargeCalculationType, penalty, + active); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformService.java index c8787727b..2b1220bec 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformService.java @@ -1,12 +1,13 @@ package org.mifosplatform.portfolio.charge.service; -import org.mifosplatform.portfolio.charge.command.ChargeDefinitionCommand; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; public interface ChargeWritePlatformService { - Long createCharge(ChargeDefinitionCommand command); + EntityIdentifier createCharge(JsonCommand command); - Long updateCharge(ChargeDefinitionCommand command); + EntityIdentifier updateCharge(Long chargeId, JsonCommand command); - Long deleteCharge(ChargeDefinitionCommand command); + EntityIdentifier deleteCharge(Long chargeId); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java index eda59d347..714d34a43 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java @@ -1,16 +1,16 @@ package org.mifosplatform.portfolio.charge.service; +import java.util.Map; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; import org.mifosplatform.portfolio.charge.command.ChargeDefinitionCommand; import org.mifosplatform.portfolio.charge.domain.Charge; -import org.mifosplatform.portfolio.charge.domain.ChargeAppliesTo; -import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType; import org.mifosplatform.portfolio.charge.domain.ChargeRepository; -import org.mifosplatform.portfolio.charge.domain.ChargeTimeType; import org.mifosplatform.portfolio.charge.exception.ChargeNotFoundException; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; +import org.mifosplatform.portfolio.charge.serialization.ChargeDefinitionCommandFromApiJsonDeserializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -24,73 +24,69 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWriteP private final static Logger logger = LoggerFactory.getLogger(ChargeWritePlatformServiceJpaRepositoryImpl.class); private final PlatformSecurityContext context; + private final ChargeDefinitionCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final ChargeRepository chargeRepository; - private final ConfigurationDomainService configurationDomainService; @Autowired - public ChargeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ChargeRepository chargeRepository, final ConfigurationDomainService configurationDomainService) { + public ChargeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, + final ChargeDefinitionCommandFromApiJsonDeserializer fromApiJsonDeserializer, + final ChargeRepository chargeRepository) { this.context = context; + this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.chargeRepository = chargeRepository; - this.configurationDomainService = configurationDomainService; } @Transactional @Override - public Long createCharge(final ChargeDefinitionCommand command) { + public EntityIdentifier createCharge(final JsonCommand command) { try { this.context.authenticatedUser(); - command.validateForCreate(); - - final ChargeAppliesTo chargeAppliesTo = ChargeAppliesTo.fromInt(command.getChargeAppliesTo()); - final ChargeTimeType chargeTimeType = ChargeTimeType.fromInt(command.getChargeTimeType()); - final ChargeCalculationType chargeCalculationType = ChargeCalculationType.fromInt(command.getChargeCalculationType()); - - final Charge charge = Charge.createNew(command.getName(), command.getAmount(), command.getCurrencyCode(), chargeAppliesTo, - chargeTimeType, chargeCalculationType, command.isPenalty(), command.isActive()); + + final ChargeDefinitionCommand chargeDefinitionCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); + chargeDefinitionCommand.validateForCreate(); + final Charge charge = Charge.fromJson(command); this.chargeRepository.save(charge); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_CHARGE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return charge.getId(); + return EntityIdentifier.resourceResult(charge.getId(), null); } catch (DataIntegrityViolationException dve) { handleDataIntegrityIssues(command, dve); - return Long.valueOf(-1); + return EntityIdentifier.empty(); } } @Transactional @Override - public Long updateCharge(final ChargeDefinitionCommand command) { + public EntityIdentifier updateCharge(final Long chargeId, final JsonCommand command) { try { this.context.authenticatedUser(); - command.validateForUpdate(); + + final ChargeDefinitionCommand chargeDefinitionCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); + chargeDefinitionCommand.validateForUpdate(); - final Long chargeId = command.getId(); final Charge chargeForUpdate = this.chargeRepository.findOne(chargeId); if (chargeForUpdate == null) { throw new ChargeNotFoundException(chargeId); } - chargeForUpdate.update(command); + final Map changes = chargeForUpdate.update(command); - this.chargeRepository.save(chargeForUpdate); + if (!changes.isEmpty()) { + this.chargeRepository.save(chargeForUpdate); + } - if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_CHARGE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return chargeForUpdate.getId(); + return EntityIdentifier.withChanges(chargeForUpdate.getId(), changes); } catch (DataIntegrityViolationException dve) { handleDataIntegrityIssues(command, dve); - return Long.valueOf(-1); + return EntityIdentifier.empty(); } } @Transactional @Override - public Long deleteCharge(final ChargeDefinitionCommand command) { + public EntityIdentifier deleteCharge(final Long chargeId) { this.context.authenticatedUser(); - final Long chargeId = command.getId(); final Charge chargeForDelete = this.chargeRepository.findOne(chargeId); if (chargeForDelete == null || chargeForDelete.isDeleted()) { throw new ChargeNotFoundException(chargeId); } @@ -98,20 +94,20 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWriteP chargeRepository.save(chargeForDelete); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("DELETE_CHARGE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return chargeForDelete.getId(); + return EntityIdentifier.resourceResult(chargeForDelete.getId(), null); } /* * Guaranteed to throw an exception no matter what the data integrity issue * is. */ - private void handleDataIntegrityIssues(final ChargeDefinitionCommand command, final DataIntegrityViolationException dve) { + private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { Throwable realCause = dve.getMostSpecificCause(); - if (realCause.getMessage().contains("name")) { throw new PlatformDataIntegrityException("error.msg.charge.duplicate.name", - "Charge with name {0} already exists", "name", command.getName()); } + if (realCause.getMessage().contains("name")) { + final String name = command.stringValueOfParameterNamed("name"); + throw new PlatformDataIntegrityException("error.msg.charge.duplicate.name", + "Charge with name `" + name +"` already exists", "name", name); } logger.error(dve.getMessage(), dve); throw new PlatformDataIntegrityException("error.msg.charge.unknown.data.integrity.issue", diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientIdentifiersApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientIdentifiersApiResource.java index f4090e81e..390b59337 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientIdentifiersApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientIdentifiersApiResource.java @@ -3,7 +3,6 @@ package org.mifosplatform.portfolio.client.api; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; @@ -29,7 +28,6 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext import org.mifosplatform.portfolio.client.data.ClientData; import org.mifosplatform.portfolio.client.data.ClientIdentifierData; import org.mifosplatform.portfolio.client.exception.DuplicateClientIdentifierException; -import org.mifosplatform.portfolio.client.serialization.ClientIdentifierCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.client.service.ClientReadPlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; @@ -48,7 +46,6 @@ public class ClientIdentifiersApiResource { private final PlatformSecurityContext context; private final ClientReadPlatformService clientReadPlatformService; private final CodeValueReadPlatformService codeValueReadPlatformService; - private final ClientIdentifierCommandFromApiJsonDeserializer commandFromApiJsonDeserializer; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @@ -56,14 +53,12 @@ public class ClientIdentifiersApiResource { @Autowired public ClientIdentifiersApiResource(final PlatformSecurityContext context, final ClientReadPlatformService readPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService, - final ClientIdentifierCommandFromApiJsonDeserializer commandFromApiJsonDeserializer, final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { this.context = context; this.clientReadPlatformService = readPlatformService; this.codeValueReadPlatformService = codeValueReadPlatformService; - this.commandFromApiJsonDeserializer = commandFromApiJsonDeserializer; this.toApiJsonSerializer = toApiJsonSerializer; this.apiRequestParameterHelper = apiRequestParameterHelper; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; @@ -103,16 +98,8 @@ public class ClientIdentifiersApiResource { public String createClientIdentifier(@PathParam("clientId") final Long clientId, final String apiRequestBodyAsJson) { try { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", - "CREATE_CLIENTIDENTIFIER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_CLIENTIDENTIFIER", allowedPermissions); - - final String commandSerializedAsJson = this.commandFromApiJsonDeserializer.serializedCommandJsonFromApiJsonWithSubResource( - apiRequestBodyAsJson, clientId); - - final String resourceUrl = "clients/" + clientId + "/identifiers"; - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", resourceUrl, null, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_CLIENTIDENTIFIER", "CREATE", + "clients", clientId, "identifiers", null, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } catch (DuplicateClientIdentifierException e) { @@ -156,16 +143,8 @@ public class ClientIdentifiersApiResource { @PathParam("identifierId") final Long clientIdentifierId, final String apiRequestBodyAsJson) { try { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", - "UPDATE_CLIENTIDENTIFIER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CLIENTIDENTIFIER", allowedPermissions); - - final String commandSerializedAsJson = this.commandFromApiJsonDeserializer.serializedCommandJsonFromApiJsonWithSubResource( - clientIdentifierId, apiRequestBodyAsJson, clientId); - - final String resourceUrl = "clients/" + clientId + "/identifiers"; - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", resourceUrl, - clientIdentifierId, commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_CLIENTIDENTIFIER", "UPDATE", + "clients", clientId, "identifiers", clientIdentifierId, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } catch (DuplicateClientIdentifierException e) { @@ -187,13 +166,8 @@ public class ClientIdentifiersApiResource { public String deleteClientIdentifier(@PathParam("clientId") final Long clientId, @PathParam("identifierId") final Long clientIdentifierId) { - final List allowedPermissions = Arrays - .asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", "DELETE_CLIENTIDENTIFIER"); - context.authenticatedUser().validateHasPermissionTo("DELETE_CLIENTIDENTIFIER", allowedPermissions); - - final String resourceUrl = "clients/" + clientId + "/identifiers"; - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", resourceUrl, clientIdentifierId, - "{}"); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE_CLIENTIDENTIFIER", "DELETE", + "clients", clientId, "identifiers", clientIdentifierId, "{}"); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientNotesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientNotesApiResource.java index 84271252a..32fced258 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientNotesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientNotesApiResource.java @@ -3,7 +3,6 @@ package org.mifosplatform.portfolio.client.api; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; @@ -24,7 +23,6 @@ import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSeriali import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.portfolio.client.data.NoteData; -import org.mifosplatform.portfolio.client.serialization.ClientNoteCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.client.service.ClientReadPlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; @@ -40,19 +38,16 @@ public class ClientNotesApiResource { private final PlatformSecurityContext context; private final ClientReadPlatformService clientReadPlatformService; - private final ClientNoteCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @Autowired public ClientNotesApiResource(final PlatformSecurityContext context, final ClientReadPlatformService readPlatformService, - final ClientNoteCommandFromApiJsonDeserializer fromApiJsonDeserializer, final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { this.context = context; this.clientReadPlatformService = readPlatformService; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.toApiJsonSerializer = toApiJsonSerializer; this.apiRequestParameterHelper = apiRequestParameterHelper; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; @@ -76,14 +71,8 @@ public class ClientNotesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String addNewClientNote(@PathParam("clientId") final Long clientId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", "CREATE_CLIENTNOTE"); - context.authenticatedUser().validateHasPermissionTo("CREATE_CLIENTNOTE", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJsonWithSubResource(apiRequestBodyAsJson, clientId); - - final String resourceUrl = "clients/" + clientId + "/notes"; - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", resourceUrl, null, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_CLIENTNOTE", "CREATE", + "clients", clientId, "notes", null, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } @@ -110,14 +99,8 @@ public class ClientNotesApiResource { public String updateClientNote(@PathParam("clientId") final Long clientId, @PathParam("noteId") final Long noteId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", "UPDATE_CLIENTNOTE"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CLIENTNOTE", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJsonWithSubResource(noteId, apiRequestBodyAsJson, clientId); - - final String resourceUrl = "clients/" + clientId + "/notes"; - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", resourceUrl, noteId, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_CLIENTNOTE", "UPDATE", + "clients", clientId, "notes", noteId, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java index bd1a4bbf3..dbd58a32d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java @@ -213,10 +213,7 @@ public class ClientsApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String createClient(final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", "CREATE_CLIENT"); - context.authenticatedUser().validateHasPermissionTo("CREATE_CLIENT", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "clients", null, + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_CLIENT", "CREATE", "clients", null, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); @@ -228,10 +225,7 @@ public class ClientsApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updateClient(@PathParam("clientId") final Long clientId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", "UPDATE_CLIENT"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_CLIENT", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "clients", clientId, + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_CLIENT", "UPDATE", "clients", clientId, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); @@ -243,10 +237,7 @@ public class ClientsApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String deleteClient(@PathParam("clientId") final Long clientId) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", "DELETE_CLIENT"); - context.authenticatedUser().validateHasPermissionTo("DELETE_CLIENT", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", "clients", clientId, "{}"); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE_CLIENT", "DELETE", "clients", clientId, "{}"); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/command/ClientIdentifierCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/command/ClientIdentifierCommand.java index bb83dd159..4d8211365 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/command/ClientIdentifierCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/command/ClientIdentifierCommand.java @@ -1,42 +1,27 @@ package org.mifosplatform.portfolio.client.command; -import java.util.Set; +import java.util.ArrayList; +import java.util.List; + +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; /** * Immutable command for creating or updating details of a client identifier. */ public class ClientIdentifierCommand { - - private final Long clientId; private final Long documentTypeId; - private final String documentKey; private final String description; - private final transient Set modifiedParameters; - private final transient boolean makerCheckerApproval; - private final transient Long id; - - public static ClientIdentifierCommand clientSubResource(final ClientIdentifierCommand command, final Long providedClientId) { - return new ClientIdentifierCommand(command.modifiedParameters, command.makerCheckerApproval, command.id, providedClientId, command.documentTypeId, command.documentKey, command.description); - } - - public ClientIdentifierCommand(final Set modifiedParameters, final boolean makerCheckerApproval, final Long id, final Long clientId, final Long documentTypeId, - final String documentKey, final String description) { - this.modifiedParameters = modifiedParameters; - this.makerCheckerApproval = makerCheckerApproval; - this.id = id; - this.clientId = clientId; + public ClientIdentifierCommand(final Long documentTypeId, final String documentKey, final String description) { this.documentTypeId = documentTypeId; this.documentKey = documentKey; this.description = description; } - public Long getId() { - return id; - } - public Long getDocumentTypeId() { return documentTypeId; } @@ -49,27 +34,33 @@ public class ClientIdentifierCommand { return description; } - public Set getModifiedParameters() { - return modifiedParameters; - } + public void validateForCreate() { + List dataValidationErrors = new ArrayList(); - public Long getClientId() { - return clientId; - } + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("clientIdentifier"); - public boolean isDocumentTypeChanged() { - return this.modifiedParameters.contains("documentTypeId"); - } + baseDataValidator.reset().parameter("documentTypeId").value(this.documentTypeId).notNull().integerGreaterThanZero(); + baseDataValidator.reset().parameter("documentKey").value(this.documentKey).notBlank(); - public boolean isDocumentKeyChanged() { - return this.modifiedParameters.contains("documentKey"); + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } } + + public void validateForUpdate() { + List dataValidationErrors = new ArrayList(); - public boolean isDescriptionChanged() { - return this.modifiedParameters.contains("description"); - } + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("clientIdentifier"); - public boolean isApprovedByChecker() { - return this.makerCheckerApproval; + baseDataValidator.reset().parameter("documentKey").value(this.documentKey).ignoreIfNull().notBlank(); + + // FIXME - kw +// if (command.isDocumentTypeChanged()) { +// baseDataValidator.reset().parameter("documentTypeId").value(command.getDocumentTypeId()).notNull().integerGreaterThanZero(); +// } + + baseDataValidator.reset().anyOfNotNull(this.documentTypeId, this.documentKey); + + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/command/ClientIdentifierCommandValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/command/ClientIdentifierCommandValidator.java deleted file mode 100644 index 77acefbd3..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/command/ClientIdentifierCommandValidator.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.mifosplatform.portfolio.client.command; - -import java.util.ArrayList; -import java.util.List; - -import org.mifosplatform.infrastructure.core.data.ApiParameterError; -import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; -import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; - -public class ClientIdentifierCommandValidator { - - private final ClientIdentifierCommand command; - - public ClientIdentifierCommandValidator(ClientIdentifierCommand command) { - this.command = command; - } - - public void validateForUpdate() { - List dataValidationErrors = new ArrayList(); - - DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("clientIdentifier"); - - baseDataValidator.reset().parameter("documentKey").value(command.getDocumentKey()).ignoreIfNull().notBlank(); - - if (command.isDocumentTypeChanged()) { - baseDataValidator.reset().parameter("documentTypeId").value(command.getDocumentTypeId()).notNull().integerGreaterThanZero(); - } - - baseDataValidator.reset().anyOfNotNull(command.getDocumentTypeId(), command.getDocumentKey()); - - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); } - } - - public void validateForCreate() { - List dataValidationErrors = new ArrayList(); - - DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("clientIdentifier"); - - baseDataValidator.reset().parameter("documentTypeId").value(command.getDocumentTypeId()).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter("clientId").value(command.getClientId()).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter("documentKey").value(command.getDocumentKey()).notBlank(); - - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); } - } -} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/command/ClientNoteCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/command/ClientNoteCommand.java index 5dc49daaf..55c5863c1 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/command/ClientNoteCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/command/ClientNoteCommand.java @@ -1,40 +1,16 @@ package org.mifosplatform.portfolio.client.command; -import java.util.Set; - /** * Immutable command used for create or update of notes. */ public class ClientNoteCommand { - private final Long clientId; private final String note; - private final transient Long id; - private final transient Set parametersPassedInRequest; - private final transient boolean makerCheckerApproval; - - public static ClientNoteCommand clientSubResource(final ClientNoteCommand command, final Long providedClientId) { - return new ClientNoteCommand(command.parametersPassedInRequest, command.makerCheckerApproval, command.id, providedClientId, command.note); - } - - public ClientNoteCommand(final Set parametersPassedInRequest, final boolean makerCheckerApproval, final Long id, Long clientId, - final String note) { - this.parametersPassedInRequest = parametersPassedInRequest; - this.makerCheckerApproval = makerCheckerApproval; - this.id = id; - this.clientId = clientId; + public ClientNoteCommand(final String note) { this.note = note; } - public Long getId() { - return id; - } - - public Long getClientId() { - return clientId; - } - public String getNote() { return note; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java index 9102bf3c6..78223890e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java @@ -134,6 +134,17 @@ public class Client extends AbstractAuditableCustom { final LocalDate newValue = command.localDateValueOfParameterNamed(joiningDateParamName); this.joinedDate = newValue.toDate(); } + + final String clientOrBusinessNameParamName = "clientOrBusinessName"; + final String lastnameParamName = "lastname"; + if (command.isChangeInStringParameterNamed(lastnameParamName, getLastnameIfNotClientOrBusinessName())) { + final String newValue = command.stringValueOfParameterNamed(lastnameParamName); + actualChanges.put(lastnameParamName, newValue); + if (StringUtils.isNotBlank(getClientOrBusinessName())) { + actualChanges.put(clientOrBusinessNameParamName, ""); + } + this.lastName = newValue; + } final String firstnameParamName = "firstname"; if (command.isChangeInStringParameterNamed(firstnameParamName, this.firstName)) { @@ -142,14 +153,7 @@ public class Client extends AbstractAuditableCustom { this.firstName = newValue; } - final String lastnameParamName = "lastname"; - if (command.isChangeInStringParameterNamed(lastnameParamName, this.lastName)) { - final String newValue = command.stringValueOfParameterNamed(lastnameParamName); - actualChanges.put(lastnameParamName, newValue); - this.lastName = newValue; - } - final String clientOrBusinessNameParamName = "clientOrBusinessName"; if (command.isChangeInStringParameterNamed(clientOrBusinessNameParamName, getClientOrBusinessName())) { final String newValue = command.stringValueOfParameterNamed(clientOrBusinessNameParamName); actualChanges.put(clientOrBusinessNameParamName, newValue); @@ -183,6 +187,18 @@ public class Client extends AbstractAuditableCustom { } return joiningLocalDate; } + + /* + * + */ + private String getLastnameIfNotClientOrBusinessName() { + String lastname = null; + if (StringUtils.isNotBlank(this.firstName) && StringUtils.isNotBlank(this.lastName)) { + lastname = this.lastName; + } + return lastname; + } + private String getClientOrBusinessName() { String clientOrBusinessName = null; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientIdentifier.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientIdentifier.java index 6f5011f35..90b14d874 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientIdentifier.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientIdentifier.java @@ -1,5 +1,8 @@ package org.mifosplatform.portfolio.client.domain; +import java.util.LinkedHashMap; +import java.util.Map; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.JoinColumn; @@ -9,8 +12,8 @@ import javax.persistence.UniqueConstraint; import org.apache.commons.lang.StringUtils; import org.mifosplatform.infrastructure.codes.domain.CodeValue; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; -import org.mifosplatform.portfolio.client.command.ClientIdentifierCommand; import org.mifosplatform.useradministration.domain.AppUser; @Entity @@ -19,6 +22,7 @@ import org.mifosplatform.useradministration.domain.AppUser; @UniqueConstraint(columnNames = { "client_id", "document_type_id" }, name = "unique_client_identifier") }) public class ClientIdentifier extends AbstractAuditableCustom { + @SuppressWarnings("unused") @ManyToOne @JoinColumn(name = "client_id", nullable = false) private Client client; @@ -33,16 +37,14 @@ public class ClientIdentifier extends AbstractAuditableCustom { @Column(name = "description", length = 1000) private String description; - public ClientIdentifier() { - this.client = null; - this.documentType = null; - this.documentKey = null; - this.description = null; + public static ClientIdentifier fromJson(final Client client, final CodeValue documentType, final JsonCommand command) { + final String documentKey = command.stringValueOfParameterNamed("documentKey"); + final String description = command.stringValueOfParameterNamed("description"); + return new ClientIdentifier(client, documentType, documentKey, description); } - public static ClientIdentifier createNew(final Client client, final CodeValue documentType, final String documentKey, - final String description) { - return new ClientIdentifier(client, documentType, documentKey, description); + protected ClientIdentifier() { + // } private ClientIdentifier(final Client client, final CodeValue documentType, final String documentKey, final String description) { @@ -52,34 +54,42 @@ public class ClientIdentifier extends AbstractAuditableCustom { this.description = StringUtils.defaultIfEmpty(description, null); } - public void update(final ClientIdentifierCommand command, final CodeValue documentType) { + public void update(final CodeValue documentType) { + this.documentType = documentType; + } - if (command.isDocumentTypeChanged()) { - this.documentType = documentType; + public Map update(final JsonCommand command) { + + final Map actualChanges = new LinkedHashMap(7); + + final String documentTypeIdParamName = "documentTypeId"; + if (command.isChangeInLongParameterNamed(documentTypeIdParamName, this.documentType.getId())) { + final Long newValue = command.longValueOfParameterNamed(documentTypeIdParamName); + actualChanges.put(documentTypeIdParamName, newValue); } - if (command.isDocumentKeyChanged()) { - this.documentKey = StringUtils.defaultIfEmpty(command.getDocumentKey(), null); + final String documentKeyParamName = "documentKey"; + if (command.isChangeInStringParameterNamed(documentKeyParamName, this.documentKey)) { + final String newValue = command.stringValueOfParameterNamed(documentKeyParamName); + actualChanges.put(documentKeyParamName, newValue); + this.documentKey = StringUtils.defaultIfEmpty(newValue, null); } - if (command.isDescriptionChanged()) { - this.description = StringUtils.defaultIfEmpty(command.getDescription(), null); + final String descriptionParamName = "description"; + if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) { + final String newValue = command.stringValueOfParameterNamed(descriptionParamName); + actualChanges.put(descriptionParamName, newValue); + this.description = StringUtils.defaultIfEmpty(newValue, null); } + + return actualChanges; } - public Client getClient() { - return client; + public String documentKey() { + return this.documentKey; } - public CodeValue getDocumentType() { - return documentType; - } - - public String getDocumentKey() { - return documentKey; - } - - public String getDescription() { - return description; + public Long documentTypeId() { + return this.documentType.getId(); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Note.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Note.java index 3589e8e0a..ab0ae9544 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Note.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Note.java @@ -1,11 +1,16 @@ package org.mifosplatform.portfolio.client.domain; +import java.util.LinkedHashMap; +import java.util.Map; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; import org.mifosplatform.portfolio.loanaccount.domain.Loan; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction; @@ -30,7 +35,6 @@ public class Note extends AbstractAuditableCustom { @JoinColumn(name = "loan_transaction_id", nullable = true) private LoanTransaction loanTransaction; - @SuppressWarnings("unused") @Column(name = "note", length = 1000) private String note; @@ -75,7 +79,8 @@ public class Note extends AbstractAuditableCustom { } } - public static Note clientNote(final Client client, final String note) { + public static Note clientNoteFromJson(final Client client, final JsonCommand command) { + final String note = command.stringValueOfParameterNamed("note"); return new Note(client, note); } @@ -86,7 +91,7 @@ public class Note extends AbstractAuditableCustom { public static Note loanTransactionNote(final Loan loan, final LoanTransaction loanTransaction, final String note) { return new Note(loan, loanTransaction, note); } - + public static Note depositNote(final DepositAccount account, final String noteText) { return new Note(account, noteText); } @@ -127,8 +132,16 @@ public class Note extends AbstractAuditableCustom { this.noteTypeId = NoteType.DEPOSIT.getValue(); } - public void update(final String note) { - this.note = note; + public Map update(final JsonCommand command) { + final Map actualChanges = new LinkedHashMap(7); + + final String noteParamName = "note"; + if (command.isChangeInStringParameterNamed(noteParamName, this.note)) { + final String newValue = command.stringValueOfParameterNamed(noteParamName); + actualChanges.put(noteParamName, newValue); + this.note = StringUtils.defaultIfEmpty(newValue, null); + } + return actualChanges; } public boolean isNotAgainstClientWithIdOf(Long clientId) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/CreateClientCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/CreateClientCommandHandler.java new file mode 100644 index 000000000..e79135f26 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/CreateClientCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.client.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.client.service.ClientWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateClientCommandHandler implements NewCommandSourceHandler { + + private final ClientWritePlatformService clientWritePlatformService; + + @Autowired + public CreateClientCommandHandler(final ClientWritePlatformService clientWritePlatformService) { + this.clientWritePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.clientWritePlatformService.createClient(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/CreateClientIdentifierCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/CreateClientIdentifierCommandHandler.java new file mode 100644 index 000000000..b6683e5e0 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/CreateClientIdentifierCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.client.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.client.service.ClientWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateClientIdentifierCommandHandler implements NewCommandSourceHandler { + + private final ClientWritePlatformService clientWritePlatformService; + + @Autowired + public CreateClientIdentifierCommandHandler(final ClientWritePlatformService clientWritePlatformService) { + this.clientWritePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.clientWritePlatformService.addClientIdentifier(command.resourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/CreateClientNoteCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/CreateClientNoteCommandHandler.java new file mode 100644 index 000000000..10c5297ad --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/CreateClientNoteCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.client.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.client.service.ClientWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateClientNoteCommandHandler implements NewCommandSourceHandler { + + private final ClientWritePlatformService clientWritePlatformService; + + @Autowired + public CreateClientNoteCommandHandler(final ClientWritePlatformService clientWritePlatformService) { + this.clientWritePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.clientWritePlatformService.addClientNote(command.resourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/DeleteClientCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/DeleteClientCommandHandler.java new file mode 100644 index 000000000..654d8d777 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/DeleteClientCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.client.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.client.service.ClientWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class DeleteClientCommandHandler implements NewCommandSourceHandler { + + private final ClientWritePlatformService clientWritePlatformService; + + @Autowired + public DeleteClientCommandHandler(final ClientWritePlatformService clientWritePlatformService) { + this.clientWritePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.clientWritePlatformService.deleteClient(command.resourceId()); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/DeleteClientIdentifierCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/DeleteClientIdentifierCommandHandler.java new file mode 100644 index 000000000..9dccab29b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/DeleteClientIdentifierCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.client.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.client.service.ClientWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class DeleteClientIdentifierCommandHandler implements NewCommandSourceHandler { + + private final ClientWritePlatformService clientWritePlatformService; + + @Autowired + public DeleteClientIdentifierCommandHandler(final ClientWritePlatformService clientWritePlatformService) { + this.clientWritePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.clientWritePlatformService.deleteClientIdentifier(command.resourceId(), command.subResourceId(), command.commandId()); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/UpdateClientCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/UpdateClientCommandHandler.java new file mode 100644 index 000000000..1c9712d09 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/UpdateClientCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.client.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.client.service.ClientWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateClientCommandHandler implements NewCommandSourceHandler { + + private final ClientWritePlatformService clientWritePlatformService; + + @Autowired + public UpdateClientCommandHandler(final ClientWritePlatformService clientWritePlatformService) { + this.clientWritePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.clientWritePlatformService.updateClient(command.resourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/UpdateClientIdentifierCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/UpdateClientIdentifierCommandHandler.java new file mode 100644 index 000000000..3495d0bc9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/UpdateClientIdentifierCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.client.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.client.service.ClientWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateClientIdentifierCommandHandler implements NewCommandSourceHandler { + + private final ClientWritePlatformService clientWritePlatformService; + + @Autowired + public UpdateClientIdentifierCommandHandler(final ClientWritePlatformService clientWritePlatformService) { + this.clientWritePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.clientWritePlatformService.updateClientIdentifier(command.resourceId(), command.subResourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/UpdateClientNoteCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/UpdateClientNoteCommandHandler.java new file mode 100644 index 000000000..da0787837 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/UpdateClientNoteCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.client.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.client.service.ClientWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateClientNoteCommandHandler implements NewCommandSourceHandler { + + private final ClientWritePlatformService clientWritePlatformService; + + @Autowired + public UpdateClientNoteCommandHandler(final ClientWritePlatformService clientWritePlatformService) { + this.clientWritePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.clientWritePlatformService.updateClientNote(command.resourceId(), command.subResourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientCommandFromApiJsonDeserializer.java index a2130f381..df4ca2cac 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientCommandFromApiJsonDeserializer.java @@ -6,9 +6,10 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.portfolio.client.command.ClientCommand; @@ -34,16 +35,16 @@ public final class ClientCommandFromApiJsonDeserializer extends AbstractFromApiJ private final FromJsonHelper fromApiJsonHelper; @Autowired - public ClientCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, final CommandSerializer commandSerializerService) { - super(commandSerializerService); + public ClientCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; } @Override - public ClientCommand commandFromApiJson(@SuppressWarnings("unused") final Long clientId, final String json) { + public ClientCommand commandFromApiJson(final String json) { + + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); final JsonElement element = fromApiJsonHelper.parse(json); @@ -52,7 +53,7 @@ public final class ClientCommandFromApiJsonDeserializer extends AbstractFromApiJ final String firstname = fromApiJsonHelper.extractStringNamed("firstname", element); final String lastname = fromApiJsonHelper.extractStringNamed("lastname", element); final String clientOrBusinessName = fromApiJsonHelper.extractStringNamed("clientOrBusinessName", element); - final LocalDate joiningDate = fromApiJsonHelper.extractLocalDateNamed("joiningDate", element); + final LocalDate joiningDate = fromApiJsonHelper.extractLocalDateNamed("joinedDate", element); return new ClientCommand(externalId, firstname, lastname, clientOrBusinessName, officeId, joiningDate); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientIdentifierCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientIdentifierCommandFromApiJsonDeserializer.java index 0c0041831..e4c5081d7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientIdentifierCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientIdentifierCommandFromApiJsonDeserializer.java @@ -6,8 +6,9 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.portfolio.client.command.ClientCommand; @@ -15,6 +16,7 @@ import org.mifosplatform.portfolio.client.command.ClientIdentifierCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import com.google.gson.JsonElement; import com.google.gson.reflect.TypeToken; /** @@ -27,40 +29,28 @@ public final class ClientIdentifierCommandFromApiJsonDeserializer extends Abstra /** * The parameters supported for this command. */ - private final Set supportedParameters = new HashSet(Arrays.asList("clientId", "documentTypeId", "documentKey", - "description")); + private final Set supportedParameters = new HashSet(Arrays.asList("documentTypeId", "documentKey", "description")); private final FromJsonHelper fromApiJsonHelper; - private final ClientIdentifierCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer; - private final CommandSerializer commandSerializerService; @Autowired - public ClientIdentifierCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, - final ClientIdentifierCommandFromCommandJsonDeserializer commandFromCommandJsonDeserializer, - final CommandSerializer commandSerializerService) { - super(commandSerializerService); + public ClientIdentifierCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; - this.commandFromCommandJsonDeserializer = commandFromCommandJsonDeserializer; - this.commandSerializerService = commandSerializerService; } @Override - public ClientIdentifierCommand commandFromApiJson(final Long clientIdentifierId, final String json) { + public ClientIdentifierCommand commandFromApiJson(final String json) { + + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - return this.commandFromCommandJsonDeserializer.commandFromCommandJson(clientIdentifierId, json); - } + final JsonElement element = fromApiJsonHelper.parse(json); + final Long documentTypeId = fromApiJsonHelper.extractLongNamed("documentTypeId", element); + final String documentKey = fromApiJsonHelper.extractStringNamed("documentKey", element); + final String documentDescription = fromApiJsonHelper.extractStringNamed("documentDescription", element); - public String serializedCommandJsonFromApiJsonWithSubResource(final String json, final Long clientId) { - return serializedCommandJsonFromApiJsonWithSubResource(null, json, clientId); - } - - public String serializedCommandJsonFromApiJsonWithSubResource(final Long clientIdentifierId, final String json, final Long clientId) { - final ClientIdentifierCommand command = commandFromApiJson(clientIdentifierId, json); - final ClientIdentifierCommand commandWithSubResource = ClientIdentifierCommand.clientSubResource(command, clientId); - return this.commandSerializerService.serializeCommandToJson(commandWithSubResource); + return new ClientIdentifierCommand(documentTypeId, documentKey, documentDescription); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientIdentifierCommandFromCommandJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientIdentifierCommandFromCommandJsonDeserializer.java deleted file mode 100644 index 828d4dec6..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientIdentifierCommandFromCommandJsonDeserializer.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.mifosplatform.portfolio.client.serialization; - -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.serialization.FromCommandJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.portfolio.client.command.ClientIdentifierCommand; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.google.gson.JsonElement; - -@Component -public final class ClientIdentifierCommandFromCommandJsonDeserializer implements FromCommandJsonDeserializer { - - private final FromJsonHelper fromJsonHelper; - - @Autowired - public ClientIdentifierCommandFromCommandJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { - this.fromJsonHelper = fromApiJsonHelper; - } - - @Override - public ClientIdentifierCommand commandFromCommandJson(final String commandAsJson) { - return commandFromCommandJson(null, commandAsJson); - } - - @Override - public ClientIdentifierCommand commandFromCommandJson(final Long clientIdentifierId, final String commandAsJson) { - return commandFromCommandJson(clientIdentifierId, commandAsJson, false); - } - - @Override - public ClientIdentifierCommand commandFromCommandJson(final Long clientIdentifierId, final String commandAsJson, - final boolean makerCheckerApproval) { - if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); } - - final Set parametersPassedInRequest = new HashSet(); - - final JsonElement element = fromJsonHelper.parse(commandAsJson); - Long actualClientId = null; // FIXME - kw -clientId - final Long clientIdInternal = fromJsonHelper.extractLongNamed("clientId", element, parametersPassedInRequest); - if (clientIdInternal != null) { - actualClientId = clientIdInternal; - } - final Long documentTypeId = fromJsonHelper.extractLongNamed("documentTypeId", element, parametersPassedInRequest); - final String documentKey = fromJsonHelper.extractStringNamed("documentKey", element, parametersPassedInRequest); - final String documentDescription = fromJsonHelper.extractStringNamed("documentDescription", element, parametersPassedInRequest); - - return new ClientIdentifierCommand(parametersPassedInRequest, makerCheckerApproval, clientIdentifierId, actualClientId, - documentTypeId, documentKey, documentDescription); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientNoteCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientNoteCommandFromApiJsonDeserializer.java index e540889ee..b213a817f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientNoteCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientNoteCommandFromApiJsonDeserializer.java @@ -6,8 +6,9 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.portfolio.client.command.ClientCommand; @@ -28,41 +29,26 @@ public final class ClientNoteCommandFromApiJsonDeserializer extends AbstractFrom /** * The parameters supported for this command. */ - private final Set supportedParameters = new HashSet(Arrays.asList("clientId", "note")); + private final Set supportedParameters = new HashSet(Arrays.asList("note")); private final FromJsonHelper fromApiJsonHelper; - private final CommandSerializer commandSerializerService; @Autowired - public ClientNoteCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, final CommandSerializer commandSerializerService) { - super(commandSerializerService); + public ClientNoteCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; - this.commandSerializerService = commandSerializerService; } @Override - public ClientNoteCommand commandFromApiJson(final Long noteId, final String json) { + public ClientNoteCommand commandFromApiJson(final String json) { + + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final Set parametersPassedInRequest = new HashSet(); - final JsonElement element = fromApiJsonHelper.parse(json); - final Long clientId = fromApiJsonHelper.extractLongNamed("clientId", element, parametersPassedInRequest); - final String note = fromApiJsonHelper.extractStringNamed("note", element, parametersPassedInRequest); + final String note = fromApiJsonHelper.extractStringNamed("note", element); - return new ClientNoteCommand(parametersPassedInRequest, false, noteId, clientId, note); - } - - public String serializedCommandJsonFromApiJsonWithSubResource(final String json, final Long clientId) { - return serializedCommandJsonFromApiJsonWithSubResource(null, json, clientId); - } - - public String serializedCommandJsonFromApiJsonWithSubResource(final Long noteId, final String json, final Long clientId) { - final ClientNoteCommand command = commandFromApiJson(noteId, json); - final ClientNoteCommand commandWithSubResource = ClientNoteCommand.clientSubResource(command, clientId); - return this.commandSerializerService.serializeCommandToJson(commandWithSubResource); + return new ClientNoteCommand(note); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientNoteCommandFromCommandJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientNoteCommandFromCommandJsonDeserializer.java deleted file mode 100644 index d9cf6a774..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientNoteCommandFromCommandJsonDeserializer.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.mifosplatform.portfolio.client.serialization; - -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.serialization.AbstractFromCommandJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.portfolio.client.command.ClientNoteCommand; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.google.gson.JsonElement; - -@Component -public final class ClientNoteCommandFromCommandJsonDeserializer extends AbstractFromCommandJsonDeserializer { - - private final FromJsonHelper fromJsonHelper; - - @Autowired - public ClientNoteCommandFromCommandJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { - this.fromJsonHelper = fromApiJsonHelper; - } - - @Override - public ClientNoteCommand commandFromCommandJson(final Long noteId, final String commandAsJson, final boolean makerCheckerApproval) { - if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); } - - final Set parametersPassedInRequest = new HashSet(); - - final JsonElement element = fromJsonHelper.parse(commandAsJson); - final Long clientId = fromJsonHelper.extractLongNamed("clientId", element, parametersPassedInRequest); - final String note = fromJsonHelper.extractStringNamed("note", element, parametersPassedInRequest); - - return new ClientNoteCommand(parametersPassedInRequest, makerCheckerApproval, noteId, clientId, note); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformService.java index e0573bc12..d76ece0d8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformService.java @@ -5,17 +5,15 @@ import java.io.InputStream; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.domain.Base64EncodedImage; -import org.mifosplatform.portfolio.client.command.ClientIdentifierCommand; -import org.mifosplatform.portfolio.client.command.ClientNoteCommand; import org.springframework.security.access.prepost.PreAuthorize; public interface ClientWritePlatformService { - Long createClient(JsonCommand command); + EntityIdentifier createClient(JsonCommand command); - EntityIdentifier updateClientDetails(Long clientId, JsonCommand command); + EntityIdentifier updateClient(Long clientId, JsonCommand command); - EntityIdentifier deleteClient(Long clientId, JsonCommand command); + EntityIdentifier deleteClient(Long clientId); @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'CREATE_CLIENTIMAGE')") EntityIdentifier saveOrUpdateClientImage(Long clientId, String imageName, InputStream inputStream); @@ -26,13 +24,13 @@ public interface ClientWritePlatformService { @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'DELETE_CLIENTIMAGE')") EntityIdentifier deleteClientImage(Long clientId); - EntityIdentifier addClientNote(ClientNoteCommand command); + EntityIdentifier addClientNote(Long clientId, JsonCommand command); - EntityIdentifier updateNote(ClientNoteCommand command); + EntityIdentifier updateClientNote(Long clientId, Long noteId, JsonCommand command); - Long addClientIdentifier(ClientIdentifierCommand command); + EntityIdentifier addClientIdentifier(Long clientId, JsonCommand command); - EntityIdentifier updateClientIdentifier(ClientIdentifierCommand command); + EntityIdentifier updateClientIdentifier(Long clientId, Long clientIdentifierId, JsonCommand command); - EntityIdentifier deleteClientIdentifier(ClientIdentifierCommand command); + EntityIdentifier deleteClientIdentifier(Long clientId, Long clientIdentifierId, Long commandId); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index d73351577..52c81be26 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -16,13 +16,11 @@ import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityExce import org.mifosplatform.infrastructure.core.service.FileUtils; import org.mifosplatform.infrastructure.documentmanagement.exception.DocumentManagementException; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; import org.mifosplatform.organisation.office.domain.Office; import org.mifosplatform.organisation.office.domain.OfficeRepository; import org.mifosplatform.organisation.office.exception.OfficeNotFoundException; import org.mifosplatform.portfolio.client.command.ClientCommand; import org.mifosplatform.portfolio.client.command.ClientIdentifierCommand; -import org.mifosplatform.portfolio.client.command.ClientIdentifierCommandValidator; import org.mifosplatform.portfolio.client.command.ClientNoteCommand; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.ClientIdentifier; @@ -35,6 +33,8 @@ import org.mifosplatform.portfolio.client.exception.ClientNotFoundException; import org.mifosplatform.portfolio.client.exception.DuplicateClientIdentifierException; import org.mifosplatform.portfolio.client.exception.NoteNotFoundException; import org.mifosplatform.portfolio.client.serialization.ClientCommandFromApiJsonDeserializer; +import org.mifosplatform.portfolio.client.serialization.ClientIdentifierCommandFromApiJsonDeserializer; +import org.mifosplatform.portfolio.client.serialization.ClientNoteCommandFromApiJsonDeserializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -53,27 +53,31 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP private final OfficeRepository officeRepository; private final NoteRepository noteRepository; private final CodeValueRepository codeValueRepository; - private final ConfigurationDomainService configurationDomainService; private final ClientCommandFromApiJsonDeserializer fromApiJsonDeserializer; + private final ClientNoteCommandFromApiJsonDeserializer clientNoteFromApiJsonDeserializer; + private final ClientIdentifierCommandFromApiJsonDeserializer clientIdentifierCommandFromApiJsonDeserializer; @Autowired public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ClientRepository clientRepository, final ClientIdentifierRepository clientIdentifierRepository, final OfficeRepository officeRepository, final NoteRepository noteRepository, final CodeValueRepository codeValueRepository, - final ConfigurationDomainService configurationDomainService, final ClientCommandFromApiJsonDeserializer fromApiJsonDeserializer) { + final ClientCommandFromApiJsonDeserializer fromApiJsonDeserializer, + final ClientNoteCommandFromApiJsonDeserializer clientNoteFromApiJsonDeserializer, + final ClientIdentifierCommandFromApiJsonDeserializer clientIdentifierCommandFromApiJsonDeserializer) { this.context = context; this.clientRepository = clientRepository; this.clientIdentifierRepository = clientIdentifierRepository; this.officeRepository = officeRepository; this.noteRepository = noteRepository; this.codeValueRepository = codeValueRepository; - this.configurationDomainService = configurationDomainService; this.fromApiJsonDeserializer = fromApiJsonDeserializer; + this.clientNoteFromApiJsonDeserializer = clientNoteFromApiJsonDeserializer; + this.clientIdentifierCommandFromApiJsonDeserializer = clientIdentifierCommandFromApiJsonDeserializer; } @Transactional @Override - public EntityIdentifier deleteClient(final Long clientId, final JsonCommand command) { + public EntityIdentifier deleteClient(final Long clientId) { final Client client = this.clientRepository.findOne(clientId); if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); } @@ -81,9 +85,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP client.delete(); this.clientRepository.save(client); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("DELETE_CLIENT") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return new EntityIdentifier(client.getId()); + return EntityIdentifier.resourceResult(clientId, null); } /* @@ -107,7 +109,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP @Transactional @Override - public Long createClient(final JsonCommand command) { + public EntityIdentifier createClient(final JsonCommand command) { try { context.authenticatedUser(); @@ -124,18 +126,16 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP final Client newClient = Client.fromJson(clientOffice, command); this.clientRepository.save(newClient); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_CLIENT") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return newClient.getId(); + return EntityIdentifier.resourceResult(newClient.getId(), null); } catch (DataIntegrityViolationException dve) { handleDataIntegrityIssues(command, dve); - return Long.valueOf(-1); + return EntityIdentifier.empty(); } } @Transactional @Override - public EntityIdentifier updateClientDetails(final Long clientId, final JsonCommand command) { + public EntityIdentifier updateClient(final Long clientId, final JsonCommand command) { try { context.authenticatedUser(); @@ -145,24 +145,22 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP final Client clientForUpdate = this.clientRepository.findOne(clientId); if (clientForUpdate == null || clientForUpdate.isDeleted()) { throw new ClientNotFoundException(clientId); } - - final Map changesOnly = clientForUpdate.update(command); - if (changesOnly.containsKey("officeId")) { - final Long officeId = (Long) changesOnly.get("officeId"); - Office newOffice = this.officeRepository.findOne(officeId); + final Map changes = clientForUpdate.update(command); + + if (changes.containsKey("officeId")) { + final Long officeId = (Long) changes.get("officeId"); + final Office newOffice = this.officeRepository.findOne(officeId); if (newOffice == null) { throw new OfficeNotFoundException(officeId); } clientForUpdate.changeOffice(newOffice); } - if (!changesOnly.isEmpty()) { + if (!changes.isEmpty()) { this.clientRepository.save(clientForUpdate); } - if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_CLIENT") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return EntityIdentifier.withChanges(clientId, changesOnly); + return EntityIdentifier.withChanges(clientId, changes); } catch (DataIntegrityViolationException dve) { handleDataIntegrityIssues(command, dve); return new EntityIdentifier(Long.valueOf(-1)); @@ -171,113 +169,122 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP @Transactional @Override - public EntityIdentifier addClientNote(final ClientNoteCommand command) { + public EntityIdentifier addClientNote(final Long clientId, final JsonCommand command) { context.authenticatedUser(); - final Client clientForUpdate = this.clientRepository.findOne(command.getClientId()); - if (clientForUpdate == null) { throw new ClientNotFoundException(command.getClientId()); } + final ClientNoteCommand clientNoteCommand = this.clientNoteFromApiJsonDeserializer.commandFromApiJson(command.json()); + // FIXME - KW - no validation of note - final Note note = Note.clientNote(clientForUpdate, command.getNote()); + final Client clientForUpdate = this.clientRepository.findOne(clientId); + if (clientForUpdate == null) { throw new ClientNotFoundException(clientId); } + + final Note note = Note.clientNoteFromJson(clientForUpdate, command); this.noteRepository.save(note); - return new EntityIdentifier(note.getId()); + return EntityIdentifier.subResourceResult(clientId, note.getId(), command.commandId()); } @Transactional @Override - public EntityIdentifier updateNote(final ClientNoteCommand command) { + public EntityIdentifier updateClientNote(final Long clientId, final Long noteId, final JsonCommand command) { context.authenticatedUser(); - final Note noteForUpdate = this.noteRepository.findOne(command.getId()); - if (noteForUpdate == null || noteForUpdate.isNotAgainstClientWithIdOf(command.getClientId())) { throw new NoteNotFoundException( - command.getId(), command.getClientId(), "client"); } + final ClientNoteCommand clientNoteCommand = this.clientNoteFromApiJsonDeserializer.commandFromApiJson(command.json()); + // FIXME - KW - no validation of note - noteForUpdate.update(command.getNote()); + final Note noteForUpdate = this.noteRepository.findOne(noteId); + if (noteForUpdate == null || noteForUpdate.isNotAgainstClientWithIdOf(clientId)) { throw new NoteNotFoundException(noteId, + clientId, "client"); } - return new EntityIdentifier(noteForUpdate.getId()); + final Map changes = noteForUpdate.update(command); + + if (!changes.isEmpty()) { + this.noteRepository.save(noteForUpdate); + } + + return EntityIdentifier.subResourceResult(clientId, noteId, command.commandId(), changes); } @Transactional @Override - public Long addClientIdentifier(final ClientIdentifierCommand command) { + public EntityIdentifier addClientIdentifier(final Long clientId, final JsonCommand command) { + context.authenticatedUser(); + final ClientIdentifierCommand clientIdentifierCommand = this.clientIdentifierCommandFromApiJsonDeserializer + .commandFromApiJson(command.json()); + clientIdentifierCommand.validateForCreate(); + + String documentKey = clientIdentifierCommand.getDocumentKey(); String documentTypeLabel = null; Long documentTypeId = null; - final String documentKey = command.getDocumentKey(); - try { - context.authenticatedUser(); + final Client client = this.clientRepository.findOne(clientId); + if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); } - final ClientIdentifierCommandValidator validator = new ClientIdentifierCommandValidator(command); - validator.validateForCreate(); + final CodeValue documentType = this.codeValueRepository.findOne(clientIdentifierCommand.getDocumentTypeId()); + if (documentType == null) { throw new CodeValueNotFoundException(clientIdentifierCommand.getDocumentTypeId()); } - final Client client = this.clientRepository.findOne(command.getClientId()); - if (client == null || client.isDeleted()) { throw new ClientNotFoundException(command.getClientId()); } - - final CodeValue documentType = this.codeValueRepository.findOne(command.getDocumentTypeId()); - if (documentType == null) { throw new CodeValueNotFoundException(command.getDocumentTypeId()); } documentTypeId = documentType.getId(); documentTypeLabel = documentType.label(); - final ClientIdentifier clientIdentifier = ClientIdentifier.createNew(client, documentType, documentKey, - command.getDescription()); + final ClientIdentifier clientIdentifier = ClientIdentifier.fromJson(client, documentType, command); this.clientIdentifierRepository.save(clientIdentifier); - return clientIdentifier.getId(); + return EntityIdentifier.subResourceResult(clientId, clientIdentifier.getId(), command.commandId()); } catch (DataIntegrityViolationException dve) { handleClientIdentifierDataIntegrityViolation(documentTypeLabel, documentTypeId, documentKey, dve); - return Long.valueOf(-1); + return EntityIdentifier.empty(); } } @Transactional @Override - public EntityIdentifier updateClientIdentifier(final ClientIdentifierCommand command) { + public EntityIdentifier updateClientIdentifier(final Long clientId, final Long identifierId, final JsonCommand command) { + + context.authenticatedUser(); + final ClientIdentifierCommand clientIdentifierCommand = this.clientIdentifierCommandFromApiJsonDeserializer + .commandFromApiJson(command.json()); + clientIdentifierCommand.validateForUpdate(); String documentTypeLabel = null; - Long documentTypeId = null; - String documentKey = command.getDocumentKey(); - + String documentKey = null; + Long documentTypeId = clientIdentifierCommand.getDocumentTypeId(); try { - context.authenticatedUser(); - - final ClientIdentifierCommandValidator validator = new ClientIdentifierCommandValidator(command); - validator.validateForUpdate(); - CodeValue documentType = null; - documentTypeId = command.getDocumentTypeId(); - if (command.isDocumentTypeChanged() && documentTypeId != null) { + + final ClientIdentifier clientIdentifierForUpdate = this.clientIdentifierRepository.findOne(identifierId); + if (clientIdentifierForUpdate == null) { throw new ClientIdentifierNotFoundException(identifierId); } + + final Map changes = clientIdentifierForUpdate.update(command); + + if (changes.containsKey("documentTypeId")) { documentType = this.codeValueRepository.findOne(documentTypeId); - if (documentType == null) { throw new CodeValueNotFoundException(command.getDocumentTypeId()); } + if (documentType == null) { throw new CodeValueNotFoundException(documentTypeId); } + documentTypeId = documentType.getId(); documentTypeLabel = documentType.label(); + clientIdentifierForUpdate.update(documentType); } - final ClientIdentifier clientIdentifierForUpdate = this.clientIdentifierRepository.findOne(command.getId()); - if (clientIdentifierForUpdate == null) { throw new ClientIdentifierNotFoundException(command.getId()); } - - // TODO - KW - why need to check what changed when integrity - // violation occurs? - if (command.isDocumentTypeChanged() && command.isDocumentKeyChanged()) { - documentTypeId = command.getDocumentTypeId(); - documentKey = command.getDocumentKey(); - } else if (command.isDocumentTypeChanged() && !command.isDocumentKeyChanged()) { - documentTypeId = command.getDocumentTypeId(); - documentKey = clientIdentifierForUpdate.getDocumentKey(); - } else if (!command.isDocumentTypeChanged() && command.isDocumentKeyChanged()) { - documentTypeId = clientIdentifierForUpdate.getDocumentType().getId(); - documentKey = clientIdentifierForUpdate.getDocumentKey(); + if (changes.containsKey("documentTypeId") && changes.containsKey("documentKey")) { + documentTypeId = clientIdentifierCommand.getDocumentTypeId(); + documentKey = clientIdentifierCommand.getDocumentKey(); + } else if (changes.containsKey("documentTypeId") && !changes.containsKey("documentKey")) { + documentTypeId = clientIdentifierCommand.getDocumentTypeId(); + documentKey = clientIdentifierForUpdate.documentKey(); + } else if (!changes.containsKey("documentTypeId") && changes.containsKey("documentKey")) { + documentTypeId = clientIdentifierForUpdate.documentTypeId(); + documentKey = clientIdentifierForUpdate.documentKey(); } - clientIdentifierForUpdate.update(command, documentType); - - this.clientIdentifierRepository.saveAndFlush(clientIdentifierForUpdate); - - return new EntityIdentifier(clientIdentifierForUpdate.getId()); + if (!changes.isEmpty()) { + this.clientIdentifierRepository.saveAndFlush(clientIdentifierForUpdate); + } + return EntityIdentifier.subResourceResult(clientId, identifierId, command.commandId(), changes); } catch (DataIntegrityViolationException dve) { handleClientIdentifierDataIntegrityViolation(documentTypeLabel, documentTypeId, documentKey, dve); return new EntityIdentifier(Long.valueOf(-1)); @@ -303,12 +310,12 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP @Transactional @Override - public EntityIdentifier deleteClientIdentifier(final ClientIdentifierCommand command) { - final ClientIdentifier clientIdentifier = this.clientIdentifierRepository.findOne(command.getId()); - if (clientIdentifier == null) { throw new ClientIdentifierNotFoundException(command.getId()); } + public EntityIdentifier deleteClientIdentifier(final Long clientId, final Long identifierId, final Long commandId) { + final ClientIdentifier clientIdentifier = this.clientIdentifierRepository.findOne(identifierId); + if (clientIdentifier == null) { throw new ClientIdentifierNotFoundException(identifierId); } this.clientIdentifierRepository.delete(clientIdentifier); - return new EntityIdentifier(command.getId()); + return EntityIdentifier.subResourceResult(clientId, identifierId, commandId); } @Transactional diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/RollbackTransactionAsCommandIsNotApprovedByCheckerException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/RollbackTransactionAsCommandIsNotApprovedByCheckerException.java index a23f95c0e..e8bcbd9eb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/RollbackTransactionAsCommandIsNotApprovedByCheckerException.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/RollbackTransactionAsCommandIsNotApprovedByCheckerException.java @@ -2,4 +2,16 @@ package org.mifosplatform.portfolio.client.service; public class RollbackTransactionAsCommandIsNotApprovedByCheckerException extends RuntimeException { + /** + * Used to pass back the changes detected when updating a resource so the command json can be changed to only the changes. + */ + private final String jsonOfChangesOnly; + + public RollbackTransactionAsCommandIsNotApprovedByCheckerException(final String jsonOfChangesOnly) { + this.jsonOfChangesOnly = jsonOfChangesOnly; + } + + public String getJsonOfChangesOnly() { + return this.jsonOfChangesOnly; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/api/FundsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/api/FundsApiResource.java index 3d29c98f9..a1ee21031 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/api/FundsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/api/FundsApiResource.java @@ -3,7 +3,6 @@ package org.mifosplatform.portfolio.fund.api; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; @@ -25,7 +24,6 @@ import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSeriali import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.portfolio.fund.data.FundData; -import org.mifosplatform.portfolio.fund.serialization.FundCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.fund.service.FundReadPlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; @@ -45,19 +43,16 @@ public class FundsApiResource { private final PlatformSecurityContext context; private final FundReadPlatformService readPlatformService; - private final FundCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @Autowired public FundsApiResource(final PlatformSecurityContext context, final FundReadPlatformService readPlatformService, - final FundCommandFromApiJsonDeserializer fromApiJsonDeserializer, final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { this.context = context; this.readPlatformService = readPlatformService; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.toApiJsonSerializer = toApiJsonSerializer; this.apiRequestParameterHelper = apiRequestParameterHelper; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; @@ -81,13 +76,8 @@ public class FundsApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String createFund(final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", "CREATE_FUND"); - context.authenticatedUser().validateHasPermissionTo("CREATE_FUND", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "funds", null, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_FUND", "CREATE", "funds", null, + apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } @@ -112,13 +102,8 @@ public class FundsApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updateFund(@PathParam("fundId") final Long fundId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", "UPDATE_FUND"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_FUND", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "funds", fundId, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_FUND", "UPDATE", "funds", fundId, + apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/command/FundCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/command/FundCommand.java index cb476d16e..54c26701d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/command/FundCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/command/FundCommand.java @@ -2,7 +2,6 @@ package org.mifosplatform.portfolio.fund.command; import java.util.ArrayList; import java.util.List; -import java.util.Set; import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; @@ -16,43 +15,11 @@ public class FundCommand { private final String name; private final String externalId; - private final transient Set parametersPassedInRequest; - private final transient boolean makerCheckerApproval; - private final transient Long id; - - public FundCommand(final Set parametersPassedInRequest, final boolean makerCheckerApproval, final Long id, - final String fundName, final String externalId) { - this.parametersPassedInRequest = parametersPassedInRequest; - this.makerCheckerApproval = makerCheckerApproval; - this.id = id; + public FundCommand(final String fundName, final String externalId) { this.name = fundName; this.externalId = externalId; } - public Long getId() { - return id; - } - - public String getName() { - return name; - } - - public String getExternalId() { - return externalId; - } - - public boolean isNameChanged() { - return this.parametersPassedInRequest.contains("name"); - } - - public boolean isExternalIdChanged() { - return this.parametersPassedInRequest.contains("externalId"); - } - - public boolean isApprovedByChecker() { - return this.makerCheckerApproval; - } - public void validateForCreate() { List dataValidationErrors = new ArrayList(); @@ -70,7 +37,6 @@ public class FundCommand { DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("fund"); - baseDataValidator.reset().parameter("id").value(this.id).notNull(); baseDataValidator.reset().parameter("name").value(this.name).ignoreIfNull().notBlank(); baseDataValidator.reset().parameter("externalId").value(this.externalId).ignoreIfNull().notExceedingLengthOf(100); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/domain/Fund.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/domain/Fund.java index a502e6ca4..66aaf90a2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/domain/Fund.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/domain/Fund.java @@ -1,13 +1,16 @@ package org.mifosplatform.portfolio.fund.domain; +import java.util.LinkedHashMap; +import java.util.Map; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; import javax.persistence.UniqueConstraint; import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; -import org.mifosplatform.portfolio.fund.command.FundCommand; import org.mifosplatform.useradministration.domain.AppUser; @Entity @@ -15,16 +18,21 @@ import org.mifosplatform.useradministration.domain.AppUser; @UniqueConstraint(columnNames = { "external_id" }, name = "fund_externalid_org") }) public class Fund extends AbstractAuditableCustom { - @SuppressWarnings("unused") @Column(name = "name") private String name; - @SuppressWarnings("unused") @Column(name = "external_id", length = 100) private String externalId; - public static Fund createNew(final String fundName, final String externalId) { - return new Fund(fundName, externalId); + public static Fund fromJson(final JsonCommand command) { + + final String firstnameParamName = "name"; + final String name = command.stringValueOfParameterNamed(firstnameParamName); + + final String lastnameParamName = "externalId"; + final String externalId = command.stringValueOfParameterNamed(lastnameParamName); + + return new Fund(name, externalId); } protected Fund() { @@ -36,14 +44,24 @@ public class Fund extends AbstractAuditableCustom { this.externalId = StringUtils.defaultIfEmpty(externalId, null); } - public void update(final FundCommand command) { + public Map update(final JsonCommand command) { - if (command.isNameChanged()) { - this.name = StringUtils.defaultIfEmpty(command.getName(), null); + final Map actualChanges = new LinkedHashMap(7); + + final String nameParamName = "name"; + if (command.isChangeInStringParameterNamed(nameParamName, this.name)) { + final String newValue = command.stringValueOfParameterNamed(nameParamName); + actualChanges.put(nameParamName, newValue); + this.name = StringUtils.defaultIfEmpty(newValue, null); } - if (command.isExternalIdChanged()) { - this.externalId = StringUtils.defaultIfEmpty(command.getExternalId(), null); + final String externalIdParamName = "externalId"; + if (command.isChangeInStringParameterNamed(externalIdParamName, this.externalId)) { + final String newValue = command.stringValueOfParameterNamed(externalIdParamName); + actualChanges.put(externalIdParamName, newValue); + this.externalId = StringUtils.defaultIfEmpty(newValue, null); } + + return actualChanges; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/handler/CreateFundCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/handler/CreateFundCommandHandler.java new file mode 100644 index 000000000..8385a9f79 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/handler/CreateFundCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.fund.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.fund.service.FundWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateFundCommandHandler implements NewCommandSourceHandler { + + private final FundWritePlatformService writePlatformService; + + @Autowired + public CreateFundCommandHandler(final FundWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.createFund(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/handler/UpdateFundCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/handler/UpdateFundCommandHandler.java new file mode 100644 index 000000000..639aff739 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/handler/UpdateFundCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.fund.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.fund.service.FundWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateFundCommandHandler implements NewCommandSourceHandler { + + private final FundWritePlatformService writePlatformService; + + @Autowired + public UpdateFundCommandHandler(final FundWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.updateFund(command.resourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/serialization/FundCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/serialization/FundCommandFromApiJsonDeserializer.java index 9a92a4bc9..75762f564 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/serialization/FundCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/serialization/FundCommandFromApiJsonDeserializer.java @@ -6,20 +6,23 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; +import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.portfolio.fund.command.FundCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import com.google.gson.JsonElement; import com.google.gson.reflect.TypeToken; /** * Implementation of {@link FromApiJsonDeserializer} for {@link FundCommand}'s. */ @Component -public final class FundCommandFromApiJsonDeserializer implements FromApiJsonDeserializer { +public final class FundCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer { /** * The parameters supported for this command. @@ -27,41 +30,24 @@ public final class FundCommandFromApiJsonDeserializer implements FromApiJsonDese private final Set supportedParameters = new HashSet(Arrays.asList("name", "externalId")); private final FromJsonHelper fromApiJsonHelper; - private final FundCommandFromCommandJsonDeserializer fromCommandJsonDeserializer; - private final CommandSerializer commandSerializerService; @Autowired - public FundCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, - final FundCommandFromCommandJsonDeserializer fromCommandJsonDeserializer, final CommandSerializer commandSerializerService) { + public FundCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; - this.fromCommandJsonDeserializer = fromCommandJsonDeserializer; - this.commandSerializerService = commandSerializerService; } @Override public FundCommand commandFromApiJson(final String json) { - return commandFromApiJson(null, json); - } - @Override - public FundCommand commandFromApiJson(final Long fundId, final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - return this.fromCommandJsonDeserializer.commandFromCommandJson(fundId, json); - } + final JsonElement element = fromApiJsonHelper.parse(json); + final String name = fromApiJsonHelper.extractStringNamed("name", element); + final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element); - @Override - public String serializedCommandJsonFromApiJson(final String json) { - final FundCommand command = commandFromApiJson(json); - return this.commandSerializerService.serializeCommandToJson(command); - } - - @Override - public String serializedCommandJsonFromApiJson(final Long fundId, final String json) { - final FundCommand command = commandFromApiJson(fundId, json); - return this.commandSerializerService.serializeCommandToJson(command); + return new FundCommand(name, externalId); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/serialization/FundCommandFromCommandJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/serialization/FundCommandFromCommandJsonDeserializer.java deleted file mode 100644 index 536f246d1..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/serialization/FundCommandFromCommandJsonDeserializer.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.mifosplatform.portfolio.fund.serialization; - -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.serialization.FromCommandJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.portfolio.fund.command.FundCommand; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.google.gson.JsonElement; - -@Component -public final class FundCommandFromCommandJsonDeserializer implements FromCommandJsonDeserializer { - - private final FromJsonHelper fromJsonHelper; - - @Autowired - public FundCommandFromCommandJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { - this.fromJsonHelper = fromApiJsonHelper; - } - - @Override - public FundCommand commandFromCommandJson(final String commandAsJson) { - return commandFromCommandJson(null, commandAsJson); - } - - @Override - public FundCommand commandFromCommandJson(final Long fundId, final String commandAsJson) { - return commandFromCommandJson(fundId, commandAsJson, false); - } - - @Override - public FundCommand commandFromCommandJson(final Long fundId, final String commandAsJson, final boolean makerCheckerApproval) { - if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); } - - final Set parametersPassedInRequest = new HashSet(); - - final JsonElement element = fromJsonHelper.parse(commandAsJson); - - final String name = fromJsonHelper.extractStringNamed("name", element, parametersPassedInRequest); - final String externalId = fromJsonHelper.extractStringNamed("externalId", element, parametersPassedInRequest); - - return new FundCommand(parametersPassedInRequest, makerCheckerApproval, fundId, name, externalId); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/service/FundWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/service/FundWritePlatformService.java index ed041e1b8..1b75f790c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/service/FundWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/service/FundWritePlatformService.java @@ -1,10 +1,11 @@ package org.mifosplatform.portfolio.fund.service; -import org.mifosplatform.portfolio.fund.command.FundCommand; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; public interface FundWritePlatformService { - Long createFund(FundCommand command); + EntityIdentifier createFund(JsonCommand command); - Long updateFund(FundCommand command); + EntityIdentifier updateFund(Long fundId, JsonCommand command); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/service/FundWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/service/FundWritePlatformServiceJpaRepositoryImpl.java index a5d9b5661..1e19a92e3 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/service/FundWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/fund/service/FundWritePlatformServiceJpaRepositoryImpl.java @@ -1,13 +1,16 @@ package org.mifosplatform.portfolio.fund.service; +import java.util.Map; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.mifosplatform.portfolio.fund.command.FundCommand; import org.mifosplatform.portfolio.fund.domain.Fund; import org.mifosplatform.portfolio.fund.domain.FundRepository; import org.mifosplatform.portfolio.fund.exception.FundNotFoundException; +import org.mifosplatform.portfolio.fund.serialization.FundCommandFromApiJsonDeserializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -21,59 +24,61 @@ public class FundWritePlatformServiceJpaRepositoryImpl implements FundWritePlatf private final static Logger logger = LoggerFactory.getLogger(FundWritePlatformServiceJpaRepositoryImpl.class); private final PlatformSecurityContext context; + private final FundCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final FundRepository fundRepository; - private final ConfigurationDomainService configurationDomainService; @Autowired - public FundWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FundRepository fundRepository, - final ConfigurationDomainService configurationDomainService) { + public FundWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, + final FundCommandFromApiJsonDeserializer fromApiJsonDeserializer, + final FundRepository fundRepository) { this.context = context; + this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.fundRepository = fundRepository; - this.configurationDomainService = configurationDomainService; } @Transactional @Override - public Long createFund(final FundCommand command) { + public EntityIdentifier createFund(final JsonCommand command) { try { context.authenticatedUser(); - command.validateForCreate(); + + final FundCommand fundCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); + fundCommand.validateForCreate(); - Fund fund = Fund.createNew(command.getName(), command.getExternalId()); + Fund fund = Fund.fromJson(command); this.fundRepository.save(fund); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_FUND") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return fund.getId(); + return EntityIdentifier.resourceResult(fund.getId(), null); } catch (DataIntegrityViolationException dve) { handleFundDataIntegrityIssues(command, dve); - return Long.valueOf(-1); + return EntityIdentifier.empty(); } } @Transactional @Override - public Long updateFund(final FundCommand command) { + public EntityIdentifier updateFund(final Long fundId, final JsonCommand command) { try { context.authenticatedUser(); - command.validateForUpdate(); + + final FundCommand fundCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); + fundCommand.validateForUpdate(); - final Long fundId = command.getId(); - Fund fund = this.fundRepository.findOne(fundId); + final Fund fund = this.fundRepository.findOne(fundId); if (fund == null) { throw new FundNotFoundException(fundId); } - fund.update(command); + + final Map changes = fund.update(command); + if (!changes.isEmpty()) { + this.fundRepository.saveAndFlush(fund); + } - this.fundRepository.save(fund); - - if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_FUND") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return fund.getId(); + return EntityIdentifier.withChanges(fund.getId(), changes); } catch (DataIntegrityViolationException dve) { handleFundDataIntegrityIssues(command, dve); - return Long.valueOf(-1); + return EntityIdentifier.empty(); } } @@ -81,14 +86,18 @@ public class FundWritePlatformServiceJpaRepositoryImpl implements FundWritePlatf * Guaranteed to throw an exception no matter what the data integrity issue * is. */ - private void handleFundDataIntegrityIssues(final FundCommand command, DataIntegrityViolationException dve) { + private void handleFundDataIntegrityIssues(final JsonCommand command, DataIntegrityViolationException dve) { Throwable realCause = dve.getMostSpecificCause(); if (realCause.getMessage().contains("fund_externalid_org")) { - throw new PlatformDataIntegrityException("error.msg.fund.duplicate.externalId", "A fund with external id '" - + command.getExternalId() + "' already exists", "externalId", command.getExternalId()); - } else if (realCause.getMessage().contains("fund_name_org")) { throw new PlatformDataIntegrityException( - "error.msg.fund.duplicate.name", "A fund with name '" + command.getName() + "' already exists", "name", command.getName()); } + final String externalId = command.stringValueOfParameterNamed("externalId"); + throw new PlatformDataIntegrityException("error.msg.fund.duplicate.externalId", "A fund with external id '" + externalId + + "' already exists", "externalId", externalId); + } else if (realCause.getMessage().contains("fund_name_org")) { + final String name = command.stringValueOfParameterNamed("name"); + throw new PlatformDataIntegrityException("error.msg.fund.duplicate.name", "A fund with name '" + name + "' already exists", + "name", name); + } logger.error(dve.getMessage(), dve); throw new PlatformDataIntegrityException("error.msg.fund.unknown.data.integrity.issue", diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/command/LoanApplicationCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/command/LoanApplicationCommand.java index bf3815a5c..37e7a0d98 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/command/LoanApplicationCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/command/LoanApplicationCommand.java @@ -11,266 +11,251 @@ import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; * Immutable command for submitting new loan application. */ public class LoanApplicationCommand { - - private final Long loanId; - private final Long clientId; - private final Long groupId; - private final Long productId; - private final String externalId; - - private final Long fundId; - private final Long loanOfficerId; - private final Long transactionProcessingStrategyId; - - private final BigDecimal principal; - private final BigDecimal inArrearsTolerance; - - private final Integer loanTermFrequency; - private final Integer loanTermFrequencyType; - - private final Integer numberOfRepayments; - private final Integer repaymentEvery; - - private final BigDecimal interestRatePerPeriod; - private final Integer repaymentFrequencyType; - private final Integer interestRateFrequencyType; - private final Integer amortizationType; - private final Integer interestType; - private final Integer interestCalculationPeriodType; - - private final LocalDate expectedDisbursementDate; - private final LocalDate repaymentsStartingFromDate; - private final LocalDate interestChargedFromDate; - private final LocalDate submittedOnDate; - private final String submittedOnNote; + + private final Long loanId; + private final Long clientId; + private final Long groupId; + private final Long productId; + private final String externalId; + + private final Long fundId; + private final Long loanOfficerId; + private final Long transactionProcessingStrategyId; + + private final BigDecimal principal; + private final BigDecimal inArrearsTolerance; + + private final Integer loanTermFrequency; + private final Integer loanTermFrequencyType; + + private final Integer numberOfRepayments; + private final Integer repaymentEvery; + + private final BigDecimal interestRatePerPeriod; + private final Integer repaymentFrequencyType; + private final Integer interestRateFrequencyType; + private final Integer amortizationType; + private final Integer interestType; + private final Integer interestCalculationPeriodType; + + private final LocalDate expectedDisbursementDate; + private final LocalDate repaymentsStartingFromDate; + private final LocalDate interestChargedFromDate; + private final LocalDate submittedOnDate; + private final String submittedOnNote; private final LoanChargeCommand[] charges; - private final Set modifiedParameters; + private final Set modifiedParameters; - public LoanApplicationCommand( - final Set modifiedParameters, - final Long loanId, - final Long clientId, final Long groupId, final Long productId, final String externalId, - final Long fundId, final Long transactionProcessingStrategyId, - final LocalDate submittedOnDate, final String submittedOnNote, - final LocalDate expectedDisbursementDate, - final LocalDate repaymentsStartingFromDate, - final LocalDate interestChargedFromLocalDate, - final BigDecimal principal, - final BigDecimal interestRatePerPeriod, - final Integer interestRateFrequencyMethod, - final Integer interestMethod, - final Integer interestCalculationPeriodMethod, - final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, - final Integer loanTermFrequency, final Integer loanTermFrequencyType, - final BigDecimal toleranceAmount, final LoanChargeCommand[] charges, - final Long loanOfficerId) { - this.modifiedParameters = modifiedParameters; - this.loanId = loanId; - this.clientId = clientId; - this.groupId = groupId; - this.productId = productId; - this.externalId = externalId; - this.fundId = fundId; - this.loanOfficerId = loanOfficerId; - this.transactionProcessingStrategyId = transactionProcessingStrategyId; - - this.submittedOnDate = submittedOnDate; - this.submittedOnNote = submittedOnNote; - this.expectedDisbursementDate = expectedDisbursementDate; - this.repaymentsStartingFromDate = repaymentsStartingFromDate; - this.interestChargedFromDate = interestChargedFromLocalDate; - - this.principal = principal; - this.loanTermFrequency = loanTermFrequency; - this.loanTermFrequencyType = loanTermFrequencyType; - this.inArrearsTolerance = toleranceAmount; - - this.interestRatePerPeriod = interestRatePerPeriod; - this.interestRateFrequencyType = interestRateFrequencyMethod; - this.interestType = interestMethod; - this.interestCalculationPeriodType = interestCalculationPeriodMethod; - this.repaymentEvery = repaymentEvery; - this.repaymentFrequencyType = repaymentFrequency; - this.numberOfRepayments = numberOfRepayments; - this.amortizationType = amortizationMethod; + public LoanApplicationCommand(final Set modifiedParameters, final Long loanId, final Long clientId, final Long groupId, + final Long productId, final String externalId, final Long fundId, final Long transactionProcessingStrategyId, + final LocalDate submittedOnDate, final String submittedOnNote, final LocalDate expectedDisbursementDate, + final LocalDate repaymentsStartingFromDate, final LocalDate interestChargedFromLocalDate, final BigDecimal principal, + final BigDecimal interestRatePerPeriod, final Integer interestRateFrequencyMethod, final Integer interestMethod, + final Integer interestCalculationPeriodMethod, final Integer repaymentEvery, final Integer repaymentFrequency, + final Integer numberOfRepayments, Integer amortizationMethod, final Integer loanTermFrequency, + final Integer loanTermFrequencyType, final BigDecimal toleranceAmount, final LoanChargeCommand[] charges, + final Long loanOfficerId) { + this.modifiedParameters = modifiedParameters; + this.loanId = loanId; + this.clientId = clientId; + this.groupId = groupId; + this.productId = productId; + this.externalId = externalId; + this.fundId = fundId; + this.loanOfficerId = loanOfficerId; + this.transactionProcessingStrategyId = transactionProcessingStrategyId; + + this.submittedOnDate = submittedOnDate; + this.submittedOnNote = submittedOnNote; + this.expectedDisbursementDate = expectedDisbursementDate; + this.repaymentsStartingFromDate = repaymentsStartingFromDate; + this.interestChargedFromDate = interestChargedFromLocalDate; + + this.principal = principal; + this.loanTermFrequency = loanTermFrequency; + this.loanTermFrequencyType = loanTermFrequencyType; + this.inArrearsTolerance = toleranceAmount; + + this.interestRatePerPeriod = interestRatePerPeriod; + this.interestRateFrequencyType = interestRateFrequencyMethod; + this.interestType = interestMethod; + this.interestCalculationPeriodType = interestCalculationPeriodMethod; + this.repaymentEvery = repaymentEvery; + this.repaymentFrequencyType = repaymentFrequency; + this.numberOfRepayments = numberOfRepayments; + this.amortizationType = amortizationMethod; this.charges = charges; - } - - public CalculateLoanScheduleCommand toCalculateLoanScheduleCommand() { - return new CalculateLoanScheduleCommand(this.productId, - this.principal, this.interestRatePerPeriod, this.interestRateFrequencyType, - this.interestType, this.interestCalculationPeriodType, this.repaymentEvery, - this.repaymentFrequencyType, this.numberOfRepayments, this.amortizationType, - this.loanTermFrequency, this.loanTermFrequencyType, - this.expectedDisbursementDate, this.repaymentsStartingFromDate, this.interestChargedFromDate, this.charges); - } - - public Long getLoanId() { - return loanId; - } + } - public Long getClientId() { - return clientId; - } + public CalculateLoanScheduleCommand toCalculateLoanScheduleCommand() { + return new CalculateLoanScheduleCommand(this.productId, this.principal, this.interestRatePerPeriod, this.interestRateFrequencyType, + this.interestType, this.interestCalculationPeriodType, this.repaymentEvery, this.repaymentFrequencyType, + this.numberOfRepayments, this.amortizationType, this.loanTermFrequency, this.loanTermFrequencyType, + this.expectedDisbursementDate, this.repaymentsStartingFromDate, this.interestChargedFromDate, this.charges); + } - public Long getGroupId() { - return groupId; - } + public Long getLoanId() { + return loanId; + } - public Long getProductId() { - return productId; - } + public Long getClientId() { + return clientId; + } - public String getExternalId() { - return externalId; - } + public Long getGroupId() { + return groupId; + } - public Long getFundId() { - return fundId; - } - - public Long getTransactionProcessingStrategyId() { - return transactionProcessingStrategyId; - } + public Long getProductId() { + return productId; + } - public BigDecimal getPrincipal() { - return principal; - } + public String getExternalId() { + return externalId; + } - public BigDecimal getInArrearsTolerance() { - return inArrearsTolerance; - } + public Long getFundId() { + return fundId; + } - public Integer getNumberOfRepayments() { - return numberOfRepayments; - } + public Long getTransactionProcessingStrategyId() { + return transactionProcessingStrategyId; + } - public Integer getRepaymentEvery() { - return repaymentEvery; - } - - public Integer getLoanTermFrequency() { - return loanTermFrequency; - } + public BigDecimal getPrincipal() { + return principal; + } - public Integer getLoanTermFrequencyType() { - return loanTermFrequencyType; - } + public BigDecimal getInArrearsTolerance() { + return inArrearsTolerance; + } - public BigDecimal getInterestRatePerPeriod() { - return interestRatePerPeriod; - } + public Integer getNumberOfRepayments() { + return numberOfRepayments; + } - public Integer getRepaymentFrequencyType() { - return repaymentFrequencyType; - } + public Integer getRepaymentEvery() { + return repaymentEvery; + } - public Integer getInterestRateFrequencyType() { - return interestRateFrequencyType; - } + public Integer getLoanTermFrequency() { + return loanTermFrequency; + } - public Integer getAmortizationType() { - return amortizationType; - } + public Integer getLoanTermFrequencyType() { + return loanTermFrequencyType; + } - public Integer getInterestType() { - return interestType; - } + public BigDecimal getInterestRatePerPeriod() { + return interestRatePerPeriod; + } - public Integer getInterestCalculationPeriodType() { - return interestCalculationPeriodType; - } + public Integer getRepaymentFrequencyType() { + return repaymentFrequencyType; + } - public LocalDate getExpectedDisbursementDate() { - return expectedDisbursementDate; - } + public Integer getInterestRateFrequencyType() { + return interestRateFrequencyType; + } - public LocalDate getRepaymentsStartingFromDate() { - return repaymentsStartingFromDate; - } + public Integer getAmortizationType() { + return amortizationType; + } - public LocalDate getInterestChargedFromDate() { - return interestChargedFromDate; - } + public Integer getInterestType() { + return interestType; + } - public LocalDate getSubmittedOnDate() { - return submittedOnDate; - } + public Integer getInterestCalculationPeriodType() { + return interestCalculationPeriodType; + } - public String getSubmittedOnNote() { - return submittedOnNote; - } + public LocalDate getExpectedDisbursementDate() { + return expectedDisbursementDate; + } + + public LocalDate getRepaymentsStartingFromDate() { + return repaymentsStartingFromDate; + } + + public LocalDate getInterestChargedFromDate() { + return interestChargedFromDate; + } + + public LocalDate getSubmittedOnDate() { + return submittedOnDate; + } + + public String getSubmittedOnNote() { + return submittedOnNote; + } public LoanChargeCommand[] getCharges() { return charges; } - public LoanProductCommand toLoanProductCommand() { - - // FIXME - KW - CHARGE - FIX UP FOR CHARGES - take look at loan product charges also and align usage with other loan areas. - return new LoanProductCommand(modifiedParameters, false, this.productId, null, null, - this.fundId, this.transactionProcessingStrategyId, - null, null, - this.principal, this.inArrearsTolerance, - this.numberOfRepayments, this.repaymentEvery, this.interestRatePerPeriod, - this.repaymentFrequencyType, this.interestRateFrequencyType, - this.amortizationType, this.interestType, - this.interestCalculationPeriodType, - null); - } + public LoanProductCommand toLoanProductCommand() { - public boolean isClientChanged() { - return this.modifiedParameters.contains("clientId"); - } + // FIXME - KW - CHARGE - FIX UP FOR CHARGES - take look at loan product + // charges also and align usage with other loan areas. + return new LoanProductCommand(null, null, this.fundId, this.transactionProcessingStrategyId, null, null, this.principal, + this.inArrearsTolerance, this.numberOfRepayments, this.repaymentEvery, this.interestRatePerPeriod, + this.repaymentFrequencyType, this.interestRateFrequencyType, this.amortizationType, this.interestType, + this.interestCalculationPeriodType, null); + } - public boolean isProductChanged() { - return this.modifiedParameters.contains("productId"); - } + public boolean isClientChanged() { + return this.modifiedParameters.contains("clientId"); + } - public boolean isFundChanged() { - return this.modifiedParameters.contains("fundId"); - } - - public boolean isLoanOfficerChanged() { - return this.modifiedParameters.contains("loanOfficerId"); - } + public boolean isProductChanged() { + return this.modifiedParameters.contains("productId"); + } - public boolean isTransactionStrategyChanged() { - return this.modifiedParameters.contains("transactionProcessingStrategyId"); - } + public boolean isFundChanged() { + return this.modifiedParameters.contains("fundId"); + } - public boolean isTermFrequencyChanged() { - return this.modifiedParameters.contains("loanTermFrequency"); - } + public boolean isLoanOfficerChanged() { + return this.modifiedParameters.contains("loanOfficerId"); + } - public boolean isTermFrequencyTypeChanged() { - return this.modifiedParameters.contains("loanTermFrequencyType"); - } + public boolean isTransactionStrategyChanged() { + return this.modifiedParameters.contains("transactionProcessingStrategyId"); + } - public boolean isSubmittedOnDateChanged() { - return this.modifiedParameters.contains("submittedOnDate"); - } + public boolean isTermFrequencyChanged() { + return this.modifiedParameters.contains("loanTermFrequency"); + } - public boolean isExpectedDisbursementDatePassed() { - return this.modifiedParameters.contains("expectedDisbursementDate"); - } + public boolean isTermFrequencyTypeChanged() { + return this.modifiedParameters.contains("loanTermFrequencyType"); + } - public boolean isRepaymentsStartingFromDateChanged() { - return this.modifiedParameters.contains("repaymentsStartingFromDate"); - } + public boolean isSubmittedOnDateChanged() { + return this.modifiedParameters.contains("submittedOnDate"); + } - public boolean isInterestChargedFromDateChanged() { - return this.modifiedParameters.contains("interestChargedFromDate"); - } + public boolean isExpectedDisbursementDatePassed() { + return this.modifiedParameters.contains("expectedDisbursementDate"); + } - public boolean isChargesChanged() { - return this.modifiedParameters.contains("charges"); - } + public boolean isRepaymentsStartingFromDateChanged() { + return this.modifiedParameters.contains("repaymentsStartingFromDate"); + } - public Long getLoanOfficerId() { - return loanOfficerId; - } + public boolean isInterestChargedFromDateChanged() { + return this.modifiedParameters.contains("interestChargedFromDate"); + } + + public boolean isChargesChanged() { + return this.modifiedParameters.contains("charges"); + } + + public Long getLoanOfficerId() { + return loanOfficerId; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index 5977db6ce..9c27826fe 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -51,1417 +51,1425 @@ import org.mifosplatform.useradministration.domain.AppUser; @Table(name = "m_loan", uniqueConstraints = @UniqueConstraint(columnNames = { "external_id" })) public class Loan extends AbstractAuditableCustom { - @ManyToOne(optional = true) - @JoinColumn(name = "client_id") - private Client client; - - @ManyToOne(optional = true) - @JoinColumn(name = "guarantor_id") - private Client guarantor; + @ManyToOne(optional = true) + @JoinColumn(name = "client_id") + private Client client; + + @ManyToOne(optional = true) + @JoinColumn(name = "guarantor_id") + private Client guarantor; @SuppressWarnings("unused") - @ManyToOne(optional = true) + @ManyToOne(optional = true) @JoinColumn(name = "group_id") private Group group; - @ManyToOne - @JoinColumn(name = "product_id") - private LoanProduct loanProduct; + @ManyToOne + @JoinColumn(name = "product_id") + private LoanProduct loanProduct; - @SuppressWarnings("unused") - @ManyToOne - @JoinColumn(name = "fund_id", nullable = true) - private Fund fund; - - @ManyToOne - @JoinColumn(name = "loan_officer_id", nullable = true) - private Staff loanofficer; - - @ManyToOne - @JoinColumn(name = "loan_transaction_strategy_id", nullable = true) - private LoanTransactionProcessingStrategy transactionProcessingStrategy; + @SuppressWarnings("unused") + @ManyToOne + @JoinColumn(name = "fund_id", nullable = true) + private Fund fund; - @Column(name = "external_id") - private String externalId; + @ManyToOne + @JoinColumn(name = "loan_officer_id", nullable = true) + private Staff loanofficer; - @Embedded - private LoanProductRelatedDetail loanRepaymentScheduleDetail; - - @SuppressWarnings("unused") - @Column(name = "term_frequency", nullable = false) - private Integer termFrequency; + @ManyToOne + @JoinColumn(name = "loan_transaction_strategy_id", nullable = true) + private LoanTransactionProcessingStrategy transactionProcessingStrategy; - @SuppressWarnings("unused") - @Column(name = "term_period_frequency_enum", nullable = false) - private Integer termPeriodFrequencyType; + @Column(name = "external_id") + private String externalId; - @Column(name = "loan_status_id", nullable = false) - private Integer loanStatus; + @Embedded + private LoanProductRelatedDetail loanRepaymentScheduleDetail; - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "submittedon_date") - private Date submittedOnDate; + @SuppressWarnings("unused") + @Column(name = "term_frequency", nullable = false) + private Integer termFrequency; - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "rejectedon_date") - private Date rejectedOnDate; + @SuppressWarnings("unused") + @Column(name = "term_period_frequency_enum", nullable = false) + private Integer termPeriodFrequencyType; - @SuppressWarnings("unused") - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "withdrawnon_date") - private Date withdrawnOnDate; + @Column(name = "loan_status_id", nullable = false) + private Integer loanStatus; - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "approvedon_date") - private Date approvedOnDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "submittedon_date") + private Date submittedOnDate; - @Temporal(TemporalType.DATE) - @Column(name = "expected_disbursedon_date") - private Date expectedDisbursedOnDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "rejectedon_date") + private Date rejectedOnDate; - @Temporal(TemporalType.DATE) - @Column(name = "expected_firstrepaymenton_date") - private Date expectedFirstRepaymentOnDate; + @SuppressWarnings("unused") + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "withdrawnon_date") + private Date withdrawnOnDate; - @Temporal(TemporalType.DATE) - @Column(name = "interest_calculated_from_date") - private Date interestChargedFromDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "approvedon_date") + private Date approvedOnDate; - @Temporal(TemporalType.DATE) - @Column(name = "disbursedon_date") - private Date disbursedOnDate; + @Temporal(TemporalType.DATE) + @Column(name = "expected_disbursedon_date") + private Date expectedDisbursedOnDate; - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "closedon_date") - private Date closedOnDate; + @Temporal(TemporalType.DATE) + @Column(name = "expected_firstrepaymenton_date") + private Date expectedFirstRepaymentOnDate; - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "writtenoffon_date") - private Date writtenOffOnDate; + @Temporal(TemporalType.DATE) + @Column(name = "interest_calculated_from_date") + private Date interestChargedFromDate; - @Temporal(TemporalType.TIMESTAMP) - @Column(name = "rescheduledon_date") - private Date rescheduledOnDate; + @Temporal(TemporalType.DATE) + @Column(name = "disbursedon_date") + private Date disbursedOnDate; - @Temporal(TemporalType.DATE) - @Column(name = "expected_maturedon_date") - private Date expectedMaturityDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "closedon_date") + private Date closedOnDate; - @Temporal(TemporalType.DATE) - @Column(name = "maturedon_date") - private Date maturedOnDate; + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "writtenoffon_date") + private Date writtenOffOnDate; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "rescheduledon_date") + private Date rescheduledOnDate; + + @Temporal(TemporalType.DATE) + @Column(name = "expected_maturedon_date") + private Date expectedMaturityDate; + + @Temporal(TemporalType.DATE) + @Column(name = "maturedon_date") + private Date maturedOnDate; @LazyCollection(LazyCollectionOption.FALSE) @OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true) private Set charges; @LazyCollection(LazyCollectionOption.FALSE) - @OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true) + @OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true) private Set loanOfficerHistory; - // see - // http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags - @LazyCollection(LazyCollectionOption.FALSE) - @OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true) - private final List repaymentScheduleInstallments = new ArrayList(); + // see + // http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags + @LazyCollection(LazyCollectionOption.FALSE) + @OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true) + private final List repaymentScheduleInstallments = new ArrayList(); - // see - // http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags - @OrderBy(value = "dateOf, id") - @LazyCollection(LazyCollectionOption.FALSE) - @OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true) - private final List loanTransactions = new ArrayList(); + // see + // http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags + @OrderBy(value = "dateOf, id") + @LazyCollection(LazyCollectionOption.FALSE) + @OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true) + private final List loanTransactions = new ArrayList(); - @Column(name = "total_charges_due_at_disbursement_derived", scale = 6, precision = 19) - private BigDecimal totalChargesDueAtDisbursement; + @Column(name = "total_charges_due_at_disbursement_derived", scale = 6, precision = 19) + private BigDecimal totalChargesDueAtDisbursement; - @Transient - private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessor = new LoanRepaymentScheduleTransactionProcessorFactory(); + @Transient + private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessor = new LoanRepaymentScheduleTransactionProcessorFactory(); - public static Loan createNew(final Fund fund,final Staff loanOfficer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, - final LoanProduct loanProduct, final Client client, - final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set loanCharges) { - return new Loan(client, fund,loanOfficer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null, loanCharges); - } + public static Loan createNew(final Fund fund, final Staff loanOfficer, + final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct, final Client client, + final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set loanCharges) { + return new Loan(client, fund, loanOfficer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null, + loanCharges); + } - public static Loan createNew(final Fund fund,final Staff loanOfficer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, - final LoanProduct loanProduct, final Group group, - final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set loanCharges) { - return new Loan(group, fund,loanOfficer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null, loanCharges); - } + public static Loan createNew(final Fund fund, final Staff loanOfficer, + final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct, final Group group, + final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set loanCharges) { + return new Loan(group, fund, loanOfficer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null, + loanCharges); + } - protected Loan() { - this.client = null; + protected Loan() { + this.client = null; this.group = null; - this.loanProduct = null; - this.loanRepaymentScheduleDetail = null; + this.loanProduct = null; + this.loanRepaymentScheduleDetail = null; this.charges = null; this.loanOfficerHistory = null; - } + } - private Loan( - final Client client, Fund fund, Staff loanOfficer, - final LoanTransactionProcessingStrategy transactionProcessingStrategy, - final LoanProduct loanProduct, - final LoanProductRelatedDetail loanRepaymentScheduleDetail, - final LoanStatus loanStatus, final Set loanCharges) { - this.client = client; - this.fund = fund; - this.loanofficer = loanOfficer; - this.transactionProcessingStrategy = transactionProcessingStrategy; - this.loanProduct = loanProduct; - this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail; - if (loanStatus != null) { - this.loanStatus = loanStatus.getValue(); - } else { - this.loanStatus = null; - } - if (loanCharges != null && !loanCharges.isEmpty()) { - this.charges = associateChargesWithThisLoan(loanCharges); - this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement(); - } else { - this.charges = null; - } + private Loan(final Client client, Fund fund, Staff loanOfficer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, + final LoanProduct loanProduct, final LoanProductRelatedDetail loanRepaymentScheduleDetail, final LoanStatus loanStatus, + final Set loanCharges) { + this.client = client; + this.fund = fund; + this.loanofficer = loanOfficer; + this.transactionProcessingStrategy = transactionProcessingStrategy; + this.loanProduct = loanProduct; + this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail; + if (loanStatus != null) { + this.loanStatus = loanStatus.getValue(); + } else { + this.loanStatus = null; + } + if (loanCharges != null && !loanCharges.isEmpty()) { + this.charges = associateChargesWithThisLoan(loanCharges); + this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement(); + } else { + this.charges = null; + } this.loanOfficerHistory = null; - } + } - private Loan( - final Group group, Fund fund, Staff loanOfficer, - final LoanTransactionProcessingStrategy transactionProcessingStrategy, - final LoanProduct loanProduct, - final LoanProductRelatedDetail loanRepaymentScheduleDetail, - final LoanStatus loanStatus, final Set loanCharges) { - this.group = group; - this.fund = fund; - this.loanofficer = loanOfficer; - this.transactionProcessingStrategy = transactionProcessingStrategy; - this.loanProduct = loanProduct; - this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail; - if (loanStatus != null) { - this.loanStatus = loanStatus.getValue(); - } else { - this.loanStatus = null; - } - if (loanCharges != null && !loanCharges.isEmpty()) { - this.charges = associateChargesWithThisLoan(loanCharges); - this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement(); - } else { - this.charges = null; - } + private Loan(final Group group, Fund fund, Staff loanOfficer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, + final LoanProduct loanProduct, final LoanProductRelatedDetail loanRepaymentScheduleDetail, final LoanStatus loanStatus, + final Set loanCharges) { + this.group = group; + this.fund = fund; + this.loanofficer = loanOfficer; + this.transactionProcessingStrategy = transactionProcessingStrategy; + this.loanProduct = loanProduct; + this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail; + if (loanStatus != null) { + this.loanStatus = loanStatus.getValue(); + } else { + this.loanStatus = null; + } + if (loanCharges != null && !loanCharges.isEmpty()) { + this.charges = associateChargesWithThisLoan(loanCharges); + this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement(); + } else { + this.charges = null; + } this.loanOfficerHistory = null; - } + } - private BigDecimal deriveSumTotalOfChargesDueAtDisbursement() { - - Money chargesDue = Money.of(getCurrency(), BigDecimal.ZERO); - - for (LoanCharge charge : this.charges) { - if (charge.isDueAtDisbursement()) { - chargesDue = chargesDue.plus(charge.amount()); - } - } - - return chargesDue.getAmount(); - } + private BigDecimal deriveSumTotalOfChargesDueAtDisbursement() { + + Money chargesDue = Money.of(getCurrency(), BigDecimal.ZERO); + + for (LoanCharge charge : this.charges) { + if (charge.isDueAtDisbursement()) { + chargesDue = chargesDue.plus(charge.amount()); + } + } + + return chargesDue.getAmount(); + } + + private Set associateChargesWithThisLoan(final Set loanCharges) { + for (LoanCharge loanCharge : loanCharges) { + loanCharge.update(this); + } + return loanCharges; + } - private Set associateChargesWithThisLoan(final Set loanCharges) { - for (LoanCharge loanCharge : loanCharges) { - loanCharge.update(this); - } - return loanCharges; - } - private void updateTotalChargesDueAtDisbursement() { this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement(); } - - public void addLoanCharge(final LoanCharge loanCharge) { - - validateLoanIsNotClosed(loanCharge); - - if (isDisbursed() && loanCharge.isDueAtDisbursement()) { - // Note: added this constraint to restrict adding charges to a loan after it is disbursed - // if the loan charge payment type is 'Disbursement'. - // To undo this constraint would mean resolving how charges due are disbursement are handled at present. - // When a loan is disbursed and has charges due at disbursement, a transaction is created to auto record - // payment of the charges (user has no choice in saying they were or werent paid) - so its assumed they were paid. - - final String defaultUserMessage = "This charge which is due at disbursement cannot be added as the loan is already disbursed."; - throw new LoanChargeCannotBeAddedException("loanCharge", "due.at.disbursement.and.loan.is.disbursed", defaultUserMessage, getId(), loanCharge.name()); - } - - validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, getDisbursementDate(), getLastRepaymentPeriodDueDate()); - - loanCharge.update(this); - this.charges.add(loanCharge); - - updateTotalChargesDueAtDisbursement(); - - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy); - - if (!loanCharge.isDueAtDisbursement()) { // TODO - only need to reprocess transactions against loan schedule if loan charge is added with due date before latest transaction. - final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); - loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, this.charges); - } else { - // just reprocess the loan schedule only for now. - LoanScheduleWrapper wrapper = new LoanScheduleWrapper(); - wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, this.charges); - } - } - private void validateLoanIsNotClosed(final LoanCharge loanCharge) { - if (isClosed()) { - final String defaultUserMessage = "This charge cannot be added as the loan is already closed."; - throw new LoanChargeCannotBeAddedException("loanCharge", "loan.is.closed", defaultUserMessage, getId(), loanCharge.name()); - } - } - - private void validateLoanChargeIsNotWaived(final LoanCharge loanCharge) { - if (loanCharge.isWaivedOrPartiallyWaived(loanCurrency())) { - final String defaultUserMessage = "This loan charge cannot be removed as the charge as already been waived."; - throw new LoanChargeCannotBeAddedException("loanCharge", "loanCharge.is.waived", defaultUserMessage, getId(), loanCharge.name()); - } - } + public void addLoanCharge(final LoanCharge loanCharge) { - private void validateChargeHasValidSpecifiedDateIfApplicable(final LoanCharge loanCharge, final LocalDate disbursementDate, final LocalDate lastRepaymentPeriodDueDate) { - if (loanCharge.isSpecifiedDueDate() && !loanCharge.isDueForCollectionBetween(disbursementDate, lastRepaymentPeriodDueDate)) { - final String defaultUserMessage = "This charge which is due at disbursement cannot be added as the loan is already disbursed."; - throw new LoanChargeCannotBeAddedException("loanCharge", "specified.due.date.outside.range", defaultUserMessage, getDisbursementDate(), getLastRepaymentPeriodDueDate(), loanCharge.name()); - } - } - - private LocalDate getLastRepaymentPeriodDueDate() { - return this.repaymentScheduleInstallments.get(this.repaymentScheduleInstallments.size()-1).getDueDate(); - } + validateLoanIsNotClosed(loanCharge); - public void removeLoanCharge(final LoanCharge loanCharge) { - - validateLoanIsNotClosed(loanCharge); - - // NOTE: to remove this constraint requires that loan transactions - // that represent the waive of charges also be removed (or reversed) - // if you want ability to remove loan charges that are waived. - validateLoanChargeIsNotWaived(loanCharge); - - boolean removed = this.charges.remove(loanCharge); - if (removed) { - updateTotalChargesDueAtDisbursement(); - } - - removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(loanCharge); - - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy); - if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) { - final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); - loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, this.charges); - } - } + if (isDisbursed() && loanCharge.isDueAtDisbursement()) { + // Note: added this constraint to restrict adding charges to a loan + // after it is disbursed + // if the loan charge payment type is 'Disbursement'. + // To undo this constraint would mean resolving how charges due are + // disbursement are handled at present. + // When a loan is disbursed and has charges due at disbursement, a + // transaction is created to auto record + // payment of the charges (user has no choice in saying they were or + // werent paid) - so its assumed they were paid. - private void removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(final LoanCharge loanCharge) { - if (loanCharge.isDueAtDisbursement()) { - LoanTransaction transactionToRemove = null; - for (LoanTransaction transaction : this.loanTransactions) { - if (transaction.isRepaymentAtDisbursement()) { - - final MonetaryCurrency currency = loanCurrency(); - final Money chargeAmount = Money.of(currency, loanCharge.amount()); - if (transaction.isGreaterThan(chargeAmount)) { - final Money principalPortion = Money.zero(currency); - final Money interestPortion = Money.zero(currency); - final Money penaltychargesPortion = Money.zero(currency); - - final Money feeChargesPortion = chargeAmount; - transaction.updateComponentsAndTotal(principalPortion, interestPortion, feeChargesPortion, penaltychargesPortion); - } else { - transactionToRemove = transaction; - } - } - } - - if (transactionToRemove != null) { - this.loanTransactions.remove(transactionToRemove); - } - } - } - - public void updateLoanCharge(final LoanCharge loanCharge, final LoanChargeCommand command) { - - validateLoanIsNotClosed(loanCharge); - - if (this.charges.contains(loanCharge)) { - loanCharge.update(command, getPrincpal().getAmount()); - updateTotalChargesDueAtDisbursement(); - } - - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy); - if (!loanCharge.isDueAtDisbursement()) { - final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); - loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, this.charges); - } else { - // reprocess loan schedule based on charge been waived. - LoanScheduleWrapper wrapper = new LoanScheduleWrapper(); - wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, this.charges); - } - } - - public LoanTransaction waiveLoanCharge(final LoanCharge loanCharge, final LoanLifecycleStateMachine loanLifecycleStateMachine) { - - validateLoanIsNotClosed(loanCharge); - - final Money amountWaived = loanCharge.waive(loanCurrency()); - - Money feeChargesWaived = Money.of(loanCurrency(), loanCharge.amount()); - Money penaltyChargesWaived = Money.zero(loanCurrency()); - if (loanCharge.isPenaltyCharge()) { - penaltyChargesWaived = Money.of(loanCurrency(), loanCharge.amount()); - feeChargesWaived = Money.zero(loanCurrency()); - } - - LocalDate transactionDate = getDisbursementDate(); - if (loanCharge.isSpecifiedDueDate()) { - transactionDate = loanCharge.getDueForCollectionAsOfLocalDate(); - } - - updateTotalChargesDueAtDisbursement(); - - final LoanTransaction waiveLoanChargeTransaction = LoanTransaction.waiveLoanCharge(this, amountWaived, transactionDate,feeChargesWaived, penaltyChargesWaived); - - // Waive of charges whose due date falls after latest 'repayment' transaction dont require entire loan schedule to be reprocessed. - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy); - if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) { - final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); - loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, this.charges); - } else { - // reprocess loan schedule based on charge been waived. - LoanScheduleWrapper wrapper = new LoanScheduleWrapper(); - wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, this.charges); - } - - doPostLoanTransactionChecks(waiveLoanChargeTransaction.getTransactionDate(), loanLifecycleStateMachine); - - return waiveLoanChargeTransaction; - } + final String defaultUserMessage = "This charge which is due at disbursement cannot be added as the loan is already disbursed."; + throw new LoanChargeCannotBeAddedException("loanCharge", "due.at.disbursement.and.loan.is.disbursed", defaultUserMessage, + getId(), loanCharge.name()); + } - public Client client() { - return this.client; - } + validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, getDisbursementDate(), getLastRepaymentPeriodDueDate()); + + loanCharge.update(this); + this.charges.add(loanCharge); + + updateTotalChargesDueAtDisbursement(); + + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor + .determineProcessor(this.transactionProcessingStrategy); + + if (!loanCharge.isDueAtDisbursement()) { // TODO - only need to + // reprocess transactions + // against loan schedule if + // loan charge is added with + // due date before latest + // transaction. + final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); + loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, + getCurrency(), this.repaymentScheduleInstallments, this.charges); + } else { + // just reprocess the loan schedule only for now. + LoanScheduleWrapper wrapper = new LoanScheduleWrapper(); + wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, this.charges); + } + } + + private void validateLoanIsNotClosed(final LoanCharge loanCharge) { + if (isClosed()) { + final String defaultUserMessage = "This charge cannot be added as the loan is already closed."; + throw new LoanChargeCannotBeAddedException("loanCharge", "loan.is.closed", defaultUserMessage, getId(), loanCharge.name()); + } + } + + private void validateLoanChargeIsNotWaived(final LoanCharge loanCharge) { + if (loanCharge.isWaivedOrPartiallyWaived(loanCurrency())) { + final String defaultUserMessage = "This loan charge cannot be removed as the charge as already been waived."; + throw new LoanChargeCannotBeAddedException("loanCharge", "loanCharge.is.waived", defaultUserMessage, getId(), loanCharge.name()); + } + } + + private void validateChargeHasValidSpecifiedDateIfApplicable(final LoanCharge loanCharge, final LocalDate disbursementDate, + final LocalDate lastRepaymentPeriodDueDate) { + if (loanCharge.isSpecifiedDueDate() && !loanCharge.isDueForCollectionBetween(disbursementDate, lastRepaymentPeriodDueDate)) { + final String defaultUserMessage = "This charge which is due at disbursement cannot be added as the loan is already disbursed."; + throw new LoanChargeCannotBeAddedException("loanCharge", "specified.due.date.outside.range", defaultUserMessage, + getDisbursementDate(), getLastRepaymentPeriodDueDate(), loanCharge.name()); + } + } + + private LocalDate getLastRepaymentPeriodDueDate() { + return this.repaymentScheduleInstallments.get(this.repaymentScheduleInstallments.size() - 1).getDueDate(); + } + + public void removeLoanCharge(final LoanCharge loanCharge) { + + validateLoanIsNotClosed(loanCharge); + + // NOTE: to remove this constraint requires that loan transactions + // that represent the waive of charges also be removed (or reversed) + // if you want ability to remove loan charges that are waived. + validateLoanChargeIsNotWaived(loanCharge); + + boolean removed = this.charges.remove(loanCharge); + if (removed) { + updateTotalChargesDueAtDisbursement(); + } + + removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(loanCharge); + + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor + .determineProcessor(this.transactionProcessingStrategy); + if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) { + final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); + loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, + getCurrency(), this.repaymentScheduleInstallments, this.charges); + } + } + + private void removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(final LoanCharge loanCharge) { + if (loanCharge.isDueAtDisbursement()) { + LoanTransaction transactionToRemove = null; + for (LoanTransaction transaction : this.loanTransactions) { + if (transaction.isRepaymentAtDisbursement()) { + + final MonetaryCurrency currency = loanCurrency(); + final Money chargeAmount = Money.of(currency, loanCharge.amount()); + if (transaction.isGreaterThan(chargeAmount)) { + final Money principalPortion = Money.zero(currency); + final Money interestPortion = Money.zero(currency); + final Money penaltychargesPortion = Money.zero(currency); + + final Money feeChargesPortion = chargeAmount; + transaction.updateComponentsAndTotal(principalPortion, interestPortion, feeChargesPortion, penaltychargesPortion); + } else { + transactionToRemove = transaction; + } + } + } + + if (transactionToRemove != null) { + this.loanTransactions.remove(transactionToRemove); + } + } + } + + public void updateLoanCharge(final LoanCharge loanCharge, final LoanChargeCommand command) { + + validateLoanIsNotClosed(loanCharge); + + if (this.charges.contains(loanCharge)) { + loanCharge.update(command, getPrincpal().getAmount()); + updateTotalChargesDueAtDisbursement(); + } + + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor + .determineProcessor(this.transactionProcessingStrategy); + if (!loanCharge.isDueAtDisbursement()) { + final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); + loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, + getCurrency(), this.repaymentScheduleInstallments, this.charges); + } else { + // reprocess loan schedule based on charge been waived. + LoanScheduleWrapper wrapper = new LoanScheduleWrapper(); + wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, this.charges); + } + } + + public LoanTransaction waiveLoanCharge(final LoanCharge loanCharge, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + validateLoanIsNotClosed(loanCharge); + + final Money amountWaived = loanCharge.waive(loanCurrency()); + + Money feeChargesWaived = Money.of(loanCurrency(), loanCharge.amount()); + Money penaltyChargesWaived = Money.zero(loanCurrency()); + if (loanCharge.isPenaltyCharge()) { + penaltyChargesWaived = Money.of(loanCurrency(), loanCharge.amount()); + feeChargesWaived = Money.zero(loanCurrency()); + } + + LocalDate transactionDate = getDisbursementDate(); + if (loanCharge.isSpecifiedDueDate()) { + transactionDate = loanCharge.getDueForCollectionAsOfLocalDate(); + } + + updateTotalChargesDueAtDisbursement(); + + final LoanTransaction waiveLoanChargeTransaction = LoanTransaction.waiveLoanCharge(this, amountWaived, transactionDate, + feeChargesWaived, penaltyChargesWaived); + + // Waive of charges whose due date falls after latest 'repayment' + // transaction dont require entire loan schedule to be reprocessed. + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor + .determineProcessor(this.transactionProcessingStrategy); + if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) { + final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); + loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, + getCurrency(), this.repaymentScheduleInstallments, this.charges); + } else { + // reprocess loan schedule based on charge been waived. + LoanScheduleWrapper wrapper = new LoanScheduleWrapper(); + wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, this.charges); + } + + doPostLoanTransactionChecks(waiveLoanChargeTransaction.getTransactionDate(), loanLifecycleStateMachine); + + return waiveLoanChargeTransaction; + } + + public Client client() { + return this.client; + } public LoanProduct loanProduct() { - return this.loanProduct; - } + return this.loanProduct; + } public LoanProductRelatedDetail repaymentScheduleDetail() { - return this.loanRepaymentScheduleDetail; - } - - public void modifyLoanApplication(final LoanApplicationCommand command, final Client client, final LoanProduct loanProduct, - final Fund fund, final LoanTransactionProcessingStrategy strategy, final LoanScheduleData modifiedLoanSchedule, final Set charges, - final LoanLifecycleStateMachine loanLifecycleStateMachine) { + return this.loanRepaymentScheduleDetail; + } - // FIXME - KW - whilst the methods are named isXXXChanged, this really only is asking has the parameter for that field been passed in request, - // an additional check to see if the value passed is different to the current value may bee need for all these like it is for expectedDisbursementDate - if (command.isClientChanged()) { - this.client = client; - } - if (command.isProductChanged()) { - this.loanProduct = loanProduct; - } - if (command.isFundChanged()) { - this.fund = fund; - } - if (command.isTransactionStrategyChanged()) { - this.transactionProcessingStrategy = strategy; - } - - if (command.isTermFrequencyChanged()) { - this.termFrequency = command.getLoanTermFrequency(); - } - - if (command.isTermFrequencyTypeChanged()) { - this.termPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getLoanTermFrequencyType()).getValue(); - } - - if (command.isSubmittedOnDateChanged()) { - this.submittedOnDate = command.getSubmittedOnDate().toDate(); - } - - if (command.isExpectedDisbursementDatePassed()) { - if (dateHasChanged(getExpectedDisbursedOnLocalDate(), command.getExpectedDisbursementDate())) { - this.expectedDisbursedOnDate = command.getExpectedDisbursementDate().toDate(); - removeFirstDisbursementTransaction(); - disburse(command.getExpectedDisbursementDate(), loanLifecycleStateMachine, false); - } - } - - if (command.isRepaymentsStartingFromDateChanged()) { - if (command.getRepaymentsStartingFromDate() != null) { - this.expectedFirstRepaymentOnDate = command.getRepaymentsStartingFromDate().toDate(); - } else { - this.expectedFirstRepaymentOnDate = null; - } - } - - if (command.isInterestChargedFromDateChanged()) { - if (command.getInterestChargedFromDate() != null) { - this.interestChargedFromDate = command.getInterestChargedFromDate().toDate(); - } else { - this.interestChargedFromDate = null; - } - } + public void modifyLoanApplication(final LoanApplicationCommand command, final Client client, final LoanProduct loanProduct, + final Fund fund, final LoanTransactionProcessingStrategy strategy, final LoanScheduleData modifiedLoanSchedule, + final Set charges, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + // FIXME - KW - whilst the methods are named isXXXChanged, this really + // only is asking has the parameter for that field been passed in + // request, + // an additional check to see if the value passed is different to the + // current value may bee need for all these like it is for + // expectedDisbursementDate + if (command.isClientChanged()) { + this.client = client; + } + if (command.isProductChanged()) { + this.loanProduct = loanProduct; + } + if (command.isFundChanged()) { + this.fund = fund; + } + if (command.isTransactionStrategyChanged()) { + this.transactionProcessingStrategy = strategy; + } + + if (command.isTermFrequencyChanged()) { + this.termFrequency = command.getLoanTermFrequency(); + } + + if (command.isTermFrequencyTypeChanged()) { + this.termPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getLoanTermFrequencyType()).getValue(); + } + + if (command.isSubmittedOnDateChanged()) { + this.submittedOnDate = command.getSubmittedOnDate().toDate(); + } + + if (command.isExpectedDisbursementDatePassed()) { + if (dateHasChanged(getExpectedDisbursedOnLocalDate(), command.getExpectedDisbursementDate())) { + this.expectedDisbursedOnDate = command.getExpectedDisbursementDate().toDate(); + removeFirstDisbursementTransaction(); + disburse(command.getExpectedDisbursementDate(), loanLifecycleStateMachine, false); + } + } + + if (command.isRepaymentsStartingFromDateChanged()) { + if (command.getRepaymentsStartingFromDate() != null) { + this.expectedFirstRepaymentOnDate = command.getRepaymentsStartingFromDate().toDate(); + } else { + this.expectedFirstRepaymentOnDate = null; + } + } + + if (command.isInterestChargedFromDateChanged()) { + if (command.getInterestChargedFromDate() != null) { + this.interestChargedFromDate = command.getInterestChargedFromDate().toDate(); + } else { + this.interestChargedFromDate = null; + } + } if (command.isChargesChanged()) { - this.charges.clear(); - this.charges.addAll(associateChargesWithThisLoan(charges)); - this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement(); - } + this.charges.clear(); + this.charges.addAll(associateChargesWithThisLoan(charges)); + this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement(); + } - this.loanRepaymentScheduleDetail.update(command.toLoanProductCommand()); - - // FIXME - rewrite over loan schedule by default for now but worth putting in check to see if required - // i.e. only a client change wouldn't require it, only if one of parameters related to loan schedule calculation is changed. - this.repaymentScheduleInstallments.clear(); - for (LoanSchedulePeriodData scheduledLoanInstallment : modifiedLoanSchedule.getPeriods()) { - - if (scheduledLoanInstallment.isRepaymentPeriod()) { - LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment( - this, - scheduledLoanInstallment.periodNumber(), - scheduledLoanInstallment.periodFromDate(), - scheduledLoanInstallment.periodDueDate(), - scheduledLoanInstallment.principalDue(), - scheduledLoanInstallment.interestDue(), - scheduledLoanInstallment.feeChargesDue(), - scheduledLoanInstallment.penaltyChargesDue()); - this.addRepaymentScheduleInstallment(installment); - } - } - - // if the loan application/contract is modified when repayments are already against it - then need to re-process it - final List repaymentsOrWaivers = retreiveListOfTransactionsPostDisbursement(); - - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy); - loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), repaymentsOrWaivers, getCurrency(), this.repaymentScheduleInstallments, this.charges); - } + // FIXME - kw - break modify loan application at present. + // this.loanRepaymentScheduleDetail.update(command.toLoanProductCommand()); - private boolean dateHasChanged(final LocalDate originalLocalDate, final LocalDate providedLocalDate) { - - boolean dateHasChanged = false; - - if (originalLocalDate != null) { - dateHasChanged = !originalLocalDate.equals(providedLocalDate); - } else { - dateHasChanged = (providedLocalDate != null); - } - - return dateHasChanged; - } + // FIXME - rewrite over loan schedule by default for now but worth + // putting in check to see if required + // i.e. only a client change wouldn't require it, only if one of + // parameters related to loan schedule calculation is changed. + this.repaymentScheduleInstallments.clear(); + for (LoanSchedulePeriodData scheduledLoanInstallment : modifiedLoanSchedule.getPeriods()) { - private void removeFirstDisbursementTransaction() { - for (LoanTransaction loanTransaction : loanTransactions) { - if (loanTransaction.isDisbursement()) { - loanTransactions.remove(loanTransaction); - break; - } - } - } + if (scheduledLoanInstallment.isRepaymentPeriod()) { + LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(this, + scheduledLoanInstallment.periodNumber(), scheduledLoanInstallment.periodFromDate(), + scheduledLoanInstallment.periodDueDate(), scheduledLoanInstallment.principalDue(), + scheduledLoanInstallment.interestDue(), scheduledLoanInstallment.feeChargesDue(), + scheduledLoanInstallment.penaltyChargesDue()); + this.addRepaymentScheduleInstallment(installment); + } + } - public void submitApplication( - final Integer loanTermFrequency, - final PeriodFrequencyType loanTermFrequencyType, - final LocalDate submittedOn, - final LocalDate expectedDisbursementDate, - final LocalDate repaymentsStartingFromDate, - final LocalDate interestChargedFromDate, - final LoanLifecycleStateMachine lifecycleStateMachine) { - - LoanStatus from = null; - if (this.loanStatus != null) { - from = LoanStatus.fromInt(this.loanStatus); - } + // if the loan application/contract is modified when repayments are + // already against it - then need to re-process it + final List repaymentsOrWaivers = retreiveListOfTransactionsPostDisbursement(); - LoanStatus statusEnum = lifecycleStateMachine.transition(LoanEvent.LOAN_CREATED, from); - this.loanStatus = statusEnum.getValue(); + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor + .determineProcessor(this.transactionProcessingStrategy); + loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), repaymentsOrWaivers, getCurrency(), + this.repaymentScheduleInstallments, this.charges); + } - this.termFrequency = loanTermFrequency; - this.termPeriodFrequencyType = loanTermFrequencyType.getValue(); - - this.submittedOnDate = submittedOn.toDate(); - this.expectedMaturityDate = determineExpectedMaturityDate().toDate(); - if (expectedDisbursementDate != null) { - // can be null during bulk upload of loans - this.expectedDisbursedOnDate = expectedDisbursementDate.toDate(); - } + private boolean dateHasChanged(final LocalDate originalLocalDate, final LocalDate providedLocalDate) { - if (repaymentsStartingFromDate != null) { - this.expectedFirstRepaymentOnDate = repaymentsStartingFromDate.toDate(); - } + boolean dateHasChanged = false; - if (interestChargedFromDate != null) { - this.interestChargedFromDate = interestChargedFromDate.toDate(); - } + if (originalLocalDate != null) { + dateHasChanged = !originalLocalDate.equals(providedLocalDate); + } else { + dateHasChanged = (providedLocalDate != null); + } - if (submittedOn.isAfter(new LocalDate())) { - final String errorMessage = "The date on which a loan is submitted cannot be in the future."; - throw new InvalidLoanStateTransitionException("submittal", - "cannot.be.a.future.date", errorMessage, submittedOn); - } + return dateHasChanged; + } - if (submittedOn.isAfter(getExpectedDisbursedOnLocalDate())) { - final String errorMessage = "The date on which a loan is submitted cannot be after its expected disbursement date: " - + getExpectedDisbursedOnLocalDate().toString(); - throw new InvalidLoanStateTransitionException("submittal", - "cannot.be.after.expected.disbursement.date", errorMessage, - submittedOn, getExpectedDisbursedOnLocalDate()); - } - - // charges are optional - if (this.charges != null) { - for (LoanCharge loanCharge : this.charges) { - validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, getDisbursementDate(), getLastRepaymentPeriodDueDate()); - } - } - } + private void removeFirstDisbursementTransaction() { + for (LoanTransaction loanTransaction : loanTransactions) { + if (loanTransaction.isDisbursement()) { + loanTransactions.remove(loanTransaction); + break; + } + } + } - private LocalDate determineExpectedMaturityDate() { - int numberOfInstallments = this.repaymentScheduleInstallments.size(); - return this.repaymentScheduleInstallments.get(numberOfInstallments - 1).getDueDate(); - } + public void submitApplication(final Integer loanTermFrequency, final PeriodFrequencyType loanTermFrequencyType, + final LocalDate submittedOn, final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate, + final LocalDate interestChargedFromDate, final LoanLifecycleStateMachine lifecycleStateMachine) { - public void reject(final LocalDate rejectedOn, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + LoanStatus from = null; + if (this.loanStatus != null) { + from = LoanStatus.fromInt(this.loanStatus); + } - LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REJECTED, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - - this.rejectedOnDate = rejectedOn.toDateTimeAtCurrentTime().toDate(); - this.closedOnDate = rejectedOn.toDateTimeAtCurrentTime().toDate(); + LoanStatus statusEnum = lifecycleStateMachine.transition(LoanEvent.LOAN_CREATED, from); + this.loanStatus = statusEnum.getValue(); - if (rejectedOn.isBefore(getSubmittedOnDate())) { - final String errorMessage = "The date on which a loan is rejected cannot be before its submittal date: " - + getSubmittedOnDate().toString(); - throw new InvalidLoanStateTransitionException("reject", - "cannot.be.before.submittal.date", errorMessage, - rejectedOn, getSubmittedOnDate()); - } - if (rejectedOn.isAfter(new LocalDate())) { - final String errorMessage = "The date on which a loan is rejected cannot be in the future."; - throw new InvalidLoanStateTransitionException("reject", - "cannot.be.a.future.date", errorMessage, rejectedOn); - } - } + this.termFrequency = loanTermFrequency; + this.termPeriodFrequencyType = loanTermFrequencyType.getValue(); - public void withdraw( - final LocalDate withdrawnOn, - final LoanLifecycleStateMachine loanLifecycleStateMachine) { + this.submittedOnDate = submittedOn.toDate(); + this.expectedMaturityDate = determineExpectedMaturityDate().toDate(); + if (expectedDisbursementDate != null) { + // can be null during bulk upload of loans + this.expectedDisbursedOnDate = expectedDisbursementDate.toDate(); + } - LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_WITHDRAWN, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - - this.withdrawnOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate(); - this.closedOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate(); + if (repaymentsStartingFromDate != null) { + this.expectedFirstRepaymentOnDate = repaymentsStartingFromDate.toDate(); + } - if (withdrawnOn.isBefore(getSubmittedOnDate())) { - final String errorMessage = "The date on which a loan is withdrawn cannot be before its submittal date: " - + getSubmittedOnDate().toString(); - throw new InvalidLoanStateTransitionException("reject", - "cannot.be.before.submittal.date", errorMessage, - withdrawnOn, getSubmittedOnDate()); - } - if (withdrawnOn.isAfter(new LocalDate())) { - final String errorMessage = "The date on which a loan is withdrawn cannot be in the future."; - throw new InvalidLoanStateTransitionException("reject", - "cannot.be.a.future.date", errorMessage, withdrawnOn); - } - } + if (interestChargedFromDate != null) { + this.interestChargedFromDate = interestChargedFromDate.toDate(); + } - public void approve(final LocalDate approvedOn, final LoanLifecycleStateMachine loanLifecycleStateMachine) { - - final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVED, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - - this.approvedOnDate = approvedOn.toDateTimeAtCurrentTime().toDate(); + if (submittedOn.isAfter(new LocalDate())) { + final String errorMessage = "The date on which a loan is submitted cannot be in the future."; + throw new InvalidLoanStateTransitionException("submittal", "cannot.be.a.future.date", errorMessage, submittedOn); + } - final LocalDate submittalDate = new LocalDate(this.submittedOnDate); - if (approvedOn.isBefore(submittalDate)) { - final String errorMessage = "The date on which a loan is approved cannot be before its submittal date: " - + submittalDate.toString(); - throw new InvalidLoanStateTransitionException("approval", - "cannot.be.before.submittal.date", errorMessage, - getApprovedOnDate(), submittalDate); - } - if (approvedOn.isAfter(new LocalDate())) { - final String errorMessage = "The date on which a loan is approved cannot be in the future."; - throw new InvalidLoanStateTransitionException("approval", - "cannot.be.a.future.date", errorMessage, - getApprovedOnDate()); - } + if (submittedOn.isAfter(getExpectedDisbursedOnLocalDate())) { + final String errorMessage = "The date on which a loan is submitted cannot be after its expected disbursement date: " + + getExpectedDisbursedOnLocalDate().toString(); + throw new InvalidLoanStateTransitionException("submittal", "cannot.be.after.expected.disbursement.date", errorMessage, + submittedOn, getExpectedDisbursedOnLocalDate()); + } + + // charges are optional + if (this.charges != null) { + for (LoanCharge loanCharge : this.charges) { + validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, getDisbursementDate(), getLastRepaymentPeriodDueDate()); + } + } + } + + private LocalDate determineExpectedMaturityDate() { + int numberOfInstallments = this.repaymentScheduleInstallments.size(); + return this.repaymentScheduleInstallments.get(numberOfInstallments - 1).getDueDate(); + } + + public void reject(final LocalDate rejectedOn, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REJECTED, LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + + this.rejectedOnDate = rejectedOn.toDateTimeAtCurrentTime().toDate(); + this.closedOnDate = rejectedOn.toDateTimeAtCurrentTime().toDate(); + + if (rejectedOn.isBefore(getSubmittedOnDate())) { + final String errorMessage = "The date on which a loan is rejected cannot be before its submittal date: " + + getSubmittedOnDate().toString(); + throw new InvalidLoanStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage, rejectedOn, + getSubmittedOnDate()); + } + if (rejectedOn.isAfter(new LocalDate())) { + final String errorMessage = "The date on which a loan is rejected cannot be in the future."; + throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, rejectedOn); + } + } + + public void withdraw(final LocalDate withdrawnOn, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_WITHDRAWN, LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + + this.withdrawnOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate(); + this.closedOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate(); + + if (withdrawnOn.isBefore(getSubmittedOnDate())) { + final String errorMessage = "The date on which a loan is withdrawn cannot be before its submittal date: " + + getSubmittedOnDate().toString(); + throw new InvalidLoanStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage, withdrawnOn, + getSubmittedOnDate()); + } + if (withdrawnOn.isAfter(new LocalDate())) { + final String errorMessage = "The date on which a loan is withdrawn cannot be in the future."; + throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, withdrawnOn); + } + } + + public void approve(final LocalDate approvedOn, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVED, LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + + this.approvedOnDate = approvedOn.toDateTimeAtCurrentTime().toDate(); + + final LocalDate submittalDate = new LocalDate(this.submittedOnDate); + if (approvedOn.isBefore(submittalDate)) { + final String errorMessage = "The date on which a loan is approved cannot be before its submittal date: " + + submittalDate.toString(); + throw new InvalidLoanStateTransitionException("approval", "cannot.be.before.submittal.date", errorMessage, getApprovedOnDate(), + submittalDate); + } + if (approvedOn.isAfter(new LocalDate())) { + final String errorMessage = "The date on which a loan is approved cannot be in the future."; + throw new InvalidLoanStateTransitionException("approval", "cannot.be.a.future.date", errorMessage, getApprovedOnDate()); + } if (this.loanofficer != null) { - final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory.createNew(this, this.loanofficer, approvedOn); + final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory.createNew(this, + this.loanofficer, approvedOn); this.loanOfficerHistory.add(loanOfficerAssignmentHistory); } - } + } - public void undoApproval(LoanLifecycleStateMachine loanLifecycleStateMachine) { - - final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVAL_UNDO, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - - this.approvedOnDate = null; + public void undoApproval(LoanLifecycleStateMachine loanLifecycleStateMachine) { + + final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVAL_UNDO, + LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + + this.approvedOnDate = null; this.loanOfficerHistory.clear(); - } - - public void disburseWithModifiedRepaymentSchedule( - final LocalDate disbursedOn, - final List modifiedLoanRepaymentSchedule, - LoanLifecycleStateMachine loanLifecycleStateMachine) { - this.repaymentScheduleInstallments.clear(); - for (LoanRepaymentScheduleInstallment modifiedInstallment : modifiedLoanRepaymentSchedule) { - modifiedInstallment.updateLoan(this); - this.repaymentScheduleInstallments.add(modifiedInstallment); - } - disburse(disbursedOn, loanLifecycleStateMachine, true); - } - - public void disburse(final LocalDate disbursedOn, final LoanLifecycleStateMachine loanLifecycleStateMachine, final boolean statusTransition) { - - if (statusTransition) { - // ensure loan is in pre-disbursal state - updateLoanToPreDisbursalState(); - - LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - } - - this.disbursedOnDate = disbursedOn.toDateTimeAtCurrentTime().toDate(); - this.expectedMaturityDate = this.repaymentScheduleInstallments - .get(this.repaymentScheduleInstallments.size() - 1) - .getDueDate().toDateMidnight().toDate(); - - // add disbursement transaction to track outgoing money from mfi to client - LoanTransaction loanTransaction = LoanTransaction.disbursement(this.loanRepaymentScheduleDetail.getPrincipal(), disbursedOn); - loanTransaction.updateLoan(this); - this.loanTransactions.add(loanTransaction); - - // add repayment transaction to track incoming money from client to mfi for (charges due at time of disbursement) - if (getTotalChargesDueAtDisbursement().isGreaterThanZero()) { - - LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getTotalChargesDueAtDisbursement(), disbursedOn); - Money zero = Money.zero(getCurrency()); - chargesPayment.updateComponents(zero, zero, getTotalChargesDueAtDisbursement(), zero); - chargesPayment.updateLoan(this); - this.loanTransactions.add(chargesPayment); - - for (LoanCharge charge : this.charges) { - if (charge.isDueAtDisbursement()) { - charge.markAsFullyPaid(); - } - } - } - - if (disbursedOn.isBefore(getApprovedOnDate())) { - final String errorMessage = "The date on which a loan is disbursed cannot be before its approval date: " - + getApprovedOnDate().toString(); - throw new InvalidLoanStateTransitionException("disbursal", - "cannot.be.before.approval.date", errorMessage, - disbursedOn, getApprovedOnDate()); - } - - if (disbursedOn.isAfter(new LocalDate())) { - final String errorMessage = "The date on which a loan is disbursed cannot be in the future."; - throw new InvalidLoanStateTransitionException("disbursal", - "cannot.be.a.future.date", errorMessage, disbursedOn); - } - - LocalDate firstRepaymentDueDate = this.repaymentScheduleInstallments.get(0).getDueDate(); - if (disbursedOn.isAfter(firstRepaymentDueDate)) { - final String errorMessage = "The date on which a loan is disbursed cannot be after the first expected repayment date: " - + firstRepaymentDueDate.toString(); - throw new InvalidLoanStateTransitionException("disbursal", - "cannot.be.after.first.repayment.due.date", errorMessage, - disbursedOn, firstRepaymentDueDate); - } - } - - public void undoDisbursal(final LoanLifecycleStateMachine loanLifecycleStateMachine) { - - final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSAL_UNDO, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - - updateLoanToPreDisbursalState(); - } - - private void updateLoanToPreDisbursalState() { - this.loanStatus = LoanStatus.APPROVED.getValue(); - - this.loanTransactions.clear(); - this.disbursedOnDate = null; - - for (LoanCharge charge : this.charges) { - charge.resetToOriginal(loanCurrency()); - } - - for (LoanRepaymentScheduleInstallment currentInstallment : this.repaymentScheduleInstallments) { - currentInstallment.resetDerivedComponents(); - } - - LoanScheduleWrapper wrapper = new LoanScheduleWrapper(); - wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, this.charges); - } - - /** - * - * @param amount The amount of interest to be waived. - * @param transactionDate The date on which the interest waiver is to be processed against. - * @param defaultLoanLifecycleStateMachine - * - * @return {@link LoanTransaction} details of executed transaction - */ - public LoanTransaction waiveInterest( - final BigDecimal amount, - final LocalDate transactionDate, - final LoanLifecycleStateMachine loanLifecycleStateMachine) { - - final Money amountToWaive = Money.of(loanCurrency(), amount); - final LoanTransaction waiveInterestTransaction = LoanTransaction.waiver(this, amountToWaive, transactionDate); - - handleRepaymentOrWaiverTransaction(waiveInterestTransaction, loanLifecycleStateMachine, null); - - return waiveInterestTransaction; - } - - public void makeRepayment(final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine) { - handleRepaymentOrWaiverTransaction(loanTransaction, loanLifecycleStateMachine, null); - } - - private void handleRepaymentOrWaiverTransaction( - final LoanTransaction loanTransaction, - final LoanLifecycleStateMachine loanLifecycleStateMachine, - final LoanTransaction adjustedTransaction) { - - final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - - loanTransaction.updateLoan(this); - - boolean isTransactionChronologicallyLatest = isChronologicallyLatestRepaymentOrWaiver(loanTransaction, this.loanTransactions); - - if (loanTransaction.isNotZero(loanCurrency())) { - this.loanTransactions.add(loanTransaction); - } - - if (loanTransaction.isNotRepayment() && loanTransaction.isNotWaiver()) { - final String errorMessage = "A transaction of type repayment or waiver was expected but not received."; - throw new InvalidLoanTransactionTypeException("transaction", - "is.not.a.repayment.or.waiver.transaction", errorMessage); - } - - LocalDate loanTransactionDate = loanTransaction.getTransactionDate(); - if (loanTransactionDate.isBefore(this.getDisbursementDate())) { - final String errorMessage = "The transaction date cannot be before the loan disbursement date: " - + getApprovedOnDate().toString(); - throw new InvalidLoanStateTransitionException("transaction", - "cannot.be.before.disbursement.date", errorMessage, - loanTransactionDate, this.getDisbursementDate()); - } - - if (loanTransactionDate.isAfter(new LocalDate())) { - final String errorMessage = "The transaction date cannot be in the future."; - throw new InvalidLoanStateTransitionException("transaction", - "cannot.be.a.future.date", errorMessage, loanTransactionDate); - } - - if (loanTransaction.isInterestWaiver()) { - Money totalInterestOutstandingOnLoan = getTotalInterestOutstandingOnLoan(); - if (adjustedTransaction != null) { - totalInterestOutstandingOnLoan = totalInterestOutstandingOnLoan.plus(adjustedTransaction.getAmount()); - } - if (loanTransaction.getAmount(loanCurrency()).isGreaterThan(totalInterestOutstandingOnLoan)) { - final String errorMessage = "The amount of interest to waive cannot be greater than total interest outstanding on loan."; - throw new InvalidLoanStateTransitionException("waive.interest", - "amount.exceeds.total.outstanding.interest", errorMessage, loanTransaction.getAmount(), totalInterestOutstandingOnLoan.getAmount()); - } - } - - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy); - if (isTransactionChronologicallyLatest && adjustedTransaction == null) { - loanRepaymentScheduleTransactionProcessor.handleTransaction(loanTransaction, getCurrency(), this.repaymentScheduleInstallments, this.charges); - } else { - final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); - loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, this.charges); - } - - doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine); - } - - private List retreiveListOfTransactionsPostDisbursement() { - List repaymentsOrWaivers = new ArrayList(); - for (LoanTransaction transaction : this.loanTransactions) { - if (!transaction.isDisbursement() && transaction.isNotContra()) { - repaymentsOrWaivers.add(transaction); - } - } - LoanTransactionComparator transactionComparator = new LoanTransactionComparator(); - Collections.sort(repaymentsOrWaivers, transactionComparator); - return repaymentsOrWaivers; - } - - private void doPostLoanTransactionChecks(final LocalDate transactionDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) { - - if (this.isOverPaid()) { - handleLoanOverpayment(loanLifecycleStateMachine); - } else if (this.isRepaidInFull()) { - // TODO - KW - probably should not close the loan automatically but let user decide if loan is closed or not and provide closing date. - // - need to dig into loan closure scenarios with MFIs - handleLoanRepaymentInFull(transactionDate, loanLifecycleStateMachine); - } - } - - private void handleLoanRepaymentInFull(final LocalDate transactionDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) { - - LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - - this.closedOnDate = transactionDate.toDate(); - this.maturedOnDate = transactionDate.toDate(); - } - - private void handleLoanOverpayment(final LoanLifecycleStateMachine loanLifecycleStateMachine) { - - LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_OVERPAYMENT, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - - this.closedOnDate = null; - this.maturedOnDate = null; - } - - private boolean isChronologicallyLatestRepaymentOrWaiver( - final LoanTransaction loanTransaction, - final List loanTransactions) { - - boolean isChronologicallyLatestRepaymentOrWaiver = true; - - LocalDate currentTransactionDate = loanTransaction.getTransactionDate(); - for (LoanTransaction previousTransaction : loanTransactions) { - if (!previousTransaction.isDisbursement() && previousTransaction.isNotContra()) { - if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate()) || - currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) { - isChronologicallyLatestRepaymentOrWaiver = false; - break; - } - } - } - - return isChronologicallyLatestRepaymentOrWaiver; - } - - private boolean isChronologicallyLatestTransaction( - final LoanTransaction loanTransaction, - final List loanTransactions) { - - boolean isChronologicallyLatestRepaymentOrWaiver = true; - - LocalDate currentTransactionDate = loanTransaction.getTransactionDate(); - for (LoanTransaction previousTransaction : loanTransactions) { - if (previousTransaction.isNotContra()) { - if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate()) || - currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) { - isChronologicallyLatestRepaymentOrWaiver = false; - break; - } - } - } - - return isChronologicallyLatestRepaymentOrWaiver; - } - - public LocalDate possibleNextRepaymentDate() { - LocalDate earliestUnpaidInstallmentDate = new LocalDate(); - for (LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) { - if (installment.isNotFullyCompleted()) { - earliestUnpaidInstallmentDate = installment.getDueDate(); - break; - } - } - - LocalDate lastTransactionDate = null; - for (LoanTransaction transaction : this.loanTransactions) { - if (transaction.isRepayment() && transaction.isNonZero()) { - lastTransactionDate = transaction.getTransactionDate(); - } - } - - LocalDate possibleNextRepaymentDate = earliestUnpaidInstallmentDate; - if (lastTransactionDate != null - && lastTransactionDate.isAfter(earliestUnpaidInstallmentDate)) { - possibleNextRepaymentDate = lastTransactionDate; - } - - return possibleNextRepaymentDate; - } - - public Money possibleNextRepaymentAmount() { - MonetaryCurrency currency = this.loanRepaymentScheduleDetail.getPrincipal().getCurrency(); - Money possibleNextRepaymentAmount = Money.zero(currency); - - for (LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) { - if (installment.isNotFullyCompleted()) { - possibleNextRepaymentAmount = installment.getTotalOutstanding(currency); - break; - } - } - - return possibleNextRepaymentAmount; - } - - public LoanTransaction deriveDefaultInterestWaiverTransaction() { - - final Money totalInterestOutstanding = getTotalInterestOutstandingOnLoan(); - Money possibleInterestToWaive = totalInterestOutstanding.copy(); - LocalDate transactionDate = new LocalDate(); - - if (totalInterestOutstanding.isGreaterThanZero()) { - // find earliest known instance of overdue interest and default to that - for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) { - - final Money outstandingForPeriod = scheduledRepayment.getInterestOutstanding(loanCurrency()); - if (scheduledRepayment.isOverdueOn(new LocalDate()) && scheduledRepayment.isNotFullyCompleted() && outstandingForPeriod.isGreaterThanZero()) { - transactionDate = scheduledRepayment.getDueDate(); - possibleInterestToWaive = outstandingForPeriod; - break; - } - } - } - - return LoanTransaction.waiver(this, possibleInterestToWaive, transactionDate); - } - - public void adjustExistingTransaction( - final LoanTransaction transactionForAdjustment, - final LoanTransaction newTransactionDetail, - final LoanLifecycleStateMachine loanLifecycleStateMachine) { - - if (transactionForAdjustment.isNotRepayment() && transactionForAdjustment.isNotWaiver()) { - final String errorMessage = "Only transactions of type repayment or waiver can be adjusted."; - throw new InvalidLoanTransactionTypeException("transaction", - "adjustment.is.only.allowed.to.repayment.or.waiver.transaction", errorMessage); - } - - if (isClosed()) { - final String errorMessage = "Transactions of a closed loan cannot be adjusted."; - throw new InvalidLoanTransactionTypeException("transaction", - "adjustment.is.not.allowed.on.closed.loan", errorMessage); - } - - transactionForAdjustment.contra(); - if (newTransactionDetail.isRepayment() || newTransactionDetail.isInterestWaiver()) { - handleRepaymentOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine, transactionForAdjustment); - } - } - - private boolean isRepaidInFull() { - - MonetaryCurrency currency = loanCurrency(); - - Money cumulativeOriginalPrincipalExpected = Money.zero(currency); - Money cumulativeOriginalInterestExpected = Money.zero(currency); - Money cumulativeOriginalTotalExpected = Money.zero(currency); - - Money cumulativeTotalPaid = Money.zero(currency); - Money cumulativeTotalWaived = Money.zero(currency); - - for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) { - cumulativeOriginalPrincipalExpected = cumulativeOriginalPrincipalExpected.plus(scheduledRepayment.getPrincipal(currency)); - cumulativeOriginalInterestExpected = cumulativeOriginalInterestExpected.plus(scheduledRepayment.getInterest(currency)); - - cumulativeTotalPaid = cumulativeTotalPaid.plus(scheduledRepayment.getPrincipalCompleted(currency).plus(scheduledRepayment.getInterestCompleted(currency))); - cumulativeTotalWaived = cumulativeTotalWaived.plus(scheduledRepayment.getInterestWaived(currency)); - } - - cumulativeOriginalTotalExpected = cumulativeOriginalPrincipalExpected.plus(cumulativeOriginalInterestExpected); - - Money totalOutstanding = cumulativeOriginalTotalExpected.minus(cumulativeTotalPaid.plus(cumulativeTotalWaived)); - boolean isRepaidInFull = totalOutstanding.isZero(); - - return isRepaidInFull; - } - - private boolean isOverPaid() { - return calculateTotalOverpayment().isGreaterThanZero(); - } - - private Money calculateTotalOverpayment() { - - final Money totalPaidInRepayments = getTotalPaidInRepayments(); - - final MonetaryCurrency currency = loanCurrency(); - Money cumulativeTotalPaidOnInstallments = Money.zero(currency); - Money cumulativeTotalWaivedOnInstallments = Money.zero(currency); - - for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) { - - cumulativeTotalPaidOnInstallments = cumulativeTotalPaidOnInstallments.plus(scheduledRepayment.getPrincipalCompleted(currency) - .plus(scheduledRepayment.getInterestCompleted(currency))) - .plus(scheduledRepayment.getFeeChargesCompleted(currency)) - .plus(scheduledRepayment.getPenaltyChargesCompleted(currency)); - - cumulativeTotalWaivedOnInstallments = cumulativeTotalWaivedOnInstallments.plus(scheduledRepayment.getInterestWaived(currency)); - } - - // if total paid in transactions doesnt match repayment schedule then theres an overpayment. - return totalPaidInRepayments.minus(cumulativeTotalPaidOnInstallments); - } - - private MonetaryCurrency loanCurrency() { - return this.loanRepaymentScheduleDetail.getCurrency(); - } - - public LoanTransaction closeAsWrittenOff( - final LocalDate writtenOffOnLocalDate, - final LoanLifecycleStateMachine loanLifecycleStateMachine) { - - final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - - this.closedOnDate = writtenOffOnLocalDate.toDate(); - this.writtenOffOnDate = writtenOffOnLocalDate.toDate(); - - if (writtenOffOnLocalDate.isBefore(this.getDisbursementDate())) { - final String errorMessage = "The date on which a loan is written off cannot be before the loan disbursement date: " - + getDisbursementDate().toString(); - throw new InvalidLoanStateTransitionException("writeoff", - "cannot.be.before.submittal.date", errorMessage, - writtenOffOnLocalDate, getDisbursementDate()); - } - - if (writtenOffOnLocalDate.isAfter(new LocalDate())) { - final String errorMessage = "The date on which a loan is written off cannot be in the future."; - throw new InvalidLoanStateTransitionException("writeoff", - "cannot.be.a.future.date", errorMessage, - writtenOffOnLocalDate); - } - - final LoanTransaction loanTransaction = LoanTransaction.writeoff(this, writtenOffOnLocalDate); - boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, loanTransactions); - if (!isLastTransaction) { - final String errorMessage = "The date of the writeoff transaction must occur on or before previous transactions."; - throw new InvalidLoanStateTransitionException("writeoff","must.occur.on.or.after.other.transaction.dates", errorMessage, writtenOffOnLocalDate); - } - - this.loanTransactions.add(loanTransaction); - - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy); - loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(), this.repaymentScheduleInstallments); - - return loanTransaction; - } - - public LoanTransaction close( - final LocalDate closureDate, - final LoanLifecycleStateMachine loanLifecycleStateMachine) { - - if (closureDate.isBefore(this.getDisbursementDate())) { - final String errorMessage = "The date on which a loan is closed cannot be before the loan disbursement date: " + getDisbursementDate().toString(); - throw new InvalidLoanStateTransitionException("close","cannot.be.before.submittal.date", errorMessage, closureDate, getDisbursementDate()); - } - - if (closureDate.isAfter(new LocalDate())) { - final String errorMessage = "The date on which a loan is closed cannot be in the future."; - throw new InvalidLoanStateTransitionException("close", "cannot.be.a.future.date", errorMessage, closureDate); - } - - LoanTransaction loanTransaction = null; - if (isOpen()) { - // 1. check total outstanding - final Money outstanding = getTotalOutstanding(); - if (outstanding.isGreaterThanZero() && getInArrearsTolerance().isGreaterThanOrEqualTo(outstanding)) { - - updateLoanForClosure(closureDate, loanLifecycleStateMachine); - - loanTransaction = LoanTransaction.writeoff(this, closureDate); - boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, loanTransactions); - if (!isLastTransaction) { - final String errorMessage = "The closing date of the loan must be on or after latest transaction date."; - throw new InvalidLoanStateTransitionException("close.loan","must.occur.on.or.after.latest.transaction.date", errorMessage, closureDate); - } - - this.loanTransactions.add(loanTransaction); - - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor.determineProcessor(this.transactionProcessingStrategy); - loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(), this.repaymentScheduleInstallments); - - } else if (outstanding.isGreaterThanZero()) { - final String errorMessage = "A loan with money outstanding cannot be closed"; - throw new InvalidLoanStateTransitionException("close", "loan.has.money.outstanding", errorMessage, outstanding.toString()); - } - } - - if (isOverPaid()) { - final Money totalLoanOverpayment = calculateTotalOverpayment(); - // FIXME - kw - use overpaymentTolerance setting when in place on loan product settings. - if (totalLoanOverpayment.isGreaterThanZero() && getInArrearsTolerance().isGreaterThanOrEqualTo(totalLoanOverpayment)) { - // TODO - technically should set somewhere that this loan has 'overpaid' amount - updateLoanForClosure(closureDate, loanLifecycleStateMachine); - } else if (totalLoanOverpayment.isGreaterThanZero()) { - final String errorMessage = "The loan is marked as 'Overpaid' and cannot be moved to 'Closed (obligations met)."; - throw new InvalidLoanStateTransitionException("close", "loan.is.overpaid", errorMessage, totalLoanOverpayment.toString()); - } - } - - return loanTransaction; - } - - private Money getTotalOutstanding() { - Money totalOutstanding = Money.zero(loanCurrency()); - // 1. check totalOutstanding value on loan - - // 2. if null calculate from loan schedule - final LoanScheduleWrapper wrapper = new LoanScheduleWrapper(); - totalOutstanding = wrapper.calculateTotalOutstanding(loanCurrency(), this.repaymentScheduleInstallments); - return totalOutstanding; - } - - private void updateLoanForClosure(final LocalDate closureDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) { - final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - this.closedOnDate = closureDate.toDate(); - } - - /** - * Behaviour added to comply with capability of previous mifos product to support easier transition to mifosx platform. - */ - public void closeAsMarkedForReschedule( - final LocalDate rescheduledOn, - final LoanLifecycleStateMachine loanLifecycleStateMachine) { - - final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_RESCHEDULE, LoanStatus.fromInt(this.loanStatus)); - this.loanStatus = statusEnum.getValue(); - - this.closedOnDate = rescheduledOn.toDate(); - this.rescheduledOnDate = rescheduledOn.toDate(); - - LocalDate rescheduledOnLocalDate = new LocalDate(rescheduledOnDate); - if (rescheduledOnLocalDate.isBefore(this.getDisbursementDate())) { - final String errorMessage = "The date on which a loan is rescheduled cannot be before the loan disbursement date: " - + getDisbursementDate().toString(); - throw new InvalidLoanStateTransitionException("close.reschedule","cannot.be.before.submittal.date", errorMessage, rescheduledOnLocalDate, getDisbursementDate()); - } - - if (rescheduledOnLocalDate.isAfter(new LocalDate())) { - final String errorMessage = "The date on which a loan is rescheduled cannot be in the future."; - throw new InvalidLoanStateTransitionException("close.reschedule", "cannot.be.a.future.date", errorMessage, rescheduledOnLocalDate); - } - } - - public boolean isNotSubmittedAndPendingApproval() { - return !isSubmittedAndPendingApproval(); - } - - private LoanStatus status() { - return LoanStatus.fromInt(this.loanStatus); - } - - public boolean isSubmittedAndPendingApproval() { - return status().isSubmittedAndPendingApproval(); - } - - public boolean isApproved() { - return status().isApproved(); - } - - public boolean isNotApproved() { - return !isApproved(); - } - - public boolean isWaitingForDisbursal() { - return this.isApproved() && this.isNotDisbursed(); - } - - public boolean isNotDisbursed() { - return !this.isDisbursed(); - } - - public boolean isDisbursed() { - return hasDisbursementTransaction(); - } - - public boolean isUndoDisbursalAllowed() { - return isDisbursed() && this.hasNoRepaymentTransaction(); - } - - public boolean isClosed() { - return status().isClosed() || this.isCancelled(); - } - - public boolean isCancelled() { - return this.isRejected() || this.isWithdrawn(); - } - - public boolean isWithdrawn() { - return status().isWithdrawnByClient(); - } - - public boolean isRejected() { - return status().isRejected(); - } - - public boolean isNotClosed() { - return !this.isClosed(); - } - - public boolean isOpen() { - return status().isActive(); - } - - public boolean isOpenWithNoRepaymentMade() { - return this.isOpen() && hasNoRepaymentTransaction(); - } - - private boolean hasNoRepaymentTransaction() { - return !hasRepaymentTransaction(); - } - - private boolean hasRepaymentTransaction() { - boolean hasRepaymentTransaction = false; - for (LoanTransaction loanTransaction : this.loanTransactions) { - if (loanTransaction.isRepayment()) { - hasRepaymentTransaction = true; - break; - } - } - return hasRepaymentTransaction; - } - - private boolean hasDisbursementTransaction() { - boolean hasRepaymentTransaction = false; - for (LoanTransaction loanTransaction : this.loanTransactions) { - if (loanTransaction.isDisbursement()) { - hasRepaymentTransaction = true; - break; - } - } - return hasRepaymentTransaction; - } - - public boolean isOpenWithRepaymentMade() { - return this.isOpen() && this.hasRepaymentTransaction(); - } - - public List getRepaymentScheduleInstallments() { - return this.repaymentScheduleInstallments; - } - - public String getExternalId() { - return this.externalId; - } - - public void setExternalId(final String externalSystemIdentifer) { - if (StringUtils.isNotBlank(externalSystemIdentifer)) { - this.externalId = externalSystemIdentifer.trim(); - } else { - this.externalId = null; - } - } - - public LocalDate getSubmittedOnDate() { - return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate( - this.submittedOnDate), null); - } - - public LocalDate getRejectedOnDate() { - return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate( - this.rejectedOnDate), null); - } - - public LocalDate getApprovedOnDate() { - LocalDate date = null; - if (this.approvedOnDate != null) { - date = new LocalDate(this.approvedOnDate); - } - return date; - } - - public LocalDate getDisbursedOnDate() { - LocalDate date = null; - if (this.disbursedOnDate != null) { - date = new LocalDate(this.disbursedOnDate); - } - return date; - } - - public LocalDate getClosedOnDate() { - LocalDate date = null; - if (this.closedOnDate != null) { - date = new LocalDate(this.closedOnDate); - } - return date; - } - - public LocalDate getWrittenOffOnDate() { - LocalDate date = null; - if (this.writtenOffOnDate != null) { - date = new LocalDate(this.writtenOffOnDate); - } - return date; - } - - public Date getExpectedDisbursedOnDate() { - return this.expectedDisbursedOnDate; - } - - public LocalDate getExpectedDisbursedOnLocalDate() { - LocalDate expectedDisbursementDate = null; - if (this.expectedDisbursedOnDate != null) { - expectedDisbursementDate = new LocalDate( - this.expectedDisbursedOnDate); - } - return expectedDisbursementDate; - } - - public LocalDate getExpectedFirstRepaymentOnDate() { - LocalDate firstRepaymentDate = null; - if (this.expectedFirstRepaymentOnDate != null) { - firstRepaymentDate = new LocalDate( - this.expectedFirstRepaymentOnDate); - } - return firstRepaymentDate; - } - - public LocalDate getDisbursementDate() { - LocalDate disbursementDate = getExpectedDisbursedOnLocalDate(); - if (this.disbursedOnDate != null) { - disbursementDate = new LocalDate(this.disbursedOnDate); - } - return disbursementDate; - } - - public LocalDate getExpectedMaturityDate() { - LocalDate possibleMaturityDate = null; - if (this.expectedMaturityDate != null) { - possibleMaturityDate = new LocalDate(this.expectedMaturityDate); - } - return possibleMaturityDate; - } - - public LocalDate getActualMaturityDate() { - LocalDate possibleMaturityDate = null; - if (this.maturedOnDate != null) { - possibleMaturityDate = new LocalDate(this.maturedOnDate); - } - return possibleMaturityDate; - } - - public LocalDate getMaturityDate() { - LocalDate possibleMaturityDate = null; - - if (this.expectedMaturityDate != null) { - possibleMaturityDate = new LocalDate(this.expectedMaturityDate); - } - if (this.maturedOnDate != null) { - possibleMaturityDate = new LocalDate(this.maturedOnDate); - } - return possibleMaturityDate; - } + } + + public void disburseWithModifiedRepaymentSchedule(final LocalDate disbursedOn, + final List modifiedLoanRepaymentSchedule, LoanLifecycleStateMachine loanLifecycleStateMachine) { + this.repaymentScheduleInstallments.clear(); + for (LoanRepaymentScheduleInstallment modifiedInstallment : modifiedLoanRepaymentSchedule) { + modifiedInstallment.updateLoan(this); + this.repaymentScheduleInstallments.add(modifiedInstallment); + } + disburse(disbursedOn, loanLifecycleStateMachine, true); + } + + public void disburse(final LocalDate disbursedOn, final LoanLifecycleStateMachine loanLifecycleStateMachine, + final boolean statusTransition) { + + if (statusTransition) { + // ensure loan is in pre-disbursal state + updateLoanToPreDisbursalState(); + + LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + } + + this.disbursedOnDate = disbursedOn.toDateTimeAtCurrentTime().toDate(); + this.expectedMaturityDate = this.repaymentScheduleInstallments.get(this.repaymentScheduleInstallments.size() - 1).getDueDate() + .toDateMidnight().toDate(); + + // add disbursement transaction to track outgoing money from mfi to + // client + LoanTransaction loanTransaction = LoanTransaction.disbursement(this.loanRepaymentScheduleDetail.getPrincipal(), disbursedOn); + loanTransaction.updateLoan(this); + this.loanTransactions.add(loanTransaction); + + // add repayment transaction to track incoming money from client to mfi + // for (charges due at time of disbursement) + if (getTotalChargesDueAtDisbursement().isGreaterThanZero()) { + + LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getTotalChargesDueAtDisbursement(), disbursedOn); + Money zero = Money.zero(getCurrency()); + chargesPayment.updateComponents(zero, zero, getTotalChargesDueAtDisbursement(), zero); + chargesPayment.updateLoan(this); + this.loanTransactions.add(chargesPayment); + + for (LoanCharge charge : this.charges) { + if (charge.isDueAtDisbursement()) { + charge.markAsFullyPaid(); + } + } + } + + if (disbursedOn.isBefore(getApprovedOnDate())) { + final String errorMessage = "The date on which a loan is disbursed cannot be before its approval date: " + + getApprovedOnDate().toString(); + throw new InvalidLoanStateTransitionException("disbursal", "cannot.be.before.approval.date", errorMessage, disbursedOn, + getApprovedOnDate()); + } + + if (disbursedOn.isAfter(new LocalDate())) { + final String errorMessage = "The date on which a loan is disbursed cannot be in the future."; + throw new InvalidLoanStateTransitionException("disbursal", "cannot.be.a.future.date", errorMessage, disbursedOn); + } + + LocalDate firstRepaymentDueDate = this.repaymentScheduleInstallments.get(0).getDueDate(); + if (disbursedOn.isAfter(firstRepaymentDueDate)) { + final String errorMessage = "The date on which a loan is disbursed cannot be after the first expected repayment date: " + + firstRepaymentDueDate.toString(); + throw new InvalidLoanStateTransitionException("disbursal", "cannot.be.after.first.repayment.due.date", errorMessage, + disbursedOn, firstRepaymentDueDate); + } + } + + public void undoDisbursal(final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSAL_UNDO, + LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + + updateLoanToPreDisbursalState(); + } + + private void updateLoanToPreDisbursalState() { + this.loanStatus = LoanStatus.APPROVED.getValue(); + + this.loanTransactions.clear(); + this.disbursedOnDate = null; + + for (LoanCharge charge : this.charges) { + charge.resetToOriginal(loanCurrency()); + } + + for (LoanRepaymentScheduleInstallment currentInstallment : this.repaymentScheduleInstallments) { + currentInstallment.resetDerivedComponents(); + } + + LoanScheduleWrapper wrapper = new LoanScheduleWrapper(); + wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, this.charges); + } + + /** + * + * @param amount + * The amount of interest to be waived. + * @param transactionDate + * The date on which the interest waiver is to be processed + * against. + * @param defaultLoanLifecycleStateMachine + * + * @return {@link LoanTransaction} details of executed transaction + */ + public LoanTransaction waiveInterest(final BigDecimal amount, final LocalDate transactionDate, + final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + final Money amountToWaive = Money.of(loanCurrency(), amount); + final LoanTransaction waiveInterestTransaction = LoanTransaction.waiver(this, amountToWaive, transactionDate); + + handleRepaymentOrWaiverTransaction(waiveInterestTransaction, loanLifecycleStateMachine, null); + + return waiveInterestTransaction; + } + + public void makeRepayment(final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + handleRepaymentOrWaiverTransaction(loanTransaction, loanLifecycleStateMachine, null); + } + + private void handleRepaymentOrWaiverTransaction(final LoanTransaction loanTransaction, + final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction adjustedTransaction) { + + final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, + LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + + loanTransaction.updateLoan(this); + + boolean isTransactionChronologicallyLatest = isChronologicallyLatestRepaymentOrWaiver(loanTransaction, this.loanTransactions); + + if (loanTransaction.isNotZero(loanCurrency())) { + this.loanTransactions.add(loanTransaction); + } + + if (loanTransaction.isNotRepayment() && loanTransaction.isNotWaiver()) { + final String errorMessage = "A transaction of type repayment or waiver was expected but not received."; + throw new InvalidLoanTransactionTypeException("transaction", "is.not.a.repayment.or.waiver.transaction", errorMessage); + } + + LocalDate loanTransactionDate = loanTransaction.getTransactionDate(); + if (loanTransactionDate.isBefore(this.getDisbursementDate())) { + final String errorMessage = "The transaction date cannot be before the loan disbursement date: " + + getApprovedOnDate().toString(); + throw new InvalidLoanStateTransitionException("transaction", "cannot.be.before.disbursement.date", errorMessage, + loanTransactionDate, this.getDisbursementDate()); + } + + if (loanTransactionDate.isAfter(new LocalDate())) { + final String errorMessage = "The transaction date cannot be in the future."; + throw new InvalidLoanStateTransitionException("transaction", "cannot.be.a.future.date", errorMessage, loanTransactionDate); + } + + if (loanTransaction.isInterestWaiver()) { + Money totalInterestOutstandingOnLoan = getTotalInterestOutstandingOnLoan(); + if (adjustedTransaction != null) { + totalInterestOutstandingOnLoan = totalInterestOutstandingOnLoan.plus(adjustedTransaction.getAmount()); + } + if (loanTransaction.getAmount(loanCurrency()).isGreaterThan(totalInterestOutstandingOnLoan)) { + final String errorMessage = "The amount of interest to waive cannot be greater than total interest outstanding on loan."; + throw new InvalidLoanStateTransitionException("waive.interest", "amount.exceeds.total.outstanding.interest", errorMessage, + loanTransaction.getAmount(), totalInterestOutstandingOnLoan.getAmount()); + } + } + + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor + .determineProcessor(this.transactionProcessingStrategy); + if (isTransactionChronologicallyLatest && adjustedTransaction == null) { + loanRepaymentScheduleTransactionProcessor.handleTransaction(loanTransaction, getCurrency(), this.repaymentScheduleInstallments, + this.charges); + } else { + final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); + loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement, + getCurrency(), this.repaymentScheduleInstallments, this.charges); + } + + doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine); + } + + private List retreiveListOfTransactionsPostDisbursement() { + List repaymentsOrWaivers = new ArrayList(); + for (LoanTransaction transaction : this.loanTransactions) { + if (!transaction.isDisbursement() && transaction.isNotContra()) { + repaymentsOrWaivers.add(transaction); + } + } + LoanTransactionComparator transactionComparator = new LoanTransactionComparator(); + Collections.sort(repaymentsOrWaivers, transactionComparator); + return repaymentsOrWaivers; + } + + private void doPostLoanTransactionChecks(final LocalDate transactionDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + if (this.isOverPaid()) { + handleLoanOverpayment(loanLifecycleStateMachine); + } else if (this.isRepaidInFull()) { + // TODO - KW - probably should not close the loan automatically but + // let user decide if loan is closed or not and provide closing + // date. + // - need to dig into loan closure scenarios with MFIs + handleLoanRepaymentInFull(transactionDate, loanLifecycleStateMachine); + } + } + + private void handleLoanRepaymentInFull(final LocalDate transactionDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + + this.closedOnDate = transactionDate.toDate(); + this.maturedOnDate = transactionDate.toDate(); + } + + private void handleLoanOverpayment(final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_OVERPAYMENT, LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + + this.closedOnDate = null; + this.maturedOnDate = null; + } + + private boolean isChronologicallyLatestRepaymentOrWaiver(final LoanTransaction loanTransaction, + final List loanTransactions) { + + boolean isChronologicallyLatestRepaymentOrWaiver = true; + + LocalDate currentTransactionDate = loanTransaction.getTransactionDate(); + for (LoanTransaction previousTransaction : loanTransactions) { + if (!previousTransaction.isDisbursement() && previousTransaction.isNotContra()) { + if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate()) + || currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) { + isChronologicallyLatestRepaymentOrWaiver = false; + break; + } + } + } + + return isChronologicallyLatestRepaymentOrWaiver; + } + + private boolean isChronologicallyLatestTransaction(final LoanTransaction loanTransaction, final List loanTransactions) { + + boolean isChronologicallyLatestRepaymentOrWaiver = true; + + LocalDate currentTransactionDate = loanTransaction.getTransactionDate(); + for (LoanTransaction previousTransaction : loanTransactions) { + if (previousTransaction.isNotContra()) { + if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate()) + || currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) { + isChronologicallyLatestRepaymentOrWaiver = false; + break; + } + } + } + + return isChronologicallyLatestRepaymentOrWaiver; + } + + public LocalDate possibleNextRepaymentDate() { + LocalDate earliestUnpaidInstallmentDate = new LocalDate(); + for (LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) { + if (installment.isNotFullyCompleted()) { + earliestUnpaidInstallmentDate = installment.getDueDate(); + break; + } + } + + LocalDate lastTransactionDate = null; + for (LoanTransaction transaction : this.loanTransactions) { + if (transaction.isRepayment() && transaction.isNonZero()) { + lastTransactionDate = transaction.getTransactionDate(); + } + } + + LocalDate possibleNextRepaymentDate = earliestUnpaidInstallmentDate; + if (lastTransactionDate != null && lastTransactionDate.isAfter(earliestUnpaidInstallmentDate)) { + possibleNextRepaymentDate = lastTransactionDate; + } + + return possibleNextRepaymentDate; + } + + public Money possibleNextRepaymentAmount() { + MonetaryCurrency currency = this.loanRepaymentScheduleDetail.getPrincipal().getCurrency(); + Money possibleNextRepaymentAmount = Money.zero(currency); + + for (LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) { + if (installment.isNotFullyCompleted()) { + possibleNextRepaymentAmount = installment.getTotalOutstanding(currency); + break; + } + } + + return possibleNextRepaymentAmount; + } + + public LoanTransaction deriveDefaultInterestWaiverTransaction() { + + final Money totalInterestOutstanding = getTotalInterestOutstandingOnLoan(); + Money possibleInterestToWaive = totalInterestOutstanding.copy(); + LocalDate transactionDate = new LocalDate(); + + if (totalInterestOutstanding.isGreaterThanZero()) { + // find earliest known instance of overdue interest and default to + // that + for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) { + + final Money outstandingForPeriod = scheduledRepayment.getInterestOutstanding(loanCurrency()); + if (scheduledRepayment.isOverdueOn(new LocalDate()) && scheduledRepayment.isNotFullyCompleted() + && outstandingForPeriod.isGreaterThanZero()) { + transactionDate = scheduledRepayment.getDueDate(); + possibleInterestToWaive = outstandingForPeriod; + break; + } + } + } + + return LoanTransaction.waiver(this, possibleInterestToWaive, transactionDate); + } + + public void adjustExistingTransaction(final LoanTransaction transactionForAdjustment, final LoanTransaction newTransactionDetail, + final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + if (transactionForAdjustment.isNotRepayment() && transactionForAdjustment.isNotWaiver()) { + final String errorMessage = "Only transactions of type repayment or waiver can be adjusted."; + throw new InvalidLoanTransactionTypeException("transaction", "adjustment.is.only.allowed.to.repayment.or.waiver.transaction", + errorMessage); + } + + if (isClosed()) { + final String errorMessage = "Transactions of a closed loan cannot be adjusted."; + throw new InvalidLoanTransactionTypeException("transaction", "adjustment.is.not.allowed.on.closed.loan", errorMessage); + } + + transactionForAdjustment.contra(); + if (newTransactionDetail.isRepayment() || newTransactionDetail.isInterestWaiver()) { + handleRepaymentOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine, transactionForAdjustment); + } + } + + private boolean isRepaidInFull() { + + MonetaryCurrency currency = loanCurrency(); + + Money cumulativeOriginalPrincipalExpected = Money.zero(currency); + Money cumulativeOriginalInterestExpected = Money.zero(currency); + Money cumulativeOriginalTotalExpected = Money.zero(currency); + + Money cumulativeTotalPaid = Money.zero(currency); + Money cumulativeTotalWaived = Money.zero(currency); + + for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) { + cumulativeOriginalPrincipalExpected = cumulativeOriginalPrincipalExpected.plus(scheduledRepayment.getPrincipal(currency)); + cumulativeOriginalInterestExpected = cumulativeOriginalInterestExpected.plus(scheduledRepayment.getInterest(currency)); + + cumulativeTotalPaid = cumulativeTotalPaid.plus(scheduledRepayment.getPrincipalCompleted(currency).plus( + scheduledRepayment.getInterestCompleted(currency))); + cumulativeTotalWaived = cumulativeTotalWaived.plus(scheduledRepayment.getInterestWaived(currency)); + } + + cumulativeOriginalTotalExpected = cumulativeOriginalPrincipalExpected.plus(cumulativeOriginalInterestExpected); + + Money totalOutstanding = cumulativeOriginalTotalExpected.minus(cumulativeTotalPaid.plus(cumulativeTotalWaived)); + boolean isRepaidInFull = totalOutstanding.isZero(); + + return isRepaidInFull; + } + + private boolean isOverPaid() { + return calculateTotalOverpayment().isGreaterThanZero(); + } + + private Money calculateTotalOverpayment() { + + final Money totalPaidInRepayments = getTotalPaidInRepayments(); + + final MonetaryCurrency currency = loanCurrency(); + Money cumulativeTotalPaidOnInstallments = Money.zero(currency); + Money cumulativeTotalWaivedOnInstallments = Money.zero(currency); + + for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) { + + cumulativeTotalPaidOnInstallments = cumulativeTotalPaidOnInstallments + .plus(scheduledRepayment.getPrincipalCompleted(currency).plus(scheduledRepayment.getInterestCompleted(currency))) + .plus(scheduledRepayment.getFeeChargesCompleted(currency)) + .plus(scheduledRepayment.getPenaltyChargesCompleted(currency)); + + cumulativeTotalWaivedOnInstallments = cumulativeTotalWaivedOnInstallments.plus(scheduledRepayment.getInterestWaived(currency)); + } + + // if total paid in transactions doesnt match repayment schedule then + // theres an overpayment. + return totalPaidInRepayments.minus(cumulativeTotalPaidOnInstallments); + } + + private MonetaryCurrency loanCurrency() { + return this.loanRepaymentScheduleDetail.getCurrency(); + } + + public LoanTransaction closeAsWrittenOff(final LocalDate writtenOffOnLocalDate, + final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING, + LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + + this.closedOnDate = writtenOffOnLocalDate.toDate(); + this.writtenOffOnDate = writtenOffOnLocalDate.toDate(); + + if (writtenOffOnLocalDate.isBefore(this.getDisbursementDate())) { + final String errorMessage = "The date on which a loan is written off cannot be before the loan disbursement date: " + + getDisbursementDate().toString(); + throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.before.submittal.date", errorMessage, + writtenOffOnLocalDate, getDisbursementDate()); + } + + if (writtenOffOnLocalDate.isAfter(new LocalDate())) { + final String errorMessage = "The date on which a loan is written off cannot be in the future."; + throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.a.future.date", errorMessage, writtenOffOnLocalDate); + } + + final LoanTransaction loanTransaction = LoanTransaction.writeoff(this, writtenOffOnLocalDate); + boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, loanTransactions); + if (!isLastTransaction) { + final String errorMessage = "The date of the writeoff transaction must occur on or before previous transactions."; + throw new InvalidLoanStateTransitionException("writeoff", "must.occur.on.or.after.other.transaction.dates", errorMessage, + writtenOffOnLocalDate); + } + + this.loanTransactions.add(loanTransaction); + + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor + .determineProcessor(this.transactionProcessingStrategy); + loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(), this.repaymentScheduleInstallments); + + return loanTransaction; + } + + public LoanTransaction close(final LocalDate closureDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + if (closureDate.isBefore(this.getDisbursementDate())) { + final String errorMessage = "The date on which a loan is closed cannot be before the loan disbursement date: " + + getDisbursementDate().toString(); + throw new InvalidLoanStateTransitionException("close", "cannot.be.before.submittal.date", errorMessage, closureDate, + getDisbursementDate()); + } + + if (closureDate.isAfter(new LocalDate())) { + final String errorMessage = "The date on which a loan is closed cannot be in the future."; + throw new InvalidLoanStateTransitionException("close", "cannot.be.a.future.date", errorMessage, closureDate); + } + + LoanTransaction loanTransaction = null; + if (isOpen()) { + // 1. check total outstanding + final Money outstanding = getTotalOutstanding(); + if (outstanding.isGreaterThanZero() && getInArrearsTolerance().isGreaterThanOrEqualTo(outstanding)) { + + updateLoanForClosure(closureDate, loanLifecycleStateMachine); + + loanTransaction = LoanTransaction.writeoff(this, closureDate); + boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, loanTransactions); + if (!isLastTransaction) { + final String errorMessage = "The closing date of the loan must be on or after latest transaction date."; + throw new InvalidLoanStateTransitionException("close.loan", "must.occur.on.or.after.latest.transaction.date", + errorMessage, closureDate); + } + + this.loanTransactions.add(loanTransaction); + + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessor + .determineProcessor(this.transactionProcessingStrategy); + loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(), + this.repaymentScheduleInstallments); + + } else if (outstanding.isGreaterThanZero()) { + final String errorMessage = "A loan with money outstanding cannot be closed"; + throw new InvalidLoanStateTransitionException("close", "loan.has.money.outstanding", errorMessage, outstanding.toString()); + } + } + + if (isOverPaid()) { + final Money totalLoanOverpayment = calculateTotalOverpayment(); + // FIXME - kw - use overpaymentTolerance setting when in place on + // loan product settings. + if (totalLoanOverpayment.isGreaterThanZero() && getInArrearsTolerance().isGreaterThanOrEqualTo(totalLoanOverpayment)) { + // TODO - technically should set somewhere that this loan has + // 'overpaid' amount + updateLoanForClosure(closureDate, loanLifecycleStateMachine); + } else if (totalLoanOverpayment.isGreaterThanZero()) { + final String errorMessage = "The loan is marked as 'Overpaid' and cannot be moved to 'Closed (obligations met)."; + throw new InvalidLoanStateTransitionException("close", "loan.is.overpaid", errorMessage, totalLoanOverpayment.toString()); + } + } + + return loanTransaction; + } + + private Money getTotalOutstanding() { + Money totalOutstanding = Money.zero(loanCurrency()); + // 1. check totalOutstanding value on loan + + // 2. if null calculate from loan schedule + final LoanScheduleWrapper wrapper = new LoanScheduleWrapper(); + totalOutstanding = wrapper.calculateTotalOutstanding(loanCurrency(), this.repaymentScheduleInstallments); + return totalOutstanding; + } + + private void updateLoanForClosure(final LocalDate closureDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + this.closedOnDate = closureDate.toDate(); + } + + /** + * Behaviour added to comply with capability of previous mifos product to + * support easier transition to mifosx platform. + */ + public void closeAsMarkedForReschedule(final LocalDate rescheduledOn, final LoanLifecycleStateMachine loanLifecycleStateMachine) { + + final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_RESCHEDULE, LoanStatus.fromInt(this.loanStatus)); + this.loanStatus = statusEnum.getValue(); + + this.closedOnDate = rescheduledOn.toDate(); + this.rescheduledOnDate = rescheduledOn.toDate(); + + LocalDate rescheduledOnLocalDate = new LocalDate(rescheduledOnDate); + if (rescheduledOnLocalDate.isBefore(this.getDisbursementDate())) { + final String errorMessage = "The date on which a loan is rescheduled cannot be before the loan disbursement date: " + + getDisbursementDate().toString(); + throw new InvalidLoanStateTransitionException("close.reschedule", "cannot.be.before.submittal.date", errorMessage, + rescheduledOnLocalDate, getDisbursementDate()); + } + + if (rescheduledOnLocalDate.isAfter(new LocalDate())) { + final String errorMessage = "The date on which a loan is rescheduled cannot be in the future."; + throw new InvalidLoanStateTransitionException("close.reschedule", "cannot.be.a.future.date", errorMessage, + rescheduledOnLocalDate); + } + } + + public boolean isNotSubmittedAndPendingApproval() { + return !isSubmittedAndPendingApproval(); + } + + private LoanStatus status() { + return LoanStatus.fromInt(this.loanStatus); + } + + public boolean isSubmittedAndPendingApproval() { + return status().isSubmittedAndPendingApproval(); + } + + public boolean isApproved() { + return status().isApproved(); + } + + public boolean isNotApproved() { + return !isApproved(); + } + + public boolean isWaitingForDisbursal() { + return this.isApproved() && this.isNotDisbursed(); + } + + public boolean isNotDisbursed() { + return !this.isDisbursed(); + } + + public boolean isDisbursed() { + return hasDisbursementTransaction(); + } + + public boolean isUndoDisbursalAllowed() { + return isDisbursed() && this.hasNoRepaymentTransaction(); + } + + public boolean isClosed() { + return status().isClosed() || this.isCancelled(); + } + + public boolean isCancelled() { + return this.isRejected() || this.isWithdrawn(); + } + + public boolean isWithdrawn() { + return status().isWithdrawnByClient(); + } + + public boolean isRejected() { + return status().isRejected(); + } + + public boolean isNotClosed() { + return !this.isClosed(); + } + + public boolean isOpen() { + return status().isActive(); + } + + public boolean isOpenWithNoRepaymentMade() { + return this.isOpen() && hasNoRepaymentTransaction(); + } + + private boolean hasNoRepaymentTransaction() { + return !hasRepaymentTransaction(); + } + + private boolean hasRepaymentTransaction() { + boolean hasRepaymentTransaction = false; + for (LoanTransaction loanTransaction : this.loanTransactions) { + if (loanTransaction.isRepayment()) { + hasRepaymentTransaction = true; + break; + } + } + return hasRepaymentTransaction; + } + + private boolean hasDisbursementTransaction() { + boolean hasRepaymentTransaction = false; + for (LoanTransaction loanTransaction : this.loanTransactions) { + if (loanTransaction.isDisbursement()) { + hasRepaymentTransaction = true; + break; + } + } + return hasRepaymentTransaction; + } + + public boolean isOpenWithRepaymentMade() { + return this.isOpen() && this.hasRepaymentTransaction(); + } + + public List getRepaymentScheduleInstallments() { + return this.repaymentScheduleInstallments; + } + + public String getExternalId() { + return this.externalId; + } + + public void setExternalId(final String externalSystemIdentifer) { + if (StringUtils.isNotBlank(externalSystemIdentifer)) { + this.externalId = externalSystemIdentifer.trim(); + } else { + this.externalId = null; + } + } + + public LocalDate getSubmittedOnDate() { + return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.submittedOnDate), null); + } + + public LocalDate getRejectedOnDate() { + return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.rejectedOnDate), null); + } + + public LocalDate getApprovedOnDate() { + LocalDate date = null; + if (this.approvedOnDate != null) { + date = new LocalDate(this.approvedOnDate); + } + return date; + } + + public LocalDate getDisbursedOnDate() { + LocalDate date = null; + if (this.disbursedOnDate != null) { + date = new LocalDate(this.disbursedOnDate); + } + return date; + } + + public LocalDate getClosedOnDate() { + LocalDate date = null; + if (this.closedOnDate != null) { + date = new LocalDate(this.closedOnDate); + } + return date; + } + + public LocalDate getWrittenOffOnDate() { + LocalDate date = null; + if (this.writtenOffOnDate != null) { + date = new LocalDate(this.writtenOffOnDate); + } + return date; + } + + public Date getExpectedDisbursedOnDate() { + return this.expectedDisbursedOnDate; + } + + public LocalDate getExpectedDisbursedOnLocalDate() { + LocalDate expectedDisbursementDate = null; + if (this.expectedDisbursedOnDate != null) { + expectedDisbursementDate = new LocalDate(this.expectedDisbursedOnDate); + } + return expectedDisbursementDate; + } + + public LocalDate getExpectedFirstRepaymentOnDate() { + LocalDate firstRepaymentDate = null; + if (this.expectedFirstRepaymentOnDate != null) { + firstRepaymentDate = new LocalDate(this.expectedFirstRepaymentOnDate); + } + return firstRepaymentDate; + } + + public LocalDate getDisbursementDate() { + LocalDate disbursementDate = getExpectedDisbursedOnLocalDate(); + if (this.disbursedOnDate != null) { + disbursementDate = new LocalDate(this.disbursedOnDate); + } + return disbursementDate; + } + + public LocalDate getExpectedMaturityDate() { + LocalDate possibleMaturityDate = null; + if (this.expectedMaturityDate != null) { + possibleMaturityDate = new LocalDate(this.expectedMaturityDate); + } + return possibleMaturityDate; + } + + public LocalDate getActualMaturityDate() { + LocalDate possibleMaturityDate = null; + if (this.maturedOnDate != null) { + possibleMaturityDate = new LocalDate(this.maturedOnDate); + } + return possibleMaturityDate; + } + + public LocalDate getMaturityDate() { + LocalDate possibleMaturityDate = null; + + if (this.expectedMaturityDate != null) { + possibleMaturityDate = new LocalDate(this.expectedMaturityDate); + } + if (this.maturedOnDate != null) { + possibleMaturityDate = new LocalDate(this.maturedOnDate); + } + return possibleMaturityDate; + } public Set getCharges() { return charges; @@ -1471,183 +1479,181 @@ public class Loan extends AbstractAuditableCustom { this.charges = charges; } - public void addRepaymentScheduleInstallment( - final LoanRepaymentScheduleInstallment installment) { - installment.updateLoan(this); - this.repaymentScheduleInstallments.add(installment); - } + public void addRepaymentScheduleInstallment(final LoanRepaymentScheduleInstallment installment) { + installment.updateLoan(this); + this.repaymentScheduleInstallments.add(installment); + } - public boolean isActualDisbursedOnDateEarlierOrLaterThanExpected(final LocalDate actualDisbursedOnDate) { - return !new LocalDate(this.expectedDisbursedOnDate) - .isEqual(actualDisbursedOnDate); - } + public boolean isActualDisbursedOnDateEarlierOrLaterThanExpected(final LocalDate actualDisbursedOnDate) { + return !new LocalDate(this.expectedDisbursedOnDate).isEqual(actualDisbursedOnDate); + } - public boolean isRepaymentScheduleRegenerationRequiredForDisbursement( - final LocalDate actualDisbursementDate) { + public boolean isRepaymentScheduleRegenerationRequiredForDisbursement(final LocalDate actualDisbursementDate) { - boolean regenerationRequired = false; + boolean regenerationRequired = false; - if (isActualDisbursedOnDateEarlierOrLaterThanExpected(actualDisbursementDate)) { - regenerationRequired = true; - } + if (isActualDisbursedOnDateEarlierOrLaterThanExpected(actualDisbursementDate)) { + regenerationRequired = true; + } - return regenerationRequired; - } + return regenerationRequired; + } - private Money getTotalPaidInRepayments() { - Money cumulativePaid = Money.zero(this.loanRepaymentScheduleDetail.getPrincipal().getCurrency()); + private Money getTotalPaidInRepayments() { + Money cumulativePaid = Money.zero(this.loanRepaymentScheduleDetail.getPrincipal().getCurrency()); - for (LoanTransaction repayment : this.loanTransactions) { - if (repayment.isRepayment()) { - cumulativePaid = cumulativePaid.plus(repayment.getAmount()); - } - } + for (LoanTransaction repayment : this.loanTransactions) { + if (repayment.isRepayment()) { + cumulativePaid = cumulativePaid.plus(repayment.getAmount()); + } + } - return cumulativePaid; - } + return cumulativePaid; + } - private Money getTotalInterestOutstandingOnLoan() { - Money cumulativeInterest = Money.zero(loanCurrency()); + private Money getTotalInterestOutstandingOnLoan() { + Money cumulativeInterest = Money.zero(loanCurrency()); - for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) { - cumulativeInterest = cumulativeInterest.plus(scheduledRepayment.getInterestOutstanding(loanCurrency())); - } + for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) { + cumulativeInterest = cumulativeInterest.plus(scheduledRepayment.getInterestOutstanding(loanCurrency())); + } - return cumulativeInterest; - } - - @SuppressWarnings("unused") - private Money getTotalInterestOverdueOnLoan() { - Money cumulativeInterestOverdue = Money.zero(this.loanRepaymentScheduleDetail.getPrincipal().getCurrency()); + return cumulativeInterest; + } - for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) { - - final Money interestOutstandingForPeriod = scheduledRepayment.getInterestOutstanding(loanCurrency()); - if (scheduledRepayment.isOverdueOn(new LocalDate())) { - cumulativeInterestOverdue = cumulativeInterestOverdue.plus(interestOutstandingForPeriod); - } - } + @SuppressWarnings("unused") + private Money getTotalInterestOverdueOnLoan() { + Money cumulativeInterestOverdue = Money.zero(this.loanRepaymentScheduleDetail.getPrincipal().getCurrency()); - return cumulativeInterestOverdue; - } + for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) { - private Money getInArrearsTolerance() { - return this.loanRepaymentScheduleDetail.getInArrearsTolerance(); - } + final Money interestOutstandingForPeriod = scheduledRepayment.getInterestOutstanding(loanCurrency()); + if (scheduledRepayment.isOverdueOn(new LocalDate())) { + cumulativeInterestOverdue = cumulativeInterestOverdue.plus(interestOutstandingForPeriod); + } + } - public boolean identifiedBy(String identifier) { - return identifier.equalsIgnoreCase(this.externalId) - || identifier.equalsIgnoreCase(this.getId().toString()); - } - - public boolean hasIdentifyOf(final Long loanId) { - return loanId.equals(this.getId()); - } - - public boolean hasLoanOfficer(final Staff fromLoanOfficer) { - - boolean matchesCurrentLoanOfficer = false; - if (this.loanofficer != null) { - matchesCurrentLoanOfficer = this.loanofficer.identifiedBy(fromLoanOfficer); - } else { - matchesCurrentLoanOfficer = fromLoanOfficer == null; - } - - return matchesCurrentLoanOfficer; - } + return cumulativeInterestOverdue; + } - public LocalDate getInterestChargedFromDate() { - LocalDate interestChargedFrom = null; - if (this.interestChargedFromDate != null) { - interestChargedFrom = new LocalDate(this.interestChargedFromDate); - } - return interestChargedFrom; - } + private Money getInArrearsTolerance() { + return this.loanRepaymentScheduleDetail.getInArrearsTolerance(); + } - public LocalDate getLoanStatusSinceDate() { + public boolean identifiedBy(String identifier) { + return identifier.equalsIgnoreCase(this.externalId) || identifier.equalsIgnoreCase(this.getId().toString()); + } - LocalDate statusSinceDate = getSubmittedOnDate(); - if (isApproved()) { - statusSinceDate = new LocalDate(this.approvedOnDate); - } + public boolean hasIdentifyOf(final Long loanId) { + return loanId.equals(this.getId()); + } - if (isDisbursed()) { - statusSinceDate = new LocalDate(this.disbursedOnDate); - } + public boolean hasLoanOfficer(final Staff fromLoanOfficer) { - if (isClosed()) { - statusSinceDate = new LocalDate(this.closedOnDate); - } + boolean matchesCurrentLoanOfficer = false; + if (this.loanofficer != null) { + matchesCurrentLoanOfficer = this.loanofficer.identifiedBy(fromLoanOfficer); + } else { + matchesCurrentLoanOfficer = fromLoanOfficer == null; + } - return statusSinceDate; - } + return matchesCurrentLoanOfficer; + } - public Money getPrincpal() { - return this.loanRepaymentScheduleDetail.getPrincipal(); - } - - public Money getTotalChargesDueAtDisbursement() { - return Money.of(getCurrency(), this.totalChargesDueAtDisbursement); - } + public LocalDate getInterestChargedFromDate() { + LocalDate interestChargedFrom = null; + if (this.interestChargedFromDate != null) { + interestChargedFrom = new LocalDate(this.interestChargedFromDate); + } + return interestChargedFrom; + } - public boolean hasCurrencyCodeOf(final String matchingCurrencyCode) { - return getCurrencyCode().equalsIgnoreCase(matchingCurrencyCode); - } - - private String getCurrencyCode() { - return this.loanRepaymentScheduleDetail.getPrincipal().getCurrencyCode(); - } - - private MonetaryCurrency getCurrency() { - return this.loanRepaymentScheduleDetail.getCurrency(); - } + public LocalDate getLoanStatusSinceDate() { + + LocalDate statusSinceDate = getSubmittedOnDate(); + if (isApproved()) { + statusSinceDate = new LocalDate(this.approvedOnDate); + } + + if (isDisbursed()) { + statusSinceDate = new LocalDate(this.disbursedOnDate); + } + + if (isClosed()) { + statusSinceDate = new LocalDate(this.closedOnDate); + } + + return statusSinceDate; + } + + public Money getPrincpal() { + return this.loanRepaymentScheduleDetail.getPrincipal(); + } + + public Money getTotalChargesDueAtDisbursement() { + return Money.of(getCurrency(), this.totalChargesDueAtDisbursement); + } + + public boolean hasCurrencyCodeOf(final String matchingCurrencyCode) { + return getCurrencyCode().equalsIgnoreCase(matchingCurrencyCode); + } + + private String getCurrencyCode() { + return this.loanRepaymentScheduleDetail.getPrincipal().getCurrencyCode(); + } + + private MonetaryCurrency getCurrency() { + return this.loanRepaymentScheduleDetail.getCurrency(); + } + + public void reassignLoanOfficer(final Staff newLoanOfficer, final LocalDate assignmentDate) { - public void reassignLoanOfficer(final Staff newLoanOfficer, final LocalDate assignmentDate) { - final LoanOfficerAssignmentHistory latestHistoryRecord = findLatestIncompleteHistoryRecord(); if (latestHistoryRecord != null && this.loanofficer.identifiedBy(newLoanOfficer)) { - latestHistoryRecord.updateStartDate(assignmentDate); + latestHistoryRecord.updateStartDate(assignmentDate); } else if (latestHistoryRecord != null && latestHistoryRecord.matchesStartDateOf(assignmentDate)) { - latestHistoryRecord.updateLoanOfficer(newLoanOfficer); - this.loanofficer = newLoanOfficer; + latestHistoryRecord.updateLoanOfficer(newLoanOfficer); + this.loanofficer = newLoanOfficer; } else if (latestHistoryRecord != null && latestHistoryRecord.hasStartDateBefore(assignmentDate)) { throw new LoanOfficerAssignmentException(this.getId(), assignmentDate); } else { - if (latestHistoryRecord != null){ - // loan officer correctly changed from previous loan officer to new loan officer + if (latestHistoryRecord != null) { + // loan officer correctly changed from previous loan officer to + // new loan officer latestHistoryRecord.updateEndDate(assignmentDate); } - this.loanofficer = newLoanOfficer; - if (this.isNotSubmittedAndPendingApproval()){ - final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory.createNew(this, this.loanofficer, assignmentDate); + this.loanofficer = newLoanOfficer; + if (this.isNotSubmittedAndPendingApproval()) { + final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory.createNew(this, + this.loanofficer, assignmentDate); this.loanOfficerHistory.add(loanOfficerAssignmentHistory); } } - } + } - private LoanOfficerAssignmentHistory findLatestIncompleteHistoryRecord() { - - LoanOfficerAssignmentHistory latestRecordWithNoEndDate = null; - for (LoanOfficerAssignmentHistory historyRecord : this.loanOfficerHistory){ - if (historyRecord.isCurrentRecord()) { - latestRecordWithNoEndDate = historyRecord; - } - } - return latestRecordWithNoEndDate; - } + private LoanOfficerAssignmentHistory findLatestIncompleteHistoryRecord() { - public Client getGuarantor() { - return guarantor; - } + LoanOfficerAssignmentHistory latestRecordWithNoEndDate = null; + for (LoanOfficerAssignmentHistory historyRecord : this.loanOfficerHistory) { + if (historyRecord.isCurrentRecord()) { + latestRecordWithNoEndDate = historyRecord; + } + } + return latestRecordWithNoEndDate; + } - public void setGuarantor(Client guarantor) { - this.guarantor = guarantor; - } + public Client getGuarantor() { + return guarantor; + } + + public void setGuarantor(Client guarantor) { + this.guarantor = guarantor; + } + + public Client getClient() { + return client; + } - public Client getClient() { - return client; - } - } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java index 192a6dd70..95eb4300a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -32,7 +32,6 @@ import org.mifosplatform.portfolio.fund.data.FundData; import org.mifosplatform.portfolio.fund.service.FundReadPlatformService; import org.mifosplatform.portfolio.loanproduct.data.LoanProductData; import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData; -import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.loanproduct.service.LoanDropdownReadPlatformService; import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService; import org.springframework.beans.factory.annotation.Autowired; @@ -59,7 +58,6 @@ public class LoanProductsApiResource { private final ChargeReadPlatformService chargeReadPlatformService; private final CurrencyReadPlatformService currencyReadPlatformService; private final FundReadPlatformService fundReadPlatformService; - private final LoanProductCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; private final LoanDropdownReadPlatformService dropdownReadPlatformService; @@ -69,7 +67,6 @@ public class LoanProductsApiResource { public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService, final ChargeReadPlatformService chargeReadPlatformService, final CurrencyReadPlatformService currencyReadPlatformService, final FundReadPlatformService fundReadPlatformService, final LoanDropdownReadPlatformService dropdownReadPlatformService, - final LoanProductCommandFromApiJsonDeserializer fromApiJsonDeserializer, final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { @@ -79,7 +76,6 @@ public class LoanProductsApiResource { this.currencyReadPlatformService = currencyReadPlatformService; this.fundReadPlatformService = fundReadPlatformService; this.dropdownReadPlatformService = dropdownReadPlatformService; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.toApiJsonSerializer = toApiJsonSerializer; this.apiRequestParameterHelper = apiRequestParameterHelper; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; @@ -90,14 +86,8 @@ public class LoanProductsApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String createLoanProduct(final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "CREATE_LOANPRODUCT"); - context.authenticatedUser().validateHasPermissionTo("CREATE_LOANPRODUCT", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "loanproducts", null, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_LOANPRODUCT", "CREATE", + "loanproducts", null, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } @@ -154,15 +144,8 @@ public class LoanProductsApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updateLoanProduct(@PathParam("productId") final Long productId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "ORGANISATION_ADMINISTRATION_SUPER_USER", - "UPDATE_LOANPRODUCT"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_LOANPRODUCT", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(productId, - apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "loanproducts", productId, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_LOANPRODUCT", "UPDATE", + "loanproducts", productId, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/command/LoanProductCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/command/LoanProductCommand.java index e665f2860..f97598401 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/command/LoanProductCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/command/LoanProductCommand.java @@ -1,7 +1,12 @@ package org.mifosplatform.portfolio.loanproduct.command; import java.math.BigDecimal; -import java.util.Set; +import java.util.ArrayList; +import java.util.List; + +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; /** * Immutable command for creating or updating details of a loan product. @@ -26,19 +31,11 @@ public class LoanProductCommand { private final Integer interestCalculationPeriodType; private final String[] charges; - private final transient Set parametersPassedInRequest; - private final transient boolean makerCheckerApproval; - private final transient Long id; - - public LoanProductCommand(final Set parametersPassedInRequest, final boolean makerCheckerApproval, final Long id, - final String name, final String description, final Long fundId, final Long transactionProcessingStrategyId, + public LoanProductCommand(final String name, final String description, final Long fundId, final Long transactionProcessingStrategyId, final String currencyCode, final Integer digitsAfterDecimal, final BigDecimal principal, final BigDecimal inArrearsTolerance, final Integer numberOfRepayments, final Integer repaymentEvery, final BigDecimal interestRatePerPeriod, final Integer repaymentFrequencyType, final Integer interestRateFrequencyType, final Integer amortizationType, final Integer interestType, final Integer interestCalculationPeriodType, final String[] charges) { - this.parametersPassedInRequest = parametersPassedInRequest; - this.makerCheckerApproval = makerCheckerApproval; - this.id = id; this.name = name; this.description = description; this.fundId = fundId; @@ -62,10 +59,6 @@ public class LoanProductCommand { this.charges = charges; } - public Long getId() { - return id; - } - public String getName() { return name; } @@ -134,75 +127,77 @@ public class LoanProductCommand { return charges; } - public boolean isNameChanged() { - return this.parametersPassedInRequest.contains("name"); + public void validateForCreate() { + + List dataValidationErrors = new ArrayList(); + + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("product"); + + baseDataValidator.reset().parameter("name").value(this.name).notBlank(); + baseDataValidator.reset().parameter("description").value(this.description).notExceedingLengthOf(500); + baseDataValidator.reset().parameter("currencyCode").value(this.currencyCode).notBlank(); + baseDataValidator.reset().parameter("digitsAfterDecimal").value(this.digitsAfterDecimal).notNull().inMinMaxRange(0, 6); + + baseDataValidator.reset().parameter("principal").value(this.principal).notNull().positiveAmount(); + baseDataValidator.reset().parameter("inArrearsTolerance").value(this.inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount(); + + baseDataValidator.reset().parameter("repaymentFrequencyType").value(this.repaymentFrequencyType).notNull().inMinMaxRange(0, 3); + baseDataValidator.reset().parameter("repaymentEvery").value(this.repaymentEvery).notNull().integerGreaterThanZero(); + baseDataValidator.reset().parameter("numberOfRepayments").value(this.numberOfRepayments).notNull().integerGreaterThanZero(); + + baseDataValidator.reset().parameter("interestRatePerPeriod").value(this.interestRatePerPeriod).notNull(); + baseDataValidator.reset().parameter("interestRateFrequencyType").value(this.interestRateFrequencyType).notNull() + .inMinMaxRange(0, 3); + + baseDataValidator.reset().parameter("amortizationType").value(this.amortizationType).notNull().inMinMaxRange(0, 1); + baseDataValidator.reset().parameter("interestType").value(this.interestType).notNull().inMinMaxRange(0, 1); + baseDataValidator.reset().parameter("interestCalculationPeriodType").value(this.interestCalculationPeriodType).notNull() + .inMinMaxRange(0, 1); + + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } } - public boolean isDescriptionChanged() { - return this.parametersPassedInRequest.contains("description"); - } + public void validateForUpdate() { - public boolean isFundChanged() { - return this.parametersPassedInRequest.contains("fundId"); - } + List dataValidationErrors = new ArrayList(); - public boolean isTransactionProcessingStrategyChanged() { - return this.parametersPassedInRequest.contains("transactionProcessingStrategyId"); - } + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("product"); - public boolean isCurrencyCodeChanged() { - return this.parametersPassedInRequest.contains("currencyCode"); - } + baseDataValidator.reset().parameter("name").value(this.name).ignoreIfNull().notBlank(); + baseDataValidator.reset().parameter("description").value(this.description).ignoreIfNull().notExceedingLengthOf(500); + baseDataValidator.reset().parameter("currencyCode").value(this.currencyCode).ignoreIfNull().notBlank(); + baseDataValidator.reset().parameter("digitsAfterDecimal").value(this.digitsAfterDecimal).ignoreIfNull().notNull() + .inMinMaxRange(0, 6); - public boolean isDigitsAfterDecimalChanged() { - return this.parametersPassedInRequest.contains("digitsAfterDecimal"); - } + baseDataValidator.reset().parameter("principal").value(this.principal).ignoreIfNull().notNull().positiveAmount(); + baseDataValidator.reset().parameter("inArrearsTolerance").value(this.inArrearsTolerance).ignoreIfNull().notNull() + .zeroOrPositiveAmount(); - public boolean isPrincipalChanged() { - return this.parametersPassedInRequest.contains("principal"); - } + baseDataValidator.reset().parameter("repaymentFrequencyType").value(this.repaymentFrequencyType).ignoreIfNull().notNull() + .inMinMaxRange(0, 3); - public boolean isInArrearsToleranceChanged() { - return this.parametersPassedInRequest.contains("inArrearsTolerance"); - } + baseDataValidator.reset().parameter("repaymentEvery").value(this.repaymentEvery).ignoreIfNull().notNull().integerGreaterThanZero(); + baseDataValidator.reset().parameter("numberOfRepayments").value(this.numberOfRepayments).ignoreIfNull().notNull() + .integerGreaterThanZero(); - public boolean isNumberOfRepaymentsChanged() { - return this.parametersPassedInRequest.contains("numberOfRepayments"); - } + baseDataValidator.reset().parameter("interestRatePerPeriod").value(this.interestRatePerPeriod).ignoreIfNull().notBlank(); + baseDataValidator.reset().parameter("interestRateFrequencyType").value(this.interestRateFrequencyType).ignoreIfNull() + .notNull().inMinMaxRange(0, 3); - public boolean isRepaymentEveryChanged() { - return this.parametersPassedInRequest.contains("repaymentEvery"); - } + baseDataValidator.reset().parameter("amortizationType").value(this.amortizationType).ignoreIfNull().notNull() + .inMinMaxRange(0, 1); + baseDataValidator.reset().parameter("interestType").value(this.interestType).ignoreIfNull().notNull().inMinMaxRange(0, 1); + baseDataValidator.reset().parameter("interestCalculationPeriodType").value(this.interestCalculationPeriodType) + .ignoreIfNull().notNull().inMinMaxRange(0, 1); - public boolean isRepaymentFrequencyTypeChanged() { - return this.parametersPassedInRequest.contains("repaymentFrequencyType"); - } + baseDataValidator.reset().anyOfNotNull(this.fundId, this.transactionProcessingStrategyId, this.name, + this.description, this.currencyCode, this.digitsAfterDecimal, this.principal, + this.inArrearsTolerance, this.repaymentFrequencyType, this.repaymentEvery, + this.numberOfRepayments, this.interestRatePerPeriod, this.interestRateFrequencyType, + this.amortizationType, this.interestType, this.interestCalculationPeriodType, this.charges); - public boolean isAmortizationTypeChanged() { - return this.parametersPassedInRequest.contains("amortizationType"); - } - - public boolean isInterestTypeChanged() { - return this.parametersPassedInRequest.contains("interestType"); - } - - public boolean isInterestRatePerPeriodChanged() { - return this.parametersPassedInRequest.contains("interestRatePerPeriod"); - } - - public boolean isInterestRateFrequencyTypeChanged() { - return this.parametersPassedInRequest.contains("interestRateFrequencyType"); - } - - public boolean isInterestCalculationPeriodTypeChanged() { - return this.parametersPassedInRequest.contains("interestCalculationPeriodType"); - } - - public boolean isChargesChanged() { - return this.parametersPassedInRequest.contains("charges"); - } - - public boolean isApprovedByChecker() { - return this.makerCheckerApproval; + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java index a5876a49b..7811debc7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java @@ -1,6 +1,9 @@ package org.mifosplatform.portfolio.loanproduct.domain; import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.Set; import javax.persistence.Column; @@ -13,11 +16,12 @@ import javax.persistence.ManyToOne; import javax.persistence.Table; import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.portfolio.charge.domain.Charge; import org.mifosplatform.portfolio.fund.domain.Fund; -import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; +import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator; import org.mifosplatform.useradministration.domain.AppUser; /** @@ -33,21 +37,17 @@ import org.mifosplatform.useradministration.domain.AppUser; @Table(name = "m_product_loan") public class LoanProduct extends AbstractAuditableCustom { - @SuppressWarnings("unused") @ManyToOne @JoinColumn(name = "fund_id", nullable = true) private Fund fund; - @SuppressWarnings("unused") @ManyToOne @JoinColumn(name = "loan_transaction_strategy_id", nullable = true) private LoanTransactionProcessingStrategy transactionProcessingStrategy; - @SuppressWarnings("unused") @Column(name = "name", nullable = false) private String name; - @SuppressWarnings("unused") @Column(name = "description") private String description; @@ -58,6 +58,37 @@ public class LoanProduct extends AbstractAuditableCustom { @Embedded private final LoanProductRelatedDetail loanProductRelatedDetail; + public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy, + final Set productCharges, final JsonCommand command, final AprCalculator aprCalculator) { + + final String name = command.stringValueOfParameterNamed("name"); + final String description = command.stringValueOfParameterNamed("description"); + final String currencyCode = command.stringValueOfParameterNamed("currencyCode"); + final Integer digitsAfterDecimal = command.integerValueOfParameterNamed("digitsAfterDecimal"); + + final MonetaryCurrency currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal); + final BigDecimal principal = command.bigDecimalValueOfParameterNamed("principal"); + + final InterestMethod interestMethod = InterestMethod.fromInt(command.integerValueOfParameterNamed("interestType")); + final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command + .integerValueOfParameterNamed("interestCalculationPeriodType")); + final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.integerValueOfParameterNamed("interestType")); + final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command + .integerValueOfParameterNamed("repaymentFrequencyType")); + final PeriodFrequencyType interestFrequencyType = PeriodFrequencyType.fromInt(command + .integerValueOfParameterNamed("interestRateFrequencyType")); + final BigDecimal interestRatePerPeriod = command.bigDecimalValueOfParameterNamed("interestRatePerPeriod"); + final BigDecimal annualInterestRate = aprCalculator.calculateFrom(interestFrequencyType, interestRatePerPeriod); + + final Integer repaymentEvery = command.integerValueOfParameterNamed("repaymentEvery"); + final Integer numberOfRepayments = command.integerValueOfParameterNamed("numberOfRepayments"); + final BigDecimal inArrearsTolerance = command.bigDecimalValueOfParameterNamed("inArrearsTolerance"); + + return new LoanProduct(fund, loanTransactionProcessingStrategy, name, description, currency, principal, interestRatePerPeriod, + interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, + repaymentFrequencyType, numberOfRepayments, amortizationMethod, inArrearsTolerance, productCharges); + } + protected LoanProduct() { this.loanProductRelatedDetail = null; } @@ -94,30 +125,75 @@ public class LoanProduct extends AbstractAuditableCustom { public Set getCharges() { return charges; } + + public void update(final Fund fund) { + this.fund = fund; + } - public void update(final LoanProductCommand command, final Fund fund, final LoanTransactionProcessingStrategy strategy, - final Set charges) { + public void update(final LoanTransactionProcessingStrategy strategy) { + this.transactionProcessingStrategy = strategy; + } - if (command.isNameChanged()) { - this.name = command.getName(); + public void update(final Set charges) { + this.charges = charges; + } + + public Map update(final JsonCommand command) { + + final Map actualChanges = this.loanProductRelatedDetail.update(command); + + final String nameParamName = "name"; + if (command.isChangeInStringParameterNamed(nameParamName, this.name)) { + final String newValue = command.stringValueOfParameterNamed(nameParamName); + actualChanges.put(nameParamName, newValue); + this.name = newValue; } - if (command.isDescriptionChanged()) { - this.description = command.getDescription(); + final String descriptionParamName = "description"; + if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) { + final String newValue = command.stringValueOfParameterNamed(descriptionParamName); + actualChanges.put(descriptionParamName, newValue); + this.description = newValue; } - if (command.isFundChanged()) { - this.fund = fund; + Long existingFundId = null; + if (this.fund != null) { + existingFundId = this.fund.getId(); + } + final String fundIdParamName = "fundId"; + if (command.isChangeInLongParameterNamed(fundIdParamName, existingFundId)) { + final Long newValue = command.longValueOfParameterNamed(fundIdParamName); + actualChanges.put(fundIdParamName, newValue); } - if (command.isTransactionProcessingStrategyChanged()) { - this.transactionProcessingStrategy = strategy; + Long existingStrategyId = null; + if (this.transactionProcessingStrategy != null) { + existingStrategyId = this.transactionProcessingStrategy.getId(); + } + final String transactionProcessingStrategyParamName = "transactionProcessingStrategyId"; + if (command.isChangeInLongParameterNamed(transactionProcessingStrategyParamName, existingStrategyId)) { + final Long newValue = command.longValueOfParameterNamed(transactionProcessingStrategyParamName); + actualChanges.put(transactionProcessingStrategyParamName, newValue); } - if (command.isChargesChanged()) { - this.charges = charges; + final String chargesParamName = "charges"; + if (command.isChangeInArrayParameterNamed(chargesParamName, getChargesIds())) { + final String[] newValue = command.arrayValueOfParameterNamed(chargesParamName); + actualChanges.put(chargesParamName, newValue); } - this.loanProductRelatedDetail.update(command); + return actualChanges; + } + + private String[] getChargesIds() { + final List chargeIds = new ArrayList(); + + if (this.charges != null) { + for (Charge charge : this.charges) { + chargeIds.add(charge.getId().toString()); + } + } + + return chargeIds.toArray(new String[chargeIds.size()]); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java index 08a7c61cb..3c30ae8f7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java @@ -1,6 +1,8 @@ package org.mifosplatform.portfolio.loanproduct.domain; import java.math.BigDecimal; +import java.util.LinkedHashMap; +import java.util.Map; import javax.persistence.Column; import javax.persistence.Embeddable; @@ -8,10 +10,10 @@ import javax.persistence.Embedded; import javax.persistence.EnumType; import javax.persistence.Enumerated; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.portfolio.loanaccount.domain.Loan; -import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; /** * LoanRepaymentScheduleDetail encapsulates all the details of a @@ -140,51 +142,113 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche return amortizationMethod; } - public void update(final LoanProductCommand command) { + public Map update(final JsonCommand command) { - Integer digitsAfterDecimalChanged = this.currency.getDigitsAfterDecimal(); - if (command.isDigitsAfterDecimalChanged()) { - digitsAfterDecimalChanged = command.getDigitsAfterDecimal(); + final Map actualChanges = new LinkedHashMap(20); + + final String localeAsInput = command.locale(); + + String currencyCode = this.currency.getCode(); + Integer digitsAfterDecimal = this.currency.getDigitsAfterDecimal(); + + final String digitsAfterDecimalParamName = "digitsAfterDecimal"; + if (command.isChangeInIntegerParameterNamed(digitsAfterDecimalParamName, digitsAfterDecimal)) { + final Integer newValue = command.integerValueOfParameterNamed(digitsAfterDecimalParamName); + actualChanges.put(digitsAfterDecimalParamName, newValue); + actualChanges.put("locale", localeAsInput); + digitsAfterDecimal = newValue; + this.currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal); } - String currencyCodeChanged = this.currency.getCode(); - if (command.isCurrencyCodeChanged()) { - currencyCodeChanged = command.getCurrencyCode(); + final String currencyCodeParamName = "currencyCode"; + if (command.isChangeInStringParameterNamed(currencyCodeParamName, currencyCode)) { + final String newValue = command.stringValueOfParameterNamed(currencyCodeParamName); + actualChanges.put(currencyCodeParamName, newValue); + currencyCode = newValue; + this.currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal); } - if (command.isDigitsAfterDecimalChanged() || command.isCurrencyCodeChanged()) { - this.currency = new MonetaryCurrency(currencyCodeChanged, digitsAfterDecimalChanged); + final String principalParamName = "principal"; + if (command.isChangeInBigDecimalParameterNamed(principalParamName, this.principal)) { + final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(principalParamName); + actualChanges.put(principalParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.principal = newValue; } - if (command.isPrincipalChanged()) { - this.principal = command.getPrincipal(); + final String repaymentEveryParamName = "repaymentEvery"; + if (command.isChangeInIntegerParameterNamed(repaymentEveryParamName, this.repayEvery)) { + final Integer newValue = command.integerValueOfParameterNamed(repaymentEveryParamName); + actualChanges.put(repaymentEveryParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.repayEvery = newValue; } - if (command.isRepaymentEveryChanged()) { - this.repayEvery = command.getRepaymentEvery(); + + final String repaymentFrequencyTypeParamName = "repaymentFrequencyType"; + if (command.isChangeInIntegerParameterNamed(repaymentFrequencyTypeParamName, this.repaymentPeriodFrequencyType.getValue())) { + final Integer newValue = command.integerValueOfParameterNamed(repaymentFrequencyTypeParamName); + actualChanges.put(repaymentFrequencyTypeParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(newValue); } - if (command.isRepaymentFrequencyTypeChanged()) { - this.repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequencyType()); + + final String numberOfRepaymentsParamName = "numberOfRepayments"; + if (command.isChangeInIntegerParameterNamed(numberOfRepaymentsParamName, this.numberOfRepayments)) { + final Integer newValue = command.integerValueOfParameterNamed(numberOfRepaymentsParamName); + actualChanges.put(numberOfRepaymentsParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.numberOfRepayments = newValue; } - if (command.isNumberOfRepaymentsChanged()) { - this.numberOfRepayments = command.getNumberOfRepayments(); + + final String amortizationTypeParamName = "amortizationType"; + if (command.isChangeInIntegerParameterNamed(amortizationTypeParamName, this.amortizationMethod.getValue())) { + final Integer newValue = command.integerValueOfParameterNamed(amortizationTypeParamName); + actualChanges.put(amortizationTypeParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.amortizationMethod = AmortizationMethod.fromInt(newValue); } - if (command.isAmortizationTypeChanged()) { - this.amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationType()); + + final String inArrearsToleranceParamName = "inArrearsTolerance"; + if (command.isChangeInBigDecimalParameterNamed(inArrearsToleranceParamName, this.inArrearsTolerance)) { + final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(inArrearsToleranceParamName); + actualChanges.put(inArrearsToleranceParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.inArrearsTolerance = newValue; } - if (command.isInArrearsToleranceChanged()) { - this.inArrearsTolerance = command.getInArrearsTolerance(); + + final String interestRatePerPeriodParamName = "interestRatePerPeriod"; + if (command.isChangeInBigDecimalParameterNamed(interestRatePerPeriodParamName, this.nominalInterestRatePerPeriod)) { + final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRatePerPeriodParamName); + actualChanges.put(interestRatePerPeriodParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.nominalInterestRatePerPeriod = newValue; } - if (command.isInterestRatePerPeriodChanged()) { - this.nominalInterestRatePerPeriod = command.getInterestRatePerPeriod(); + + final String interestRateFrequencyTypeParamName = "interestRateFrequencyType"; + if (command.isChangeInIntegerParameterNamed(interestRateFrequencyTypeParamName, this.interestPeriodFrequencyType.getValue())) { + final Integer newValue = command.integerValueOfParameterNamed(interestRateFrequencyTypeParamName); + actualChanges.put(interestRateFrequencyTypeParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.interestPeriodFrequencyType = PeriodFrequencyType.fromInt(newValue); } - if (command.isInterestRateFrequencyTypeChanged()) { - this.interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyType()); + + final String interestTypeParamName = "interestType"; + if (command.isChangeInIntegerParameterNamed(interestTypeParamName, this.interestMethod.getValue())) { + final Integer newValue = command.integerValueOfParameterNamed(interestTypeParamName); + actualChanges.put(interestTypeParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.interestMethod = InterestMethod.fromInt(newValue); } - if (command.isInterestTypeChanged()) { - this.interestMethod = InterestMethod.fromInt(command.getInterestType()); - } - if (command.isInterestCalculationPeriodTypeChanged()) { - this.interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodType()); + + final String interestCalculationPeriodTypeParamName = "interestCalculationPeriodType"; + if (command + .isChangeInIntegerParameterNamed(interestCalculationPeriodTypeParamName, this.interestCalculationPeriodMethod.getValue())) { + final Integer newValue = command.integerValueOfParameterNamed(interestCalculationPeriodTypeParamName); + actualChanges.put(interestCalculationPeriodTypeParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(newValue); } + + return actualChanges; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/handler/CreateLoanProductCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/handler/CreateLoanProductCommandHandler.java new file mode 100644 index 000000000..d73b5df9f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/handler/CreateLoanProductCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.loanproduct.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.loanproduct.service.LoanProductWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateLoanProductCommandHandler implements NewCommandSourceHandler { + + private final LoanProductWritePlatformService writePlatformService; + + @Autowired + public CreateLoanProductCommandHandler(final LoanProductWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.createLoanProduct(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/handler/UpdateLoanProductCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/handler/UpdateLoanProductCommandHandler.java new file mode 100644 index 000000000..0e66d70c9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/handler/UpdateLoanProductCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.portfolio.loanproduct.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.portfolio.loanproduct.service.LoanProductWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateLoanProductCommandHandler implements NewCommandSourceHandler { + + private final LoanProductWritePlatformService writePlatformService; + + @Autowired + public UpdateLoanProductCommandHandler(final LoanProductWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.updateLoanProduct(command.resourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java index 64a7df3e8..bdc86ee34 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java @@ -7,7 +7,9 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; +import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; @@ -22,7 +24,7 @@ import com.google.gson.reflect.TypeToken; * {@link LoanProductCommand}'s. */ @Component -public final class LoanProductCommandFromApiJsonDeserializer implements FromApiJsonDeserializer { +public final class LoanProductCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer { /** * The parameters supported for this command. @@ -33,76 +35,45 @@ public final class LoanProductCommandFromApiJsonDeserializer implements FromApiJ "amortizationType", "interestType", "interestCalculationPeriodType", "charges", "locale")); private final FromJsonHelper fromApiJsonHelper; - private final CommandSerializer commandSerializerService; @Autowired - public LoanProductCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, - final CommandSerializer commandSerializerService) { + public LoanProductCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; - this.commandSerializerService = commandSerializerService; } @Override public LoanProductCommand commandFromApiJson(final String json) { - return commandFromApiJson(null, json); - } - @Override - public LoanProductCommand commandFromApiJson(final Long loanProductId, final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final Set parametersPassedInRequest = new HashSet(); - final JsonElement element = fromApiJsonHelper.parse(json); - final String name = fromApiJsonHelper.extractStringNamed("name", element, parametersPassedInRequest); - final String description = fromApiJsonHelper.extractStringNamed("description", element, parametersPassedInRequest); - final Long fundId = fromApiJsonHelper.extractLongNamed("fundId", element, parametersPassedInRequest); + final String name = fromApiJsonHelper.extractStringNamed("name", element); + final String description = fromApiJsonHelper.extractStringNamed("description", element); + final Long fundId = fromApiJsonHelper.extractLongNamed("fundId", element); - final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element, - parametersPassedInRequest); + final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element); - final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element, parametersPassedInRequest); - final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerWithLocaleNamed("digitsAfterDecimal", element, - parametersPassedInRequest); + final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element); + final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerWithLocaleNamed("digitsAfterDecimal", element); - final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element, parametersPassedInRequest); - final BigDecimal inArrearsTolerance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element, - parametersPassedInRequest); - final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element, - parametersPassedInRequest); - final Integer repaymentEvery = fromApiJsonHelper - .extractIntegerWithLocaleNamed("repaymentEvery", element, parametersPassedInRequest); - final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element, - parametersPassedInRequest); - final Integer repaymentFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyType", element, - parametersPassedInRequest); - final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestRateFrequencyType", element, - parametersPassedInRequest); - final Integer amortizationType = fromApiJsonHelper.extractIntegerWithLocaleNamed("amortizationType", element, - parametersPassedInRequest); - final Integer interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element, parametersPassedInRequest); + final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element); + final BigDecimal inArrearsTolerance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element); + final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element); + final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element); + final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element); + final Integer repaymentFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyType", element); + final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestRateFrequencyType", element); + final Integer amortizationType = fromApiJsonHelper.extractIntegerWithLocaleNamed("amortizationType", element); + final Integer interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element); final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestCalculationPeriodType", - element, parametersPassedInRequest); - final String[] charges = fromApiJsonHelper.extractArrayNamed("charges", element, parametersPassedInRequest); + element); + final String[] charges = fromApiJsonHelper.extractArrayNamed("charges", element); - return new LoanProductCommand(parametersPassedInRequest, false, loanProductId, name, description, fundId, - transactionProcessingStrategyId, currencyCode, digitsAfterDecimal, principal, inArrearsTolerance, numberOfRepayments, - repaymentEvery, interestRatePerPeriod, repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestType, - interestCalculationPeriodType, charges); - } - - @Override - public String serializedCommandJsonFromApiJson(final String json) { - final LoanProductCommand command = commandFromApiJson(json); - return this.commandSerializerService.serializeCommandToJson(command); - } - - @Override - public String serializedCommandJsonFromApiJson(final Long loanProductId, final String json) { - final LoanProductCommand command = commandFromApiJson(loanProductId, json); - return this.commandSerializerService.serializeCommandToJson(command); + return new LoanProductCommand(name, description, fundId, transactionProcessingStrategyId, currencyCode, digitsAfterDecimal, + principal, inArrearsTolerance, numberOfRepayments, repaymentEvery, interestRatePerPeriod, repaymentFrequencyType, + interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, charges); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromCommandJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromCommandJsonDeserializer.java deleted file mode 100644 index 86eb3b8b2..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromCommandJsonDeserializer.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.mifosplatform.portfolio.loanproduct.serialization; - -import java.math.BigDecimal; -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.serialization.FromCommandJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.google.gson.JsonElement; - -@Component -public final class LoanProductCommandFromCommandJsonDeserializer implements FromCommandJsonDeserializer { - - private final FromJsonHelper fromJsonHelper; - - @Autowired - public LoanProductCommandFromCommandJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { - this.fromJsonHelper = fromApiJsonHelper; - } - - @Override - public LoanProductCommand commandFromCommandJson(final String commandAsJson) { - return commandFromCommandJson(null, commandAsJson); - } - - @Override - public LoanProductCommand commandFromCommandJson(final Long loanProductId, final String commandAsJson) { - return commandFromCommandJson(loanProductId, commandAsJson, false); - } - - @Override - public LoanProductCommand commandFromCommandJson(final Long loanProductId, final String commandAsJson, - final boolean makerCheckerApproval) { - if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); } - - final Set parametersPassedInRequest = new HashSet(); - - final JsonElement element = fromJsonHelper.parse(commandAsJson); - - final String name = fromJsonHelper.extractStringNamed("name", element, parametersPassedInRequest); - final String description = fromJsonHelper.extractStringNamed("description", element, parametersPassedInRequest); - final Long fundId = fromJsonHelper.extractLongNamed("fundId", element, parametersPassedInRequest); - final Long transactionProcessingStrategyId = fromJsonHelper.extractLongNamed("transactionProcessingStrategyId", element, - parametersPassedInRequest); - final String currencyCode = fromJsonHelper.extractStringNamed("currencyCode", element, parametersPassedInRequest); - final Integer digitsAfterDecimal = fromJsonHelper.extractIntegerNamed("digitsAfterDecimal", element, parametersPassedInRequest); - - final BigDecimal principal = fromJsonHelper.extractBigDecimalNamed("principal", element.getAsJsonObject(), - parametersPassedInRequest); - final BigDecimal inArrearsTolerance = fromJsonHelper.extractBigDecimalNamed("inArrearsTolerance", element.getAsJsonObject(), - parametersPassedInRequest); - final BigDecimal interestRatePerPeriod = fromJsonHelper.extractBigDecimalNamed("interestRatePerPeriod", element.getAsJsonObject(), - parametersPassedInRequest); - final Integer repaymentEvery = fromJsonHelper.extractIntegerNamed("repaymentEvery", element, parametersPassedInRequest); - final Integer numberOfRepayments = fromJsonHelper.extractIntegerNamed("numberOfRepayments", element, parametersPassedInRequest); - final Integer repaymentFrequencyType = fromJsonHelper.extractIntegerNamed("repaymentFrequencyType", element, - parametersPassedInRequest); - final Integer interestRateFrequencyType = fromJsonHelper.extractIntegerNamed("interestRateFrequencyType", element, - parametersPassedInRequest); - final Integer amortizationType = fromJsonHelper.extractIntegerNamed("amortizationType", element, parametersPassedInRequest); - final Integer interestType = fromJsonHelper.extractIntegerNamed("interestType", element, parametersPassedInRequest); - final Integer interestCalculationPeriodType = fromJsonHelper.extractIntegerNamed("interestCalculationPeriodType", element, - parametersPassedInRequest); - final String[] charges = fromJsonHelper.extractArrayNamed("charges", element, parametersPassedInRequest); - - return new LoanProductCommand(parametersPassedInRequest, makerCheckerApproval, loanProductId, name, description, fundId, - transactionProcessingStrategyId, currencyCode, digitsAfterDecimal, principal, inArrearsTolerance, numberOfRepayments, - repaymentEvery, interestRatePerPeriod, repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestType, - interestCalculationPeriodType, charges); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductCommandValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductCommandValidator.java deleted file mode 100644 index 2a310a984..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductCommandValidator.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.mifosplatform.portfolio.loanproduct.service; - -import java.util.ArrayList; -import java.util.List; - -import org.mifosplatform.infrastructure.core.data.ApiParameterError; -import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; -import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; -import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; - -public class LoanProductCommandValidator { - - private final LoanProductCommand command; - - public LoanProductCommandValidator(LoanProductCommand command) { - this.command = command; - } - - public void validateForUpdate() { - - List dataValidationErrors = new ArrayList(); - - DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("product"); - - baseDataValidator.reset().parameter("id").value(command.getId()).notNull(); - baseDataValidator.reset().parameter("name").value(command.getName()).ignoreIfNull().notBlank(); - baseDataValidator.reset().parameter("description").value(command.getDescription()).ignoreIfNull().notExceedingLengthOf(500); - baseDataValidator.reset().parameter("currencyCode").value(command.getCurrencyCode()).ignoreIfNull().notBlank(); - baseDataValidator.reset().parameter("digitsAfterDecimal").value(command.getDigitsAfterDecimal()).ignoreIfNull().notNull().inMinMaxRange(0, 6); - - baseDataValidator.reset().parameter("principal").value(command.getPrincipal()).ignoreIfNull().notNull().positiveAmount(); - baseDataValidator.reset().parameter("inArrearsTolerance").value(command.getInArrearsTolerance()).ignoreIfNull().notNull().zeroOrPositiveAmount(); - - baseDataValidator.reset().parameter("repaymentFrequencyType").value(command.getRepaymentFrequencyType()).ignoreIfNull().notNull().inMinMaxRange(0, 3); - - baseDataValidator.reset().parameter("repaymentEvery").value(command.getRepaymentEvery()).ignoreIfNull().notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter("numberOfRepayments").value(command.getNumberOfRepayments()).ignoreIfNull().notNull().integerGreaterThanZero(); - - baseDataValidator.reset().parameter("interestRatePerPeriod").value(command.getInterestRatePerPeriod()).ignoreIfNull().notBlank(); - baseDataValidator.reset().parameter("interestRateFrequencyType").value(command.getInterestRateFrequencyType()).ignoreIfNull().notNull().inMinMaxRange(0, 3); - - baseDataValidator.reset().parameter("amortizationType").value(command.getAmortizationType()).ignoreIfNull().notNull().inMinMaxRange(0, 1); - baseDataValidator.reset().parameter("interestType").value(command.getInterestType()).ignoreIfNull().notNull().inMinMaxRange(0, 1); - baseDataValidator.reset().parameter("interestCalculationPeriodType").value(command.getInterestCalculationPeriodType()).ignoreIfNull().notNull().inMinMaxRange(0, 1); - - baseDataValidator.reset().anyOfNotNull(command.getFundId(), command.getTransactionProcessingStrategyId(), command.getName(), command.getDescription(), command.getCurrencyCode(), command.getDigitsAfterDecimal(), - command.getPrincipal(), command.getInArrearsTolerance(), command.getRepaymentFrequencyType(), command.getRepaymentEvery(), command.getNumberOfRepayments(), - command.getInterestRatePerPeriod(), command.getInterestRateFrequencyType(), command.getAmortizationType(), command.getInterestType(), command.getInterestCalculationPeriodType(), command.getCharges()); - - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); - } - } - - public void validateForCreate() { - - List dataValidationErrors = new ArrayList(); - - DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("product"); - - baseDataValidator.reset().parameter("name").value(command.getName()).notBlank(); - baseDataValidator.reset().parameter("description").value(command.getDescription()).notExceedingLengthOf(500); - baseDataValidator.reset().parameter("currencyCode").value(command.getCurrencyCode()).notBlank(); - baseDataValidator.reset().parameter("digitsAfterDecimal").value(command.getDigitsAfterDecimal()).notNull().inMinMaxRange(0, 6); - - baseDataValidator.reset().parameter("principal").value(command.getPrincipal()).notNull().positiveAmount(); - baseDataValidator.reset().parameter("inArrearsTolerance").value(command.getInArrearsTolerance()).ignoreIfNull().zeroOrPositiveAmount(); - - baseDataValidator.reset().parameter("repaymentFrequencyType").value(command.getRepaymentFrequencyType()).notNull().inMinMaxRange(0, 3); - baseDataValidator.reset().parameter("repaymentEvery").value(command.getRepaymentEvery()).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter("numberOfRepayments").value(command.getNumberOfRepayments()).notNull().integerGreaterThanZero(); - - // transactionProcessingStrategyId defaults to mifos strategy if left null - - baseDataValidator.reset().parameter("interestRatePerPeriod").value(command.getInterestRatePerPeriod()).notNull(); - baseDataValidator.reset().parameter("interestRateFrequencyType").value(command.getInterestRateFrequencyType()).notNull().inMinMaxRange(0, 3); - - baseDataValidator.reset().parameter("amortizationType").value(command.getAmortizationType()).notNull().inMinMaxRange(0, 1); - baseDataValidator.reset().parameter("interestType").value(command.getInterestType()).notNull().inMinMaxRange(0, 1); - baseDataValidator.reset().parameter("interestCalculationPeriodType").value(command.getInterestCalculationPeriodType()).notNull().inMinMaxRange(0, 1); - - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); - } - } - -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformService.java index 23850024d..7fdee9167 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformService.java @@ -1,11 +1,11 @@ package org.mifosplatform.portfolio.loanproduct.service; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.EntityIdentifier; -import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; public interface LoanProductWritePlatformService { - EntityIdentifier createLoanProduct(LoanProductCommand command); + EntityIdentifier createLoanProduct(JsonCommand command); - EntityIdentifier updateLoanProduct(LoanProductCommand command); + EntityIdentifier updateLoanProduct(Long loanProductId, JsonCommand command); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java index b4fecc061..016281789 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java @@ -1,18 +1,16 @@ package org.mifosplatform.portfolio.loanproduct.service; -import java.math.BigDecimal; import java.util.HashSet; +import java.util.Map; import java.util.Set; +import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; -import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; import org.mifosplatform.portfolio.charge.domain.Charge; import org.mifosplatform.portfolio.charge.domain.ChargeRepository; import org.mifosplatform.portfolio.charge.exception.ChargeIsNotActiveException; import org.mifosplatform.portfolio.charge.exception.ChargeNotFoundException; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.mifosplatform.portfolio.fund.domain.Fund; import org.mifosplatform.portfolio.fund.domain.FundRepository; import org.mifosplatform.portfolio.fund.exception.FundNotFoundException; @@ -20,15 +18,12 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionProcessingS import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator; import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; -import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod; -import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod; -import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository; import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; -import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException; import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException; +import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductCommandFromApiJsonDeserializer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -38,69 +33,49 @@ import org.springframework.util.ObjectUtils; public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanProductWritePlatformService { private final PlatformSecurityContext context; + private final LoanProductCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final LoanProductRepository loanProductRepository; private final AprCalculator aprCalculator; private final FundRepository fundRepository; private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository; private final ChargeRepository chargeRepository; - private final ConfigurationDomainService configurationDomainService; @Autowired public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, - final LoanProductRepository loanProductRepository, final AprCalculator aprCalculator, final FundRepository fundRepository, + final LoanProductCommandFromApiJsonDeserializer fromApiJsonDeserializer, final LoanProductRepository loanProductRepository, + final AprCalculator aprCalculator, final FundRepository fundRepository, final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository, - final ChargeRepository chargeRepository, - final ConfigurationDomainService configurationDomainService) { + final ChargeRepository chargeRepository) { this.context = context; + this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.loanProductRepository = loanProductRepository; this.aprCalculator = aprCalculator; this.fundRepository = fundRepository; this.loanTransactionProcessingStrategyRepository = loanTransactionProcessingStrategyRepository; this.chargeRepository = chargeRepository; - this.configurationDomainService = configurationDomainService; } @Transactional @Override - public EntityIdentifier createLoanProduct(final LoanProductCommand command) { + public EntityIdentifier createLoanProduct(final JsonCommand command) { this.context.authenticatedUser(); - LoanProductCommandValidator validator = new LoanProductCommandValidator(command); - validator.validateForCreate(); - - // assemble LoanProduct from data - InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestType()); - InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command - .getInterestCalculationPeriodType()); - - AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationType()); - - PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequencyType()); - - PeriodFrequencyType interestFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyType()); - - MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal()); - - BigDecimal annualInterestRate = this.aprCalculator.calculateFrom(interestFrequencyType, command.getInterestRatePerPeriod()); + final LoanProductCommand loanProductCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); + loanProductCommand.validateForCreate(); // associating fund with loan product at creation is optional for now. - Fund fund = findFundByIdIfProvided(command.getFundId()); - LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(command - .getTransactionProcessingStrategyId()); - + final Fund fund = findFundByIdIfProvided(command.longValueOfParameterNamed("fundId")); + final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(command + .longValueOfParameterNamed("transactionProcessingStrategyId")); final Set charges = this.assembleSetOfCharges(command, null); - LoanProduct loanproduct = new LoanProduct(fund, loanTransactionProcessingStrategy, command.getName(), command.getDescription(), - currency, command.getPrincipal(), command.getInterestRatePerPeriod(), interestFrequencyType, annualInterestRate, - interestMethod, interestCalculationPeriodMethod, command.getRepaymentEvery(), repaymentFrequencyType, - command.getNumberOfRepayments(), amortizationMethod, command.getInArrearsTolerance(), charges); + final LoanProduct loanproduct = LoanProduct.assembleFromJson(fund, loanTransactionProcessingStrategy, charges, command, + this.aprCalculator); this.loanProductRepository.save(loanproduct); - - if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_LOANPRODUCT") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - return new EntityIdentifier(loanproduct.getId()); + return EntityIdentifier.resourceResult(loanproduct.getId(), null); } private LoanTransactionProcessingStrategy findStrategyByIdIfProvided(final Long transactionProcessingStrategyId) { @@ -123,54 +98,61 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro @Transactional @Override - public EntityIdentifier updateLoanProduct(final LoanProductCommand command) { + public EntityIdentifier updateLoanProduct(final Long loanProductId, final JsonCommand command) { this.context.authenticatedUser(); + + final LoanProductCommand loanProductCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); + loanProductCommand.validateForUpdate(); - LoanProductCommandValidator validator = new LoanProductCommandValidator(command); - validator.validateForUpdate(); - - LoanProduct product = this.loanProductRepository.findOne(command.getId()); - if (product == null) { throw new LoanProductNotFoundException(command.getId()); } + final LoanProduct product = this.loanProductRepository.findOne(loanProductId); + if (product == null) { throw new LoanProductNotFoundException(loanProductId); } + + final Map changes = product.update(command); // associating fund with loan product at creation is optional for now. - Fund fund = null; - if (command.isFundChanged()) { - fund = findFundByIdIfProvided(command.getFundId()); + if (changes.containsKey("fundId")) { + final Long fundId = (Long) changes.get("fundId"); + final Fund fund = findFundByIdIfProvided(fundId); + product.update(fund); } - LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = null; - if (command.isTransactionProcessingStrategyChanged()) { - loanTransactionProcessingStrategy = findStrategyByIdIfProvided(command.getTransactionProcessingStrategyId()); + if (changes.containsKey("transactionProcessingStrategyId")) { + final Long transactionProcessingStrategyId = (Long) changes.get("transactionProcessingStrategyId"); + final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(transactionProcessingStrategyId); + product.update(loanTransactionProcessingStrategy); } - - final Set charges = this.assembleSetOfCharges(command, product.getCurrency().getCode()); - - product.update(command, fund, loanTransactionProcessingStrategy, charges); - - this.loanProductRepository.save(product); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_LOANPRODUCT") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } + if (changes.containsKey("charges")) { + final Set charges = this.assembleSetOfCharges(command, product.getCurrency().getCode()); + product.update(charges); + } - return new EntityIdentifier(Long.valueOf(product.getId())); + if (!changes.isEmpty()) { + this.loanProductRepository.save(product); + } + + return EntityIdentifier.withChanges(product.getId(), changes); } - private Set assembleSetOfCharges(final LoanProductCommand command, final String currencyCode) { + private Set assembleSetOfCharges(final JsonCommand command, final String currencyCode) { - Set charges = new HashSet(); - String[] chargesArray = command.getCharges(); + final Set charges = new HashSet(); + final String[] chargesArray = command.arrayValueOfParameterNamed("charges"); - String loanProductCurrencyCode = command.getCurrencyCode(); + String loanProductCurrencyCode = command.stringValueOfParameterNamed("currencyCode"); if (loanProductCurrencyCode == null) { loanProductCurrencyCode = currencyCode; } - if (command.isChargesChanged() && !ObjectUtils.isEmpty(chargesArray)) { - for (String chargeId : chargesArray) { - Long id = Long.valueOf(chargeId); - Charge charge = this.chargeRepository.findOne(id); + if (!ObjectUtils.isEmpty(chargesArray)) { + for (final String chargeId : chargesArray) { + + final Long id = Long.valueOf(chargeId); + final Charge charge = this.chargeRepository.findOne(id); if (charge == null || charge.isDeleted()) { throw new ChargeNotFoundException(id); } if (!charge.isActive()) { throw new ChargeIsNotActiveException(id, charge.getName()); } + if (!loanProductCurrencyCode.equals(charge.getCurrencyCode())) { String errorMessage = "Charge and Loan Product must have the same currency."; throw new InvalidCurrencyException("charge", "attach.to.loan.product", errorMessage); @@ -181,5 +163,4 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro return charges; } - } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/api/DepositAccountsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/api/DepositAccountsApiResource.java index 45d8a6601..577b03e59 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/api/DepositAccountsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/api/DepositAccountsApiResource.java @@ -79,9 +79,8 @@ public class DepositAccountsApiResource { "interestCompoundedEvery", "interestCompoundingAllowed", "interestCompoundedEveryPeriodType", "renewalAllowed", "preClosureAllowed", "preClosureInterestRate", "withdrawnonDate", "rejectedonDate", "closedonDate", "transactions", "interestPaid", "isInterestWithdrawable", "availableInterestForWithdrawal", "availableWithdrawalAmount", "todaysDate", - "isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType","printFDdetailsLocation", "availableInterest", "interestPostedAmount", - "lastInterestPostedDate", "nextInterestPostedDate","fatherName","address","imageKey")); - + "isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType", "printFDdetailsLocation", "availableInterest", + "interestPostedAmount", "lastInterestPostedDate", "nextInterestPostedDate", "fatherName", "address", "imageKey")); @POST @Consumes({ MediaType.APPLICATION_JSON }) @@ -263,8 +262,7 @@ public class DepositAccountsApiResource { private boolean is(final String commandParam, final String commandValue) { return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue); - } - + } @POST @Path("postinterest") @@ -276,23 +274,22 @@ public class DepositAccountsApiResource { return Response.ok().entity(entityIdentifier).build(); } - + @GET - @Path("{accountId}/print") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public Response printDepositAccount(@PathParam("accountId") final Long accountId, @Context final UriInfo uriInfo) { - - DepositAccountData account = this.depositAccountReadPlatformService.retrieveDepositAccount(accountId); - String printFileName=null; - if (account != null) - printFileName = new GeneratePDF(account).generatePDF(); - account.setPrintFDdetailsLocation(printFileName); - - File file = new File(printFileName); - ResponseBuilder response = Response.ok(file); - response.header("Content-Disposition", "attachment; filename=\""+ printFileName + "\""); - response.header("Content-Type", "applicatio/pdf"); - return response.build(); - } + @Path("{accountId}/print") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response printDepositAccount(@PathParam("accountId") final Long accountId) { + + DepositAccountData account = this.depositAccountReadPlatformService.retrieveDepositAccount(accountId); + String printFileName = null; + if (account != null) printFileName = new GeneratePDF(account).generatePDF(); + account.setPrintFDdetailsLocation(printFileName); + + File file = new File(printFileName); + ResponseBuilder response = Response.ok(file); + response.header("Content-Disposition", "attachment; filename=\"" + printFileName + "\""); + response.header("Content-Type", "applicatio/pdf"); + return response.build(); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/service/DepositAccountReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/service/DepositAccountReadPlatformServiceImpl.java index 6e8982447..0eb1378e2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/service/DepositAccountReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/service/DepositAccountReadPlatformServiceImpl.java @@ -132,27 +132,25 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead private static final class DepositAccountMapper implements RowMapper { public String schema() { - return "da.id as id, da.external_id as externalId, da.client_id as clientId, da.product_id as productId, " - + " da.currency_code as currencyCode, da.currency_digits as currencyDigits, " - + " da.deposit_amount as depositAmount, da.status_enum as statusId, " - + " da.maturity_nominal_interest_rate as interestRate, da.tenure_months as termInMonths, da.projected_commencement_date as projectedCommencementDate," - + " da.actual_commencement_date as actualCommencementDate, da.matures_on_date as maturedOn," - + " da.projected_interest_accrued_on_maturity as projectedInterestAccrued, da.actual_interest_accrued as actualInterestAccrued, " - + " da.projected_total_maturity_amount as projectedMaturityAmount, da.actual_total_amount as actualMaturityAmount, " - + " da.interest_compounded_every as interestCompoundedEvery, da.interest_compounded_every_period_enum as interestCompoundedEveryPeriodType, " - + " da.is_renewal_allowed as renewalAllowed, da.is_preclosure_allowed as preClosureAllowed, da.pre_closure_interest_rate as preClosureInterestRate, " - + " da.withdrawnon_date as withdrawnonDate, da.rejectedon_date as rejectedonDate, da.closedon_date as closedonDate, " - + " da.interest_paid as interestPaid, da.is_interest_withdrawable as isInterestWithdrawable, da.is_compounding_interest_allowed as interestCompoundingAllowed, " - + " da.is_lock_in_period_allowed as isLockinPeriodAllowed, da.lock_in_period as lockinPeriod, da.lock_in_period_type lockinPeriodType, " - + " da.available_interest as availableInterest, da.interest_posted_amount as interestPostedAmount, da.last_interest_posted_date as lastInterestPostedDate, da.next_interest_posting_date as nextInterestPostedDate," - + " c.firstname as firstname, c.lastname as lastname, pd.name as productName, c.image_key as imageKey, " - + " curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol, " - + " ecd.father_name as fatherName, ecd.client_address as clientAddress " - + " from m_deposit_account da " - + " join m_currency curr on curr.code = da.currency_code " - + " join m_client c on c.id = da.client_id " - + " join m_product_deposit pd on pd.id = da.product_id" - + " left join extra_client_details ecd on da.client_id = ecd.client_id "; + return "da.id as id, da.external_id as externalId, da.client_id as clientId, da.product_id as productId, " + + " da.currency_code as currencyCode, da.currency_digits as currencyDigits, " + + " da.deposit_amount as depositAmount, da.status_enum as statusId, " + + " da.maturity_nominal_interest_rate as interestRate, da.tenure_months as termInMonths, da.projected_commencement_date as projectedCommencementDate," + + " da.actual_commencement_date as actualCommencementDate, da.matures_on_date as maturedOn," + + " da.projected_interest_accrued_on_maturity as projectedInterestAccrued, da.actual_interest_accrued as actualInterestAccrued, " + + " da.projected_total_maturity_amount as projectedMaturityAmount, da.actual_total_amount as actualMaturityAmount, " + + " da.interest_compounded_every as interestCompoundedEvery, da.interest_compounded_every_period_enum as interestCompoundedEveryPeriodType, " + + " da.is_renewal_allowed as renewalAllowed, da.is_preclosure_allowed as preClosureAllowed, da.pre_closure_interest_rate as preClosureInterestRate, " + + " da.withdrawnon_date as withdrawnonDate, da.rejectedon_date as rejectedonDate, da.closedon_date as closedonDate, " + + " da.interest_paid as interestPaid, da.is_interest_withdrawable as isInterestWithdrawable, da.is_compounding_interest_allowed as interestCompoundingAllowed, " + + " da.is_lock_in_period_allowed as isLockinPeriodAllowed, da.lock_in_period as lockinPeriod, da.lock_in_period_type lockinPeriodType, " + + " da.available_interest as availableInterest, da.interest_posted_amount as interestPostedAmount, da.last_interest_posted_date as lastInterestPostedDate, da.next_interest_posting_date as nextInterestPostedDate," + + " c.firstname as firstname, c.lastname as lastname, pd.name as productName, c.image_key as imageKey, " + + " curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol, " + + " ecd.father_name as fatherName, ecd.client_address as clientAddress " + " from m_deposit_account da " + + " join m_currency curr on curr.code = da.currency_code " + " join m_client c on c.id = da.client_id " + + " join m_product_deposit pd on pd.id = da.product_id" + + " left join extra_client_details ecd on da.client_id = ecd.client_id "; } @Override @@ -212,14 +210,14 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead Integer lockinPeriod = JdbcSupport.getInteger(rs, "lockinPeriod"); Integer lockinPeriodTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodType"); EnumOptionData lockinPeriodType = SavingsDepositEnumerations.interestCompoundingPeriodType(lockinPeriodTypeValue); - + BigDecimal availableInterest = rs.getBigDecimal("availableInterest"); - BigDecimal interestPostedAmount = rs.getBigDecimal("interestPostedAmount"); - LocalDate lastInterestPostedDate = JdbcSupport.getLocalDate(rs, "lastInterestPostedDate"); - LocalDate nextInterestPostedDate = JdbcSupport.getLocalDate(rs, "nextInterestPostedDate"); - String imageKey = rs.getString("imageKey"); - String fatherName = rs.getString("fatherName"); - String address = rs.getString("clientAddress"); + BigDecimal interestPostedAmount = rs.getBigDecimal("interestPostedAmount"); + LocalDate lastInterestPostedDate = JdbcSupport.getLocalDate(rs, "lastInterestPostedDate"); + LocalDate nextInterestPostedDate = JdbcSupport.getLocalDate(rs, "nextInterestPostedDate"); + String imageKey = rs.getString("imageKey"); + String fatherName = rs.getString("fatherName"); + String address = rs.getString("clientAddress"); return new DepositAccountData(id, externalId, status, clientId, clientName, productId, productName, currencyData, depositAmount, interestRate, termInMonths, projectedCommencementDate, actualCommencementDate, maturedOn, @@ -227,15 +225,15 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead interestCompoundedEvery, interestCompoundedEveryPeriodType, renewalAllowed, preClosureAllowed, preClosureInterestRate, withdrawnonDate, rejectedonDate, closedonDate, isInterestWithdrawable, interestPaid, interestCompoundingAllowed, isLockinPeriodAllowed, lockinPeriod, lockinPeriodType, availableInterest, interestPostedAmount, lastInterestPostedDate, - nextInterestPostedDate,fatherName,address,imageKey); + nextInterestPostedDate, fatherName, address, imageKey); } } private static final class DepositAccountTransactionMapper implements RowMapper { public String schema() { - return " txn.id as transactionId, txn.deposit_account_id as accountId, txn.transaction_type_enum as transactionType, txn.transaction_date as transactionDate, txn.amount as transactionAmount, txn.interest as interestAmount, " - + "txn.total as total from m_deposit_account_transaction txn"; + return " txn.id as transactionId, txn.deposit_account_id as accountId, txn.transaction_type_enum as transactionType, txn.transaction_date as transactionDate, txn.amount as transactionAmount, txn.interest as interestAmount, " + + "txn.total as total from m_deposit_account_transaction txn"; } @Override @@ -262,7 +260,18 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead boolean undoApprovalAllowed = (depositAccountData.getStatus().getId().equals(300L)); boolean renewelAllowed = false; if (depositAccountData.getMaturedOn() != null) { - if (new LocalDate().isAfter(depositAccountData.getMaturedOn())/* || depositAccountData.getMaturedOn().isEqual(new LocalDate()) */) { + if (new LocalDate().isAfter(depositAccountData.getMaturedOn())/* + * || + * depositAccountData + * . + * getMaturedOn + * (). + * isEqual + * ( + * new + * LocalDate + * ()) + */) { renewelAllowed = depositAccountData.isRenewalAllowed(); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java index fe9da64ee..8a980cecb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositaccount/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java @@ -7,7 +7,6 @@ import java.util.List; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; -import org.joda.time.Months; import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/PermissionsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/PermissionsApiResource.java index 27050cb22..313f81b57 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/PermissionsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/PermissionsApiResource.java @@ -3,7 +3,6 @@ package org.mifosplatform.useradministration.api; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; @@ -78,10 +77,7 @@ public class PermissionsApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updatePermissionsDetails(final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "UPDATE_PERMISSION"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_PERMISSION", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "permissions", null, + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_PERMISSION", "UPDATE", "permissions", null, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/RolesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/RolesApiResource.java index 9459d9f51..6c8c0a48a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/RolesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/RolesApiResource.java @@ -3,7 +3,6 @@ package org.mifosplatform.useradministration.api; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; @@ -104,13 +103,8 @@ public class RolesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String createRole(final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "CREATE_ROLE"); - context.authenticatedUser().validateHasPermissionTo("CREATE_ROLE", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "roles", null, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_ROLE", "CREATE", "roles", null, + apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } @@ -127,7 +121,7 @@ public class RolesApiResource { RoleData role = this.roleReadPlatformService.retrieveRole(roleId); if (settings.isCommandIdPassed()) { - RoleData currentChanges = handleRequestToIntegrateProposedChangesFromRoleCommand(roleId, settings.getCommandId()); + RoleData currentChanges = handleRequestToIntegrateProposedChangesFromRoleCommand(settings.getCommandId()); role = RoleData.integrateChanges(role, currentChanges); } @@ -135,13 +129,13 @@ public class RolesApiResource { return this.toApiJsonSerializer.serialize(settings, role, RESPONSE_DATA_PARAMETERS); } - private RoleData handleRequestToIntegrateProposedChangesFromRoleCommand(final Long roleId, final Long commandId) { + private RoleData handleRequestToIntegrateProposedChangesFromRoleCommand(final Long commandId) { final CommandSourceData entry = this.commandSourceReadPlatformService.retrieveById(commandId); - return assembleRoleChanges(roleId, entry); + return assembleRoleChanges(entry); } - private RoleData assembleRoleChanges(final Long roleId, final CommandSourceData entry) { - final RoleCommand changesOnly = this.fromApiJsonDeserializer.commandFromApiJson(roleId, entry.json()); + private RoleData assembleRoleChanges(final CommandSourceData entry) { + final RoleCommand changesOnly = this.fromApiJsonDeserializer.commandFromApiJson(entry.json()); return RoleData.changes(changesOnly.getName(), changesOnly.getDescription()); } @@ -151,13 +145,8 @@ public class RolesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updateRole(@PathParam("roleId") final Long roleId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "UPDATE_ROLE"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_ROLE", allowedPermissions); - - final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "roles", roleId, - commandSerializedAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_ROLE", "UPDATE", "roles", roleId, + apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } @@ -186,11 +175,8 @@ public class RolesApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updateRolePermissions(@PathParam("roleId") final Long roleId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "PERMISSIONS_ROLE"); - context.authenticatedUser().validateHasPermissionTo("PERMISSIONS_ROLE", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATEPERMISSIONS", "roles", roleId, - apiRequestBodyAsJson); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("PERMISSIONS_ROLE", "UPDATEPERMISSIONS", + "roles", roleId, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/UsersApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/UsersApiResource.java index cdeeb9709..7d4b9b49b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/UsersApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/UsersApiResource.java @@ -39,7 +39,8 @@ import org.springframework.stereotype.Component; public class UsersApiResource { /** - * The set of parameters that are supported in response for {@link AppUserData}. + * The set of parameters that are supported in response for + * {@link AppUserData}. */ private final Set RESPONSE_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "officeId", "officeName", "username", "firstname", "lastname", "email", "allowedOffices", "availableRoles", "selectedRoles")); @@ -55,8 +56,8 @@ public class UsersApiResource { @Autowired public UsersApiResource(final PlatformSecurityContext context, final AppUserReadPlatformService readPlatformService, - final OfficeReadPlatformService officeReadPlatformService, - final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, + final OfficeReadPlatformService officeReadPlatformService, final DefaultToApiJsonSerializer toApiJsonSerializer, + final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { this.context = context; this.readPlatformService = readPlatformService; @@ -117,10 +118,7 @@ public class UsersApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String createUser(final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "CREATE_USER"); - context.authenticatedUser().validateHasPermissionTo("CREATE_USER", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "users", null, + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE_USER", "CREATE", "users", null, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); @@ -132,10 +130,7 @@ public class UsersApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String updateUser(@PathParam("userId") final Long userId, final String apiRequestBodyAsJson) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "UPDATE_USER"); - context.authenticatedUser().validateHasPermissionTo("UPDATE_USER", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "users", userId, + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE_USER", "UPDATE", "users", userId, apiRequestBodyAsJson); return this.toApiJsonSerializer.serialize(result); @@ -147,10 +142,8 @@ public class UsersApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String deleteUser(@PathParam("userId") final Long userId) { - final List allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "DELETE_USER"); - context.authenticatedUser().validateHasPermissionTo("DELETE_USER", allowedPermissions); - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", "users", userId, "{}"); + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE_USER", "DELETE", "users", userId, + "{}"); return this.toApiJsonSerializer.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/command/UserCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/command/UserCommand.java index c74994183..2555c1ebc 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/command/UserCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/command/UserCommand.java @@ -17,20 +17,18 @@ public class UserCommand { private final String lastname; private final String password; private final String repeatPassword; - private final String passwordEncoded; private final String email; private final Long officeId; private final String[] notSelectedRoles; private final String[] roles; public UserCommand(final String username, final String firstname, final String lastname, final String password, - final String repeatPassword, final String passwordEncoded, final String email, final Long officeId, final String[] notSelectedRoles, final String[] roles) { + final String repeatPassword, final String email, final Long officeId, final String[] notSelectedRoles, final String[] roles) { this.username = username; this.firstname = firstname; this.lastname = lastname; this.password = password; this.repeatPassword = repeatPassword; - this.passwordEncoded = passwordEncoded; this.email = email; this.officeId = officeId; this.notSelectedRoles = notSelectedRoles; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/AppUser.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/AppUser.java index b8baf1840..dfdbdd048 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/AppUser.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/AppUser.java @@ -25,6 +25,8 @@ import org.mifosplatform.infrastructure.security.domain.PlatformUser; import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException; import org.mifosplatform.infrastructure.security.service.PlatformPasswordEncoder; import org.mifosplatform.organisation.office.domain.Office; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; @@ -33,6 +35,8 @@ import org.springframework.security.core.userdetails.User; @Table(name = "m_appuser", uniqueConstraints = @UniqueConstraint(columnNames = { "username" }, name = "username_org")) public class AppUser extends AbstractAuditableCustom implements PlatformUser { + private final static Logger logger = LoggerFactory.getLogger(AppUser.class); + @Column(name = "email", nullable = false, length = 100) private String email; @@ -327,7 +331,7 @@ public class AppUser extends AbstractAuditableCustom implements P return false; } - public boolean hasNotPermissionForDatatable(String datatable, String accessType) { + public boolean hasNotPermissionForDatatable(final String datatable, final String accessType) { String matchPermission = accessType + "_" + datatable; @@ -414,10 +418,27 @@ public class AppUser extends AbstractAuditableCustom implements P } } + private boolean hasNotPermissionTo(final String permissionCode) { + return !hasPermissionTo(permissionCode); + } + private boolean hasPermissionTo(final String permissionCode) { + boolean hasPermission = hasAllFunctionsPermission(); + if (!hasPermission) { + for (Role role : this.roles) { + if (role.hasPermissionTo(permissionCode)) { + hasPermission = true; + break; + } + } + } + return hasPermission; + } + + private boolean hasAllFunctionsPermission() { boolean match = false; for (Role role : this.roles) { - if (role.hasPermissionTo(permissionCode)) { + if (role.hasPermissionTo("ALL_FUNCTIONS")) { match = true; break; } @@ -452,4 +473,21 @@ public class AppUser extends AbstractAuditableCustom implements P throw new NoAuthorizationException(authorizationMessage); } } + + public void validateHasPermissionTo(final String function) { + if (hasNotPermissionTo(function)) { + final String authorizationMessage = "User has no authority to: " + function; + logger.info("Unauthorized access: userId: " + this.getId() + " action: " + function + " allowed: " + getAuthorities()); + throw new NoAuthorizationException(authorizationMessage); + } + } + + public void validateHasCheckerPermissionTo(final String function) { + + final String checkerPermissionName = function.toUpperCase() + "_CHECKER"; + if (hasNotPermissionTo(checkerPermissionName)) { + final String authorizationMessage = "User has no authority to be a checker for: " + function; + throw new NoAuthorizationException(authorizationMessage); + } + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/JpaUserDomainService.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/JpaUserDomainService.java index 83b2f0e2d..fbf87fd04 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/JpaUserDomainService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/JpaUserDomainService.java @@ -4,8 +4,6 @@ import org.mifosplatform.infrastructure.core.domain.EmailDetail; import org.mifosplatform.infrastructure.core.service.PlatformEmailService; import org.mifosplatform.infrastructure.security.service.PlatformPasswordEncoder; import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator; -import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,20 +14,18 @@ public class JpaUserDomainService implements UserDomainService { private final AppUserRepository userRepository; private final PlatformPasswordEncoder applicationPasswordEncoder; private final PlatformEmailService emailService; - private final ConfigurationDomainService configurationDomainService; @Autowired public JpaUserDomainService(final AppUserRepository userRepository, final PlatformPasswordEncoder applicationPasswordEncoder, - final PlatformEmailService emailService, final ConfigurationDomainService configurationDomainService) { + final PlatformEmailService emailService) { this.userRepository = userRepository; this.applicationPasswordEncoder = applicationPasswordEncoder; this.emailService = emailService; - this.configurationDomainService = configurationDomainService; } @Transactional @Override - public void create(final AppUser appUser, final boolean isApprovedByChecker) { + public void create(final AppUser appUser) { generateKeyUsedForPasswordSalting(appUser); @@ -44,8 +40,6 @@ public class JpaUserDomainService implements UserDomainService { this.userRepository.save(appUser); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_USER") && !isApprovedByChecker) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - final EmailDetail emailDetail = new EmailDetail(appUser.getFirstname(), appUser.getFirstname(), appUser.getEmail(), appUser.getUsername()); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/UserDomainService.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/UserDomainService.java index fd455cd48..824ea8d5f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/UserDomainService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/UserDomainService.java @@ -2,5 +2,5 @@ package org.mifosplatform.useradministration.domain; public interface UserDomainService { - void create(AppUser appUser, boolean isApprovedByChecker); + void create(AppUser appUser); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/CreateRoleCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/CreateRoleCommandHandler.java new file mode 100644 index 000000000..6990dc109 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/CreateRoleCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.useradministration.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.useradministration.service.RoleWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateRoleCommandHandler implements NewCommandSourceHandler { + + private final RoleWritePlatformService writePlatformService; + + @Autowired + public CreateRoleCommandHandler(final RoleWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.createRole(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/CreateUserCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/CreateUserCommandHandler.java new file mode 100644 index 000000000..78d2bec50 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/CreateUserCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.useradministration.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.useradministration.service.AppUserWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateUserCommandHandler implements NewCommandSourceHandler { + + private final AppUserWritePlatformService writePlatformService; + + @Autowired + public CreateUserCommandHandler(final AppUserWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.createUser(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/DeleteUserCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/DeleteUserCommandHandler.java new file mode 100644 index 000000000..8c8898302 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/DeleteUserCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.useradministration.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.useradministration.service.AppUserWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class DeleteUserCommandHandler implements NewCommandSourceHandler { + + private final AppUserWritePlatformService writePlatformService; + + @Autowired + public DeleteUserCommandHandler(final AppUserWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.deleteUser(command.resourceId()); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateMakerCheckerPermissionsCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateMakerCheckerPermissionsCommandHandler.java new file mode 100644 index 000000000..33ed47f49 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateMakerCheckerPermissionsCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.useradministration.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.useradministration.service.PermissionWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateMakerCheckerPermissionsCommandHandler implements NewCommandSourceHandler { + + private final PermissionWritePlatformService writePlatformService; + + @Autowired + public UpdateMakerCheckerPermissionsCommandHandler(final PermissionWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.updateMakerCheckerPermissions(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateRoleCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateRoleCommandHandler.java new file mode 100644 index 000000000..00d887291 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateRoleCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.useradministration.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.useradministration.service.RoleWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateRoleCommandHandler implements NewCommandSourceHandler { + + private final RoleWritePlatformService writePlatformService; + + @Autowired + public UpdateRoleCommandHandler(final RoleWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.updateRole(command.resourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateRolePermissionsCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateRolePermissionsCommandHandler.java new file mode 100644 index 000000000..81d1f8dc9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateRolePermissionsCommandHandler.java @@ -0,0 +1,27 @@ +package org.mifosplatform.useradministration.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.useradministration.service.RoleWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateRolePermissionsCommandHandler implements NewCommandSourceHandler { + + private final RoleWritePlatformService writePlatformService; + + @Autowired + public UpdateRolePermissionsCommandHandler(final RoleWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + return this.writePlatformService.updateRolePermissions(command.resourceId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateUserCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateUserCommandHandler.java new file mode 100644 index 000000000..dd36a81f5 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/handler/UpdateUserCommandHandler.java @@ -0,0 +1,41 @@ +package org.mifosplatform.useradministration.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.useradministration.domain.AppUser; +import org.mifosplatform.useradministration.service.AppUserWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateUserCommandHandler implements NewCommandSourceHandler { + + private final AppUserWritePlatformService writePlatformService; + private final PlatformSecurityContext context; + + @Autowired + public UpdateUserCommandHandler(final PlatformSecurityContext context, final AppUserWritePlatformService writePlatformService) { + this.context = context; + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public EntityIdentifier processCommand(final JsonCommand command) { + + final AppUser loggedInUser = context.authenticatedUser(); + + final Long userId = command.resourceId(); + EntityIdentifier result = null; + if (loggedInUser.hasIdOf(userId)) { + result = this.writePlatformService.updateUsersOwnAccountDetails(userId, command); + } else { + result = this.writePlatformService.updateUser(userId, command); + } + + return result; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/PermissionsCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/PermissionsCommandFromApiJsonDeserializer.java index 9cabac880..eefadf51f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/PermissionsCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/PermissionsCommandFromApiJsonDeserializer.java @@ -9,7 +9,6 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.useradministration.command.PermissionsCommand; @@ -32,20 +31,18 @@ public final class PermissionsCommandFromApiJsonDeserializer extends AbstractFro private final FromJsonHelper fromApiJsonHelper; @Autowired - public PermissionsCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, - final CommandSerializer commandSerializerService) { - super(commandSerializerService); + public PermissionsCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; } @Override - public PermissionsCommand commandFromApiJson(@SuppressWarnings("unused") final Long resourceId, final String json) { - + public PermissionsCommand commandFromApiJson(final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } - + final Type typeOfMap = new TypeToken>() {}.getType(); fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - + return fromApiJsonHelper.fromJson(json, PermissionsCommand.class); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/RoleCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/RoleCommandFromApiJsonDeserializer.java index 6e5ea2945..d45c56883 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/RoleCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/RoleCommandFromApiJsonDeserializer.java @@ -9,7 +9,6 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.useradministration.command.RoleCommand; @@ -33,13 +32,12 @@ public final class RoleCommandFromApiJsonDeserializer extends AbstractFromApiJso private final FromJsonHelper fromApiJsonHelper; @Autowired - public RoleCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, final CommandSerializer commandSerializerService) { - super(commandSerializerService); + public RoleCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; } @Override - public RoleCommand commandFromApiJson(@SuppressWarnings("unused") final Long roleId, final String json) { + public RoleCommand commandFromApiJson(final String json) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/UserCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/UserCommandFromApiJsonDeserializer.java index 819fa5253..73036d966 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/UserCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/UserCommandFromApiJsonDeserializer.java @@ -9,7 +9,6 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.useradministration.command.UserCommand; @@ -34,18 +33,16 @@ public final class UserCommandFromApiJsonDeserializer extends AbstractFromApiJso private final FromJsonHelper fromApiJsonHelper; @Autowired - public UserCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, final CommandSerializer commandSerializerService) { - super(commandSerializerService); + public UserCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { this.fromApiJsonHelper = fromApiJsonHelper; } @Override - public UserCommand commandFromApiJson(@SuppressWarnings("unused") final Long userId, final String json) { + public UserCommand commandFromApiJson(final String json) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); final JsonElement element = fromApiJsonHelper.parse(json); @@ -55,13 +52,12 @@ public final class UserCommandFromApiJsonDeserializer extends AbstractFromApiJso final String lastname = fromApiJsonHelper.extractStringNamed("lastname", element); final String password = fromApiJsonHelper.extractStringNamed("password", element); final String repeatPassword = fromApiJsonHelper.extractStringNamed("repeatPassword", element); - final String passwordEncoded = fromApiJsonHelper.extractStringNamed("passwordEncoded", element); final String email = fromApiJsonHelper.extractStringNamed("email", element); final Long officeId = fromApiJsonHelper.extractLongNamed("officeId", element); final String[] notSelectedRoles = fromApiJsonHelper.extractArrayNamed("notSelectedRoles", element); final String[] roles = fromApiJsonHelper.extractArrayNamed("roles", element); - return new UserCommand(username, firstname, lastname, password, repeatPassword, passwordEncoded, email, officeId, notSelectedRoles, roles); + return new UserCommand(username, firstname, lastname, password, repeatPassword, email, officeId, notSelectedRoles, roles); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/AppUserWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/AppUserWritePlatformService.java index 430d5e839..917e1375f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/AppUserWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/AppUserWritePlatformService.java @@ -5,11 +5,11 @@ import org.mifosplatform.infrastructure.core.data.EntityIdentifier; public interface AppUserWritePlatformService { - Long createUser(JsonCommand command); + EntityIdentifier createUser(JsonCommand command); EntityIdentifier updateUser(Long userId, JsonCommand command); - void deleteUser(Long userId, JsonCommand command); + EntityIdentifier deleteUser(Long userId); // we dont put any permissions on this e.g. a user with no admin rights can // change their own details (email, username, password etc). diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java index e670dde2f..9a457f4ec 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/AppUserWritePlatformServiceJpaRepositoryImpl.java @@ -14,11 +14,9 @@ import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityExce import org.mifosplatform.infrastructure.core.service.PlatformEmailSendException; import org.mifosplatform.infrastructure.security.service.PlatformPasswordEncoder; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; import org.mifosplatform.organisation.office.domain.Office; import org.mifosplatform.organisation.office.domain.OfficeRepository; import org.mifosplatform.organisation.office.exception.OfficeNotFoundException; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.mifosplatform.useradministration.command.UserCommand; import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUserRepository; @@ -47,27 +45,24 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit private final AppUserRepository appUserRepository; private final OfficeRepository officeRepository; private final RoleRepository roleRepository; - private final ConfigurationDomainService configurationDomainService; private final UserCommandFromApiJsonDeserializer fromApiJsonDeserializer; @Autowired public AppUserWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final AppUserRepository appUserRepository, final UserDomainService userDomainService, final OfficeRepository officeRepository, final RoleRepository roleRepository, - final PlatformPasswordEncoder platformPasswordEncoder, final ConfigurationDomainService configurationDomainService, - final UserCommandFromApiJsonDeserializer fromApiJsonDeserializer) { + final PlatformPasswordEncoder platformPasswordEncoder, final UserCommandFromApiJsonDeserializer fromApiJsonDeserializer) { this.context = context; this.appUserRepository = appUserRepository; this.userDomainService = userDomainService; this.officeRepository = officeRepository; this.roleRepository = roleRepository; this.platformPasswordEncoder = platformPasswordEncoder; - this.configurationDomainService = configurationDomainService; this.fromApiJsonDeserializer = fromApiJsonDeserializer; } @Transactional @Override - public Long createUser(final JsonCommand command) { + public EntityIdentifier createUser(final JsonCommand command) { try { context.authenticatedUser(); @@ -85,12 +80,12 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit final Set allRoles = assembleSetOfRoles(roles); final AppUser appUser = AppUser.fromJson(userOffice, allRoles, command); - this.userDomainService.create(appUser, command.isApprovedByChecker()); + this.userDomainService.create(appUser); - return appUser.getId(); + return EntityIdentifier.resourceResult(appUser.getId(), null); } catch (DataIntegrityViolationException dve) { handleDataIntegrityIssues(command, dve); - return Long.valueOf(-1); + return EntityIdentifier.empty(); } catch (PlatformEmailSendException e) { final List dataValidationErrors = new ArrayList(); @@ -138,8 +133,6 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit this.appUserRepository.save(userToUpdate); } - if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_USER") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - return EntityIdentifier.withChanges(userId, changes); } catch (DataIntegrityViolationException dve) { handleDataIntegrityIssues(command, dve); @@ -211,7 +204,7 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit @Transactional @Override - public void deleteUser(final Long userId, final JsonCommand command) { + public EntityIdentifier deleteUser(final Long userId) { final AppUser user = this.appUserRepository.findOne(userId); if (user == null || user.isDeleted()) { throw new UserNotFoundException(userId); } @@ -219,7 +212,7 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit user.delete(); this.appUserRepository.save(user); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("DELETE_USER") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } + return EntityIdentifier.resourceResult(userId, null); } /* diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformService.java index 6abb28483..2558602ec 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformService.java @@ -5,7 +5,7 @@ import org.mifosplatform.infrastructure.core.data.EntityIdentifier; public interface RoleWritePlatformService { - Long createRole(JsonCommand command); + EntityIdentifier createRole(JsonCommand command); EntityIdentifier updateRole(Long roleId, JsonCommand command); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java index 3f5b88a89..382a7e434 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java @@ -7,8 +7,6 @@ import java.util.Map; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; -import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.mifosplatform.useradministration.command.PermissionsCommand; import org.mifosplatform.useradministration.command.RoleCommand; import org.mifosplatform.useradministration.domain.Permission; @@ -29,26 +27,23 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf private final PlatformSecurityContext context; private final RoleRepository roleRepository; private final PermissionRepository permissionRepository; - private final ConfigurationDomainService configurationDomainService; private final RoleCommandFromApiJsonDeserializer roleCommandFromApiJsonDeserializer; private final PermissionsCommandFromApiJsonDeserializer permissionsFromApiJsonDeserializer; @Autowired public RoleWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final RoleRepository roleRepository, - final PermissionRepository permissionRepository, final ConfigurationDomainService configurationDomainService, - final RoleCommandFromApiJsonDeserializer roleCommandFromApiJsonDeserializer, + final PermissionRepository permissionRepository, final RoleCommandFromApiJsonDeserializer roleCommandFromApiJsonDeserializer, final PermissionsCommandFromApiJsonDeserializer fromApiJsonDeserializer) { this.context = context; this.roleRepository = roleRepository; this.permissionRepository = permissionRepository; - this.configurationDomainService = configurationDomainService; this.roleCommandFromApiJsonDeserializer = roleCommandFromApiJsonDeserializer; this.permissionsFromApiJsonDeserializer = fromApiJsonDeserializer; } @Transactional @Override - public Long createRole(final JsonCommand command) { + public EntityIdentifier createRole(final JsonCommand command) { context.authenticatedUser(); @@ -58,9 +53,7 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf final Role entity = Role.fromJson(command); this.roleRepository.save(entity); - if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_ROLE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - - return entity.getId(); + return EntityIdentifier.resourceResult(entity.getId(), null); } @Transactional @@ -80,8 +73,6 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf this.roleRepository.save(role); } - if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_ROLE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - return EntityIdentifier.withChanges(role.getId(), changes); } @@ -115,8 +106,6 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf this.roleRepository.save(role); } - if (this.configurationDomainService.isMakerCheckerEnabledForTask("PERMISSIONS_ROLE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - return EntityIdentifier.withChanges(role.getId(), changes); } diff --git a/mifosng-provider/src/main/resources/META-INF/spring/appContext.xml b/mifosng-provider/src/main/resources/META-INF/spring/appContext.xml index b594b5fcb..0fdadfc48 100644 --- a/mifosng-provider/src/main/resources/META-INF/spring/appContext.xml +++ b/mifosng-provider/src/main/resources/META-INF/spring/appContext.xml @@ -16,6 +16,8 @@