MIFOSX-445: default the list of loan officer options for new loan application to pick up on loan officers in offices higher in its office hierarchy. add optional parameter to allow people to restrict this list to only the selected branch.

This commit is contained in:
Keith Woodlock
2013-06-13 00:13:02 +01:00
parent 2d2028bb69
commit c58d541279
6 changed files with 136 additions and 45 deletions
+13 -2
View File
@@ -3901,12 +3901,14 @@ GET https://DomainName/mifosng-provider/api/v1/groups
<td class=fielddesc>The type of transaction processing strategy to be used.<br>
At present some MFI specific ones exist. This is an important point of change for many MFIs.
<br>Responsible for things like payment order and how early or late repayments should be processed.<br>
Out of the box, four available:
Out of the box options available are:
<ol>
<li>id=1, code=mifos-standard-strategy, name=Mifos style</li>
<li>id=2, code=heavensfamily-strategy, name=Heavensfamily</li>
<li>id=3, code=creocore-strategy, name=Creocore</li>
<li>id=4, code=rbi-india-strategy, name=RBI (India)</li>
<li>id=5, code=principal-interest-penalties-fees-order-strategy, name=Principal Interest Penalties Fees Order</li>
<li>id=6, code=interest-principal-penalties-fees-order-strategy, name=Interest Principal Penalties Fees Order</li>
</ol>
</td>
</tr>
@@ -3973,6 +3975,13 @@ GET https://DomainName/mifosng-provider/api/v1/groups
</dd>
<dd>If entered, productId, productName and selectedProduct
fields are returned.</dd>
<dt>loanOfficersInSelectedOfficeOnly</dt>
<dd>
Boolean <span>optional</span>
</dd>
<dd>Defaults to false if not provided. If <strong>loanOfficersInSelectedOfficeOnly=true</strong> only loan officers
who are associated with the select branch are returned.</dd>
</dl>
<p>Example Requests:</p>
<div class=apiClick>loans/template?templateType=individual&clientId=1</div>
@@ -6995,12 +7004,14 @@ Request Body:
<td class=fielddesc>The type of transaction processing strategy to be used.<br>
At present some MFI specific ones exist. This is an important point of change for many MFIs.
<br>Responsible for things like payment order and how early or late repayments should be processed.<br>
Out of the box, four available:
Out of the box options available are:
<ol>
<li>id=1, code=mifos-standard-strategy, name=Mifos style</li>
<li>id=2, code=heavensfamily-strategy, name=Heavensfamily</li>
<li>id=3, code=creocore-strategy, name=Creocore</li>
<li>id=4, code=rbi-india-strategy, name=RBI (India)</li>
<li>id=5, code=principal-interest-penalties-fees-order-strategy, name=Principal Interest Penalties Fees Order</li>
<li>id=6, code=interest-principal-penalties-fees-order-strategy, name=Interest Principal Penalties Fees Order</li>
</ol>
</td>
</tr>
@@ -22,7 +22,6 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
@@ -81,8 +80,7 @@ public class StaffApiResource {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
final String extraCriteria = getStaffCriteria(sqlSearch, officeId);
final Collection<StaffData> staff = this.readPlatformService.retrieveAllStaff(extraCriteria);
final Collection<StaffData> staff = this.readPlatformService.retrieveAllStaff(sqlSearch, officeId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, staff, RESPONSE_DATA_PARAMETERS);
@@ -131,22 +129,4 @@ public class StaffApiResource {
return this.toApiJsonSerializer.serialize(result);
}
private String getStaffCriteria(final String sqlSearch, final Long officeId) {
String extraCriteria = "";
if (sqlSearch != null) {
extraCriteria = " and (" + sqlSearch + ")";
}
if (officeId != null) {
extraCriteria += " and office_id = " + officeId;
}
if (StringUtils.isNotBlank(extraCriteria)) {
extraCriteria = extraCriteria.substring(4);
}
return extraCriteria;
}
}
@@ -13,9 +13,15 @@ public interface StaffReadPlatformService {
StaffData retrieveStaff(Long staffId);
Collection<StaffData> retrieveAllStaff(final String extraCriteria);
Collection<StaffData> retrieveAllStaffForDropdown(Long officeId);
Collection<StaffData> retrieveAllLoanOfficersByOffice(final Long officeId);
Collection<StaffData> retrieveAllLoanOfficersInOfficeById(final Long officeId);
/**
* returns all loan officers in offices that are above the provided
* <code>officeId</code>.
*/
Collection<StaffData> retrieveAllLoanOfficersInOfficeAndItsParentOfficeHierarchy(Long officeId);
Collection<StaffData> retrieveAllStaff(String sqlSearch, Long officeId);
}
@@ -26,6 +26,7 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final StaffLookupMapper lookupMapper = new StaffLookupMapper();
private final StaffInOfficeHierarchyMapper staffInOfficeHierarchyMapper = new StaffInOfficeHierarchyMapper();
@Autowired
public StaffReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource) {
@@ -56,6 +57,43 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
}
}
private static final class StaffInOfficeHierarchyMapper implements RowMapper<StaffData> {
final String schema;
public StaffInOfficeHierarchyMapper() {
StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("s.id as id, s.office_id as officeId, o.name as officeName,");
sqlBuilder.append("s.firstname as firstname, s.lastname as lastname,");
sqlBuilder.append("s.display_name as displayName, s.is_loan_officer as isLoanOfficer ");
sqlBuilder.append("from m_office o ");
sqlBuilder.append("join m_office ohierarchy on o.hierarchy like concat(ohierarchy.hierarchy, '%') ");
sqlBuilder.append("join m_staff s on s.office_id = ohierarchy.id and s.is_loan_officer is true ");
sqlBuilder.append("where o.id = ? ");
this.schema = sqlBuilder.toString();
}
public String schema() {
return this.schema;
}
@Override
public StaffData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String firstname = rs.getString("firstname");
final String lastname = rs.getString("lastname");
final String displayName = rs.getString("displayName");
final Long officeId = rs.getLong("officeId");
final String officeName = rs.getString("officeName");
final boolean isLoanOfficer = rs.getBoolean("isLoanOfficer");
return StaffData.instance(id, firstname, lastname, displayName, officeId, officeName, isLoanOfficer);
}
}
private static final class StaffLookupMapper implements RowMapper<StaffData> {
private final String schemaSql;
@@ -84,19 +122,7 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
}
@Override
public Collection<StaffData> retrieveAllStaff(final String extraCriteria) {
final StaffMapper rm = new StaffMapper();
String sql = "select " + rm.schema();
if (StringUtils.isNotBlank(extraCriteria)) {
sql += " where " + extraCriteria;
}
sql = sql + " order by s.lastname";
return this.jdbcTemplate.query(sql, rm, new Object[] {});
}
@Override
public Collection<StaffData> retrieveAllLoanOfficersByOffice(final Long officeId) {
public Collection<StaffData> retrieveAllLoanOfficersInOfficeById(final Long officeId) {
return retrieveAllStaff(" office_id=" + officeId + " and is_loan_officer=1");
}
@@ -132,4 +158,48 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
throw new StaffNotFoundException(staffId);
}
}
@Override
public Collection<StaffData> retrieveAllStaff(final String sqlSearch, final Long officeId) {
final String extraCriteria = getStaffCriteria(sqlSearch, officeId);
return retrieveAllStaff(extraCriteria);
}
private Collection<StaffData> retrieveAllStaff(final String extraCriteria) {
final StaffMapper rm = new StaffMapper();
String sql = "select " + rm.schema();
if (StringUtils.isNotBlank(extraCriteria)) {
sql += " where " + extraCriteria;
}
sql = sql + " order by s.lastname";
return this.jdbcTemplate.query(sql, rm, new Object[] {});
}
private String getStaffCriteria(final String sqlSearch, final Long officeId) {
String extraCriteria = "";
if (sqlSearch != null) {
extraCriteria = " and (" + sqlSearch + ")";
}
if (officeId != null) {
extraCriteria += " and office_id = " + officeId;
}
if (StringUtils.isNotBlank(extraCriteria)) {
extraCriteria = extraCriteria.substring(4);
}
return extraCriteria;
}
@Override
public Collection<StaffData> retrieveAllLoanOfficersInOfficeAndItsParentOfficeHierarchy(final Long officeId) {
String sql = "select " + this.staffInOfficeHierarchyMapper.schema();
sql = sql + " order by s.lastname";
return this.jdbcTemplate.query(sql, this.staffInOfficeHierarchyMapper, new Object[] { officeId });
}
}
@@ -88,7 +88,7 @@ public class BulkLoansApiResource {
StaffAccountSummaryCollectionData staffAccountSummaryCollectionData = null;
if (officeId != null) {
loanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(officeId);
loanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersInOfficeById(officeId);
}
if (loanOfficerId != null) {
@@ -5,6 +5,7 @@
*/
package org.mifosplatform.portfolio.loanaccount.api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
@@ -12,6 +13,7 @@ import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
@@ -162,6 +164,7 @@ public class LoansApiResource {
@Produces({ MediaType.APPLICATION_JSON })
public String template(@QueryParam("clientId") final Long clientId, @QueryParam("groupId") final Long groupId,
@QueryParam("productId") final Long productId, @QueryParam("templateType") final String templateType,
@DefaultValue("false") @QueryParam("loanOfficersInSelectedOfficeOnly") final boolean loanOfficersInSelectedOfficeOnly,
@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
@@ -223,7 +226,28 @@ public class LoansApiResource {
throw new NotSupportedLoanTemplateTypeException(errorMsg, templateType);
}
if (officeId != null) allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(officeId);
if (officeId != null) {
if (loanOfficersInSelectedOfficeOnly) {
// only bring back loan officers in selected branch/office
Collection<StaffData> loanOfficersInBranch = this.staffReadPlatformService
.retrieveAllLoanOfficersInOfficeById(officeId);
if (!CollectionUtils.isEmpty(loanOfficersInBranch)) {
allowedLoanOfficers = new ArrayList<StaffData>(loanOfficersInBranch);
}
} else {
// by default bring back all loan officers in selected
// branch/office as well as loan officers in officer above
// this office
Collection<StaffData> loanOfficersInHierarchy = this.staffReadPlatformService
.retrieveAllLoanOfficersInOfficeAndItsParentOfficeHierarchy(officeId);
if (!CollectionUtils.isEmpty(loanOfficersInHierarchy)) {
allowedLoanOfficers = new ArrayList<StaffData>(loanOfficersInHierarchy);
}
}
}
// add product options, allowed loan officers and calendar options
// (calendar options will be null in individual loan)
newLoanAccount = LoanAccountData.associationsAndTemplate(newLoanAccount, productOptions, allowedLoanOfficers, calendarOptions);
@@ -336,9 +360,9 @@ public class LoansApiResource {
chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
if (loanBasicDetails.officeId() != null) {
allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails.officeId());
allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersInOfficeById(loanBasicDetails.officeId());
} else if (loanBasicDetails.groupOfficeId() != null) {
allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails.groupOfficeId());
allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersInOfficeById(loanBasicDetails.groupOfficeId());
}
loanPurposeOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanPurpose");
@@ -492,8 +516,8 @@ public class LoansApiResource {
// for officeId and loanOfficerId in current way!
final LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveOne(loanId);
final Collection<StaffData> allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails
.officeId());
final Collection<StaffData> allowedLoanOfficers = this.staffReadPlatformService
.retrieveAllLoanOfficersInOfficeById(loanBasicDetails.officeId());
final Long fromLoanOfficerId = loanBasicDetails.loanOfficerId();
final BulkTransferLoanOfficerData loanReassignmentData = BulkTransferLoanOfficerData.template(fromLoanOfficerId,