datatables formatting and first bit of flexible account number generation for clients.

This commit is contained in:
Keith Woodlock
2013-01-04 14:28:09 +00:00
parent 6d2151f4db
commit b61ab594e4
13 changed files with 285 additions and 298 deletions
@@ -0,0 +1,12 @@
ALTER TABLE `m_client`
ADD COLUMN `account_no` VARCHAR(20) NOT NULL AFTER `id`;
UPDATE `m_client`
SET
`account_no` = `id`
WHERE `id` > 0;
ALTER TABLE `m_client` ADD UNIQUE INDEX `account_no_UNIQUE` (`account_no` ASC);
@@ -33,210 +33,167 @@ import org.springframework.stereotype.Component;
@Scope("singleton")
public class DataTableApiResource {
private final PlatformSecurityContext context;
private final GenericDataService genericDataService;
private final ReadWriteNonCoreDataService readWriteNonCoreDataService;
private final ToApiJsonSerializer<GenericResultsetData> toApiJsonSerializer;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final PlatformSecurityContext context;
private final GenericDataService genericDataService;
private final ReadWriteNonCoreDataService readWriteNonCoreDataService;
private final ToApiJsonSerializer<GenericResultsetData> toApiJsonSerializer;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired
public DataTableApiResource(
final PlatformSecurityContext context,
final GenericDataService genericDataService,
final ReadWriteNonCoreDataService readWriteNonCoreDataService,
final ToApiJsonSerializer<GenericResultsetData> toApiJsonSerializer,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
this.context = context;
this.genericDataService = genericDataService;
this.readWriteNonCoreDataService = readWriteNonCoreDataService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
}
@Autowired
public DataTableApiResource(final PlatformSecurityContext context, final GenericDataService genericDataService,
final ReadWriteNonCoreDataService readWriteNonCoreDataService,
final ToApiJsonSerializer<GenericResultsetData> toApiJsonSerializer,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
this.context = context;
this.genericDataService = genericDataService;
this.readWriteNonCoreDataService = readWriteNonCoreDataService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String getDatatables(@QueryParam("apptable") final String apptable,
@Context final UriInfo uriInfo) {
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String getDatatables(@QueryParam("apptable") final String apptable, @Context final UriInfo uriInfo) {
final List<DatatableData> result = this.readWriteNonCoreDataService
.retrieveDatatableNames(apptable);
final List<DatatableData> result = this.readWriteNonCoreDataService.retrieveDatatableNames(apptable);
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo
.getQueryParameters());
return this.toApiJsonSerializer.serializePretty(prettyPrint, result);
}
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serializePretty(prettyPrint, result);
}
@POST
@Path("register/{datatable}/{apptable}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String registerDatatable(
@PathParam("datatable") final String datatable,
@PathParam("apptable") final String apptable) {
@POST
@Path("register/{datatable}/{apptable}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String registerDatatable(@PathParam("datatable") final String datatable, @PathParam("apptable") final String apptable) {
this.readWriteNonCoreDataService.registerDatatable(datatable, apptable);
this.readWriteNonCoreDataService.registerDatatable(datatable, apptable);
return this.toApiJsonSerializer.serialize(EntityIdentifier.empty());
}
return this.toApiJsonSerializer.serialize(EntityIdentifier.empty());
}
@POST
@Path("deregister/{datatable}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deregisterDatatable(
@PathParam("datatable") final String datatable) {
@POST
@Path("deregister/{datatable}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deregisterDatatable(@PathParam("datatable") final String datatable) {
this.readWriteNonCoreDataService.deregisterDatatable(datatable);
this.readWriteNonCoreDataService.deregisterDatatable(datatable);
return this.toApiJsonSerializer.serialize(EntityIdentifier.empty());
}
return this.toApiJsonSerializer.serialize(EntityIdentifier.empty());
}
@GET
@Path("{datatable}/{apptableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String getDatatable(@PathParam("datatable") final String datatable,
@PathParam("apptableId") final Long apptableId,
@QueryParam("order") final String order,
@Context final UriInfo uriInfo) {
@GET
@Path("{datatable}/{apptableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String getDatatable(@PathParam("datatable") final String datatable, @PathParam("apptableId") final Long apptableId,
@QueryParam("order") final String order, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasDatatableReadPermission(
datatable);
context.authenticatedUser().validateHasDatatableReadPermission(datatable);
GenericResultsetData results = this.readWriteNonCoreDataService
.retrieveDataTableGenericResultSet(datatable, apptableId,
order, null);
GenericResultsetData results = this.readWriteNonCoreDataService.retrieveDataTableGenericResultSet(datatable, apptableId, order,
null);
String json = "";
final boolean genericResultSet = ApiParameterHelper
.genericResultSet(uriInfo.getQueryParameters());
if (genericResultSet) {
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo
.getQueryParameters());
json = this.toApiJsonSerializer.serializePretty(prettyPrint,
results);
} else {
json = this.genericDataService
.generateJsonFromGenericResultsetData(results);
}
String json = "";
final boolean genericResultSet = ApiParameterHelper.genericResultSet(uriInfo.getQueryParameters());
if (genericResultSet) {
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
json = this.toApiJsonSerializer.serializePretty(prettyPrint, results);
} else {
json = this.genericDataService.generateJsonFromGenericResultsetData(results);
}
return json;
}
return json;
}
@GET
@Path("{datatable}/{apptableId}/{datatableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String getDatatableManyEntry(
@PathParam("datatable") final String datatable,
@PathParam("apptableId") final Long apptableId,
@PathParam("datatableId") final Long datatableId,
@QueryParam("order") final String order,
@Context final UriInfo uriInfo) {
@GET
@Path("{datatable}/{apptableId}/{datatableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String getDatatableManyEntry(@PathParam("datatable") final String datatable, @PathParam("apptableId") final Long apptableId,
@PathParam("datatableId") final Long datatableId, @QueryParam("order") final String order, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasDatatableReadPermission(
datatable);
context.authenticatedUser().validateHasDatatableReadPermission(datatable);
GenericResultsetData results = this.readWriteNonCoreDataService
.retrieveDataTableGenericResultSet(datatable, apptableId,
order, datatableId);
GenericResultsetData results = this.readWriteNonCoreDataService.retrieveDataTableGenericResultSet(datatable, apptableId, order,
datatableId);
String json = "";
final boolean genericResultSet = ApiParameterHelper
.genericResultSet(uriInfo.getQueryParameters());
if (genericResultSet) {
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo
.getQueryParameters());
json = this.toApiJsonSerializer.serializePretty(prettyPrint,
results);
} else {
json = this.genericDataService
.generateJsonFromGenericResultsetData(results);
}
String json = "";
final boolean genericResultSet = ApiParameterHelper.genericResultSet(uriInfo.getQueryParameters());
if (genericResultSet) {
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
json = this.toApiJsonSerializer.serializePretty(prettyPrint, results);
} else {
json = this.genericDataService.generateJsonFromGenericResultsetData(results);
}
return json;
}
return json;
}
@POST
@Path("{datatable}/{apptableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String newDatatableEntry(
@PathParam("datatable") final String datatable,
@PathParam("apptableId") final Long apptableId,
final String apiRequestBodyAsJson) {
@POST
@Path("{datatable}/{apptableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String newDatatableEntry(@PathParam("datatable") final String datatable, @PathParam("apptableId") final Long apptableId,
final String apiRequestBodyAsJson) {
final EntityIdentifier entityIdentifier = this.commandsSourceWritePlatformService
.logCommandSource("CREATE", datatable, "CREATE", "datatables/"
+ datatable, apptableId, apiRequestBodyAsJson);
final EntityIdentifier entityIdentifier = this.commandsSourceWritePlatformService.logCommandSource("CREATE", datatable, "CREATE",
"datatables/" + datatable, apptableId, apiRequestBodyAsJson);
return this.toApiJsonSerializer.serialize(entityIdentifier);
}
return this.toApiJsonSerializer.serialize(entityIdentifier);
}
@PUT
@Path("{datatable}/{apptableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateDatatableEntryOnetoOne(
@PathParam("datatable") final String datatable,
@PathParam("apptableId") final Long apptableId,
final String apiRequestBodyAsJson) {
@PUT
@Path("{datatable}/{apptableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateDatatableEntryOnetoOne(@PathParam("datatable") final String datatable,
@PathParam("apptableId") final Long apptableId, final String apiRequestBodyAsJson) {
final EntityIdentifier entityIdentifier = this.commandsSourceWritePlatformService
.logCommandSource("UPDATE", datatable, "UPDATE", "datatables/"
+ datatable, apptableId, apiRequestBodyAsJson);
final EntityIdentifier entityIdentifier = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", datatable, "UPDATE",
"datatables/" + datatable, apptableId, apiRequestBodyAsJson);
return this.toApiJsonSerializer.serialize(entityIdentifier);
}
return this.toApiJsonSerializer.serialize(entityIdentifier);
}
@PUT
@Path("{datatable}/{apptableId}/{datatableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateDatatableEntryOneToMany(
@PathParam("datatable") final String datatable,
@PathParam("apptableId") final Long apptableId,
@PathParam("datatableId") final Long datatableId,
final String apiRequestBodyAsJson) {
@PUT
@Path("{datatable}/{apptableId}/{datatableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateDatatableEntryOneToMany(@PathParam("datatable") final String datatable,
@PathParam("apptableId") final Long apptableId, @PathParam("datatableId") final Long datatableId,
final String apiRequestBodyAsJson) {
final EntityIdentifier entityIdentifier = this.commandsSourceWritePlatformService
.logCommandSource("UPDATE", datatable, "UPDATE_MULTIPLE",
"datatables/" + datatable, apptableId, "datatables/"
+ datatable, datatableId, apiRequestBodyAsJson);
final EntityIdentifier entityIdentifier = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", datatable,
"UPDATE_MULTIPLE", "datatables/" + datatable, apptableId, "datatables/" + datatable, datatableId, apiRequestBodyAsJson);
return this.toApiJsonSerializer.serialize(entityIdentifier);
}
return this.toApiJsonSerializer.serialize(entityIdentifier);
}
@DELETE
@Path("{datatable}/{apptableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteDatatableEntries(
@PathParam("datatable") final String datatable,
@PathParam("apptableId") final Long apptableId) {
@DELETE
@Path("{datatable}/{apptableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteDatatableEntries(@PathParam("datatable") final String datatable, @PathParam("apptableId") final Long apptableId) {
final EntityIdentifier entityIdentifier = this.commandsSourceWritePlatformService
.logCommandSource("DELETE", datatable, "DELETE", "datatables/"
+ datatable, apptableId, "{}");
final EntityIdentifier entityIdentifier = this.commandsSourceWritePlatformService.logCommandSource("DELETE", datatable, "DELETE",
"datatables/" + datatable, apptableId, "{}");
return this.toApiJsonSerializer.serialize(entityIdentifier);
}
return this.toApiJsonSerializer.serialize(entityIdentifier);
}
@DELETE
@Path("{datatable}/{apptableId}/{datatableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteDatatableEntries(
@PathParam("datatable") final String datatable,
@PathParam("apptableId") final Long apptableId,
@PathParam("datatableId") final Long datatableId) {
@DELETE
@Path("{datatable}/{apptableId}/{datatableId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteDatatableEntries(@PathParam("datatable") final String datatable, @PathParam("apptableId") final Long apptableId,
@PathParam("datatableId") final Long datatableId) {
final EntityIdentifier entityIdentifier = this.commandsSourceWritePlatformService
.logCommandSource("DELETE", datatable, "DELETE_MULTIPLE",
"datatables/" + datatable, apptableId, "datatables/"
+ datatable, datatableId, "{}");
final EntityIdentifier entityIdentifier = this.commandsSourceWritePlatformService.logCommandSource("DELETE", datatable,
"DELETE_MULTIPLE", "datatables/" + datatable, apptableId, "datatables/" + datatable, datatableId, "{}");
return this.toApiJsonSerializer.serialize(entityIdentifier);
}
return this.toApiJsonSerializer.serialize(entityIdentifier);
}
}
@@ -1,5 +1,7 @@
package org.mifosplatform.infrastructure.dataqueries.handler;
import java.util.Map;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
@@ -9,25 +11,22 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UpdateOneToOneDatatableEntryCommandHandler implements
NewCommandSourceHandler {
public class UpdateOneToOneDatatableEntryCommandHandler implements NewCommandSourceHandler {
private final ReadWriteNonCoreDataService writePlatformService;
private final ReadWriteNonCoreDataService writePlatformService;
@Autowired
public UpdateOneToOneDatatableEntryCommandHandler(
final ReadWriteNonCoreDataService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Autowired
public UpdateOneToOneDatatableEntryCommandHandler(final ReadWriteNonCoreDataService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public EntityIdentifier processCommand(final JsonCommand command) {
@Transactional
@Override
public EntityIdentifier processCommand(final JsonCommand command) {
// TODO - return only detected changes
this.writePlatformService.updateDatatableEntryOneToOne(command.entityName(), command.resourceId(), command);
return EntityIdentifier.resourceResult(command.resourceId(),
command.commandId());
}
// TODO - return only detected changes
Map<String, Object> changes = this.writePlatformService.updateDatatableEntryOneToOne(command.entityName(), command.resourceId(), command);
return EntityIdentifier.resourceResult(command.resourceId(), command.commandId(), changes);
}
}
@@ -1,6 +1,7 @@
package org.mifosplatform.infrastructure.dataqueries.service;
import java.util.List;
import java.util.Map;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.dataqueries.data.DatatableData;
@@ -9,29 +10,24 @@ import org.springframework.security.access.prepost.PreAuthorize;
public interface ReadWriteNonCoreDataService {
List<DatatableData> retrieveDatatableNames(String appTable);
List<DatatableData> retrieveDatatableNames(String appTable);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'REGISTER_DATATABLE')")
void registerDatatable(String datatable, String appTable);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'REGISTER_DATATABLE')")
void registerDatatable(String datatable, String appTable);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'DEREGISTER_DATATABLE')")
void deregisterDatatable(String datatable);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'DEREGISTER_DATATABLE')")
void deregisterDatatable(String datatable);
GenericResultsetData retrieveDataTableGenericResultSet(String datatable,
Long appTableId, String order, Long id);
GenericResultsetData retrieveDataTableGenericResultSet(String datatable, Long appTableId, String order, Long id);
void newDatatableEntry(String datatable, Long appTableId,
JsonCommand command);
void newDatatableEntry(String datatable, Long appTableId, JsonCommand command);
void updateDatatableEntryOneToOne(String datatable, Long appTableId,
JsonCommand command);
Map<String, Object> updateDatatableEntryOneToOne(String datatable, Long appTableId, JsonCommand command);
void updateDatatableEntryOneToMany(String datatable, Long appTableId,
Long datatableId, JsonCommand command);
void updateDatatableEntryOneToMany(String datatable, Long appTableId, Long datatableId, JsonCommand command);
void deleteDatatableEntries(String datatable, Long appTableId);
void deleteDatatableEntries(String datatable, Long appTableId);
void deleteDatatableEntry(String datatable, Long appTableId,
Long datatableId);
void deleteDatatableEntry(String datatable, Long appTableId, Long datatableId);
}
@@ -5,6 +5,7 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -37,15 +38,15 @@ import com.google.gson.reflect.TypeToken;
@Service
public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataService {
private final static Logger logger = LoggerFactory.getLogger(ReadWriteNonCoreDataServiceImpl.class);
private final static Logger logger = LoggerFactory.getLogger(ReadWriteNonCoreDataServiceImpl.class);
private final PlatformSecurityContext context;
private final FromJsonHelper fromJsonHelper;
private final FromJsonHelper fromJsonHelper;
@Autowired
public ReadWriteNonCoreDataServiceImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper) {
this.context = context;
this.fromJsonHelper = fromJsonHelper;
this.fromJsonHelper = fromJsonHelper;
}
@Autowired
@@ -160,7 +161,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
String appTable = getWithinScopeApplicationTableName(datatable, appTableId);
List<ResultsetColumnHeader> columnHeaders = getDatatableResultsetColumnHeaders(datatable);
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json());
@@ -176,9 +177,11 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
@Override
public void updateDatatableEntryOneToOne(final String datatable, final Long appTableId, final JsonCommand command) {
public Map<String, Object> updateDatatableEntryOneToOne(final String datatable, final Long appTableId, final JsonCommand command) {
// long startTime = System.currentTimeMillis();
Map<String, Object> changes = new LinkedHashMap<String, Object>();
GenericResultsetData grs = retrieveDataTableGenericResultSet(datatable, appTableId, null, null);
if (grs.getData().size() == 0) throw new DataTableNotFoundException(datatable, appTableId);
@@ -188,10 +191,10 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
+ " Foreign Key Id: " + appTableId);
String fkName = getFKField(getApplicationTableName(datatable));
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json());
String sql = getUpdateSql(grs, datatable, fkName, appTableId, dataParams);
if (sql != null) {
@@ -204,7 +207,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
// logger.info("FINISHING updateDatatableEntryOnetoOne: Elapsed Time: "
// + elapsed + " - datatable: " + datatable + fkName
// + ": " + appTableId);
return changes;
}
@Override
@@ -218,7 +222,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json());
String sql = getUpdateSql(grs, datatable, "id", datatableId, dataParams);
if (sql != null) {
@@ -9,74 +9,37 @@ import org.joda.time.LocalDate;
*/
public class OfficeData {
private final Long id;
private final String name;
private final String nameDecorated;
private final String externalId;
private final LocalDate openingDate;
private final String hierarchy;
private final Long parentId;
private final String parentName;
private final List<OfficeLookup> allowedParents;
public static OfficeData template(final List<OfficeLookup> parentLookups, final LocalDate defaultOpeningDate) {
return new OfficeData(null, null, null, null, defaultOpeningDate, null, null, null, parentLookups);
}
public static OfficeData appendedTemplate(final OfficeData office, final List<OfficeLookup> allowedParents) {
return new OfficeData(office.getId(), office.getName(), office.getNameDecorated(), office.getExternalId(),
office.getOpeningDate(), office.getHierarchy(), office.getParentId(), office.getParentName(), allowedParents);
}
private final Long id;
private final String name;
private final String nameDecorated;
private final String externalId;
private final LocalDate openingDate;
private final String hierarchy;
private final Long parentId;
private final String parentName;
public OfficeData(final Long id, final String name,
final String nameDecorated, final String externalId,
final LocalDate openingDate, String hierarchy, final Long parentId,
final String parentName, final List<OfficeLookup> allowedParents) {
this.id = id;
this.name = name;
this.nameDecorated = nameDecorated;
this.externalId = externalId;
this.openingDate = openingDate;
this.hierarchy = hierarchy;
this.parentName = parentName;
this.parentId = parentId;
this.allowedParents = allowedParents;
}
@SuppressWarnings("unused")
private final List<OfficeLookup> allowedParents;
public Long getId() {
return id;
}
public static OfficeData template(final List<OfficeLookup> parentLookups, final LocalDate defaultOpeningDate) {
return new OfficeData(null, null, null, null, defaultOpeningDate, null, null, null, parentLookups);
}
public String getName() {
return name;
}
public static OfficeData appendedTemplate(final OfficeData office, final List<OfficeLookup> allowedParents) {
return new OfficeData(office.id, office.name, office.nameDecorated, office.externalId, office.openingDate,
office.hierarchy, office.parentId, office.parentName, allowedParents);
}
public String getNameDecorated() {
return nameDecorated;
}
public String getExternalId() {
return externalId;
}
public LocalDate getOpeningDate() {
return openingDate;
}
public String getHierarchy() {
return hierarchy;
}
public Long getParentId() {
return parentId;
}
public String getParentName() {
return parentName;
}
public List<OfficeLookup> getAllowedParents() {
return allowedParents;
}
public OfficeData(final Long id, final String name, final String nameDecorated, final String externalId, final LocalDate openingDate,
String hierarchy, final Long parentId, final String parentName, final List<OfficeLookup> allowedParents) {
this.id = id;
this.name = name;
this.nameDecorated = nameDecorated;
this.externalId = externalId;
this.openingDate = openingDate;
this.hierarchy = hierarchy;
this.parentName = parentName;
this.parentId = parentId;
this.allowedParents = allowedParents;
}
}
@@ -86,7 +86,10 @@ public class ClientsApiResource {
context.authenticatedUser().validateHasReadPermission("CLIENT");
final String extraCriteria = getClientCriteria(sqlSearch, officeId, externalId, displayName, firstName, lastName, hierarchy);
// FIXME - kw - rather than exposing SQL through the api can we not just
// pass parameter we want to search by and build up sql like is done for
// other parameters?
final String extraCriteria = buildSqlStringFromClientCriteria(sqlSearch, officeId, externalId, displayName, firstName, lastName, hierarchy);
final Collection<ClientData> clients = this.clientReadPlatformService.retrieveAllIndividualClients(extraCriteria);
@@ -94,8 +97,8 @@ public class ClientsApiResource {
return this.toApiJsonSerializer.serialize(settings, clients, CLIENT_DATA_PARAMETERS);
}
private String getClientCriteria(String sqlSearch, Long officeId, String externalId, String displayName, String firstName,
String lastName, String hierarchy) {
private String buildSqlStringFromClientCriteria(final String sqlSearch, final Long officeId, final String externalId,
final String displayName, final String firstName, final String lastName, final String hierarchy) {
String extraCriteria = "";
@@ -147,6 +150,7 @@ public class ClientsApiResource {
ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId);
if (settings.isTemplate()) {
// FIXME - KW - no need for special OfficeLookup object, just use OfficeData and only populate with id, name, nameDecorated
final List<OfficeLookup> allowedOffices = new ArrayList<OfficeLookup>(officeReadPlatformService.retrieveAllOfficesForLookup());
clientData = ClientData.templateOnTop(clientData, allowedOffices);
}
@@ -13,6 +13,7 @@ import org.mifosplatform.organisation.office.data.OfficeLookup;
final public class ClientData {
private final Long id;
private final String accountNo;
private final String firstname;
private final String lastname;
private final String clientOrBusinessName;
@@ -55,7 +56,7 @@ final public class ClientData {
}
final String displayName = buildDisplayNameFrom(firstnameValue, lastnameValue);
return new ClientData(officeId, null, id, firstnameValue, lastnameValue, displayName, externalId, joiningDate, null, null, null,
return new ClientData(null, officeId, null, id, firstnameValue, lastnameValue, displayName, externalId, joiningDate, null, null, null,
null);
}
@@ -67,12 +68,12 @@ final public class ClientData {
lastname = clientData.clientOrBusinessName;
}
final String displayName = buildDisplayNameFrom(firstname, lastname);
return new ClientData(clientData.officeId, clientData.officeName, clientData.id, firstname, lastname, displayName,
return new ClientData(clientData.accountNo, clientData.officeId, clientData.officeName, clientData.id, firstname, lastname, displayName,
clientData.externalId, clientData.joinedDate, clientData.imageKey, clientData.allowedOffices, currentChange, allChanges);
}
public static ClientData template(final Long officeId, final LocalDate joinedDate, final List<OfficeLookup> allowedOffices) {
return new ClientData(officeId, null, null, null, null, null, null, joinedDate, null, allowedOffices, null, null);
return new ClientData(null, officeId, null, null, null, null, null, null, joinedDate, null, allowedOffices, null, null);
}
public static ClientData templateOnTop(final ClientData clientData, final List<OfficeLookup> allowedOffices) {
@@ -84,22 +85,23 @@ final public class ClientData {
lastname = clientData.clientOrBusinessName;
}
final String displayName = buildDisplayNameFrom(firstname, lastname);
return new ClientData(clientData.officeId, clientData.officeName, clientData.id, firstname, lastname, displayName,
return new ClientData(clientData.accountNo, clientData.officeId, clientData.officeName, clientData.id, firstname, lastname, displayName,
clientData.externalId, clientData.joinedDate, clientData.imageKey, allowedOffices, clientData.currentChange,
clientData.allChanges);
}
public static ClientData clientIdentifier(final Long id, final String firstname, final String lastname, final Long officeId,
public static ClientData clientIdentifier(final Long id, final String accountIdentifier, final String firstname, final String lastname, final Long officeId,
final String officeName) {
final String displayName = buildDisplayNameFrom(firstname, lastname);
return new ClientData(officeId, officeName, id, firstname, lastname, displayName, null, null, null, null, null, null);
return new ClientData(accountIdentifier, officeId, officeName, id, firstname, lastname, displayName, null, null, null, null, null, null);
}
public ClientData(final Long officeId, final String officeName, final Long id, final String firstname, final String lastname,
public ClientData(final String accountNo, final Long officeId, final String officeName, final Long id, final String firstname, final String lastname,
final String displayName, final String externalId, final LocalDate joinedDate, final String imageKey,
final List<OfficeLookup> allowedOffices, final ClientData currentChange, final Collection<ClientData> allChanges) {
this.accountNo = accountNo;
this.officeId = officeId;
this.officeName = officeName;
this.id = id;
@@ -0,0 +1,12 @@
package org.mifosplatform.portfolio.client.domain;
/**
* Responsible for generating unique account identifiers based some rules or patterns.
*
* @see ClientAccountIdentifierGenerator
*/
public interface AccountIdentifierGenerator {
String generate();
}
@@ -15,14 +15,17 @@ import javax.persistence.TemporalType;
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.infrastructure.security.service.RandomPasswordGenerator;
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@Table(name = "m_client")
public class Client extends AbstractAuditableCustom<AppUser, Long> {
public class Client extends AbstractPersistable<Long> {
@Column(name = "account_no", length=40, unique=true, nullable=false)
private String accountNumber;
@ManyToOne
@JoinColumn(name = "office_id", nullable = false)
private Office office;
@@ -78,6 +81,7 @@ public class Client extends AbstractAuditableCustom<AppUser, Long> {
}
private Client(final Office office, final String firstName, final String lastName, final LocalDate openingDate, final String externalId) {
this.accountNumber = new RandomPasswordGenerator(25).generate();
this.office = office;
if (StringUtils.isNotBlank(externalId)) {
this.externalId = externalId.trim();
@@ -110,6 +114,10 @@ public class Client extends AbstractAuditableCustom<AppUser, Long> {
public void changeOffice(final Office newOffice) {
this.office = newOffice;
}
public void updateAccountIdentifier(final String accountIdentifier) {
this.accountNumber = accountIdentifier;
}
public Map<String, Object> update(final JsonCommand command) {
@@ -0,0 +1,21 @@
package org.mifosplatform.portfolio.client.domain;
/**
* Example {@link AccountIdentifierGenerator} for clients that takes clients
* auto generated database id and zero fills it ensuring the identifier is
* always of a given <code>maxLength</code>.
*/
public class ClientAccountIdentifierGenerator implements AccountIdentifierGenerator {
private final Long clientId;
private final int maxLength;
public ClientAccountIdentifierGenerator(final Long clientId, int maxLength) {
this.clientId = clientId;
this.maxLength = maxLength;}
@Override
public String generate() {
return String.format("%0" + maxLength + "d", clientId);
}
}
@@ -130,7 +130,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
private static final class ClientMapper implements RowMapper<ClientData> {
public String clientSchema() {
return "c.office_id as officeId, o.name as officeName, c.id as id, c.firstname as firstname, c.lastname as lastname, c.display_name as displayName, "
return "c.account_no as accountNo, c.office_id as officeId, o.name as officeName, c.id as id, c.firstname as firstname, c.lastname as lastname, c.display_name as displayName, "
+ "c.external_id as externalId, c.joined_date as joinedDate, c.image_key as imagekey from m_client c join m_office o on o.id = c.office_id "
+ " where o.hierarchy like ? and c.is_deleted=0 ";
}
@@ -138,6 +138,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
@Override
public ClientData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final String accountNo = rs.getString("accountNo");
final Long officeId = JdbcSupport.getLong(rs, "officeId");
final Long id = JdbcSupport.getLong(rs, "id");
String firstname = rs.getString("firstname");
@@ -151,7 +152,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final String imageKey = rs.getString("imageKey");
final String officeName = rs.getString("officeName");
return new ClientData(officeId, officeName, id, firstname, lastname, displayName, externalId, joinedDate, imageKey, null, null,
return new ClientData(accountNo, officeId, officeName, id, firstname, lastname, displayName, externalId, joinedDate, imageKey, null, null,
null);
}
@@ -523,7 +524,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
private static final class ClientIdentifierMapper implements RowMapper<ClientData> {
public String clientLookupByIdentifierSchema() {
return "c.id as id, c.firstname as firstname, c.lastname as lastname, " + "c.office_id as officeId, o.name as officeName "
return "c.id as id, c.account_no as accountNo, c.firstname as firstname, c.lastname as lastname, " + "c.office_id as officeId, o.name as officeName "
+ "from m_client c, m_office o, m_client_identifier ci " + "where o.id = c.office_id and c.id=ci.client_id "
+ "and ci.document_type_id= ? and ci.document_key like ?";
}
@@ -532,6 +533,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
public ClientData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String accountNo = rs.getString("accountNo");
String firstname = rs.getString("firstname");
if (StringUtils.isBlank(firstname)) {
firstname = "";
@@ -541,7 +543,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final Long officeId = rs.getLong("officeId");
final String officeName = rs.getString("officeName");
return ClientData.clientIdentifier(id, firstname, lastname, officeId, officeName);
return ClientData.clientIdentifier(id, accountNo, firstname, lastname, officeId, officeName);
}
}
@@ -22,7 +22,9 @@ 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.ClientNoteCommand;
import org.mifosplatform.portfolio.client.domain.AccountIdentifierGenerator;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.domain.ClientAccountIdentifierGenerator;
import org.mifosplatform.portfolio.client.domain.ClientIdentifier;
import org.mifosplatform.portfolio.client.domain.ClientIdentifierRepository;
import org.mifosplatform.portfolio.client.domain.ClientRepository;
@@ -125,7 +127,12 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final Client newClient = Client.fromJson(clientOffice, command);
this.clientRepository.save(newClient);
// now use client account identifier generator to generate proper account number
AccountIdentifierGenerator generator = new ClientAccountIdentifierGenerator(newClient.getId(), 9);
newClient.updateAccountIdentifier(generator.generate());
this.clientRepository.save(newClient);
return EntityIdentifier.resourceResult(newClient.getId(), null);
} catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);