Merge pull request #561 from vishwasbabu/mifosx-436

Mifosx 436
This commit is contained in:
Vishwas Babu A J
2013-09-03 19:56:02 -07:00
30 changed files with 610 additions and 264 deletions
+122 -22
View File
@@ -90,7 +90,7 @@
<body> <body>
<div id="page-wrapper"> <div id="page-wrapper">
<div id="flybar"> <div id="flybar">
<div id="nav-logo">1.8.1.RELEASE API</div> <div id="nav-logo">1.9.0.RELEASE API</div>
<div class="flybar-nav"> <div class="flybar-nav">
<h2 class="flybar-button">Overview</h2> <h2 class="flybar-button">Overview</h2>
<div class="flybar-menu-overview"> <div class="flybar-menu-overview">
@@ -209,8 +209,32 @@
</tr> </tr>
<tr class="alt"> <tr class="alt">
<td></td> <td></td>
<td>clients/{clientId}?command=transfer</td> <td>clients/{clientId}?command=proposeTransfer</td>
<td><a href="#clients_transfer">Transfer Client</a></td> <td><a href="#clients_propose_transfer">Propose a Client Transfer</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>clients/{clientId}?command=withdrawTransfer</td>
<td><a href="#clients_withdraw_transfer">Withdraw Client Transfer Proposal</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr class="alt">
<td></td>
<td>clients/{clientId}?command=acceptTransfer</td>
<td><a href="#clients_accept_transfer">Accept Client Transfer</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>clients/{clientId}?command=rejectTransfer</td>
<td><a href="#clients_reject_transfer">Reject Client Transfer</a></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
@@ -586,7 +610,7 @@
<tr> <tr>
<td></td> <td></td>
<td>groups/{groupId}?command=transferClients</td> <td>groups/{groupId}?command=transferClients</td>
<td><a href="#groups_transfer_clients">Transfer Clients</a></td> <td><a href="#groups_transfer_clients">Bulk Transfer Clients across Groups</a></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
@@ -2138,19 +2162,20 @@ Request Body:
</div> </div>
</div> </div>
<a id="clients_transfer" name="clients_transfer" class="old-syle-anchor">&nbsp;</a> <a id="clients_propose_transfer" name="clients_propose_transfer" class="old-syle-anchor">&nbsp;</a>
<div class="method-section"> <div class="method-section">
<div class="method-description"> <div class="method-description">
<h4>Transfer a Client</h4> <h4>Propose a Client Transfer</h4>
<p>Allows you to transfer a <i>Client</i> between <i>Offices</i>.</p> <p>Allows you to propose the transfer of a <i>Client</i> to a different <i>Offices</i>.</p>
</div> </div>
<div class="method-example"> <div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/clients/{clientId}?command=transfer</code> <code class="method-declaration">POST https://Domain Name/api/v1/clients/{clientId}?command=proposeTransfer</code>
<code class="method-request">POST clients/1?command=transfer <code class="method-request">POST clients/1?command=proposeTransfer
Content-Type: application/json Content-Type: application/json
Request Body: Request Body:
{ {
destinationOfficeId:1 "destinationOfficeId":"2",
"note":"Client Relocating to Bangalore"
} }
</code> </code>
<code class="method-response"> <code class="method-response">
@@ -2163,6 +2188,91 @@ Request Body:
</code> </code>
</div> </div>
</div> </div>
<a id="clients_withdraw_transfer" name="clients_withdraw_transfer" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Withdraw a Client Transfer</h4>
<p>Allows you to withdraw the proposed the transfer of a <i>Client</i> to a different <i>Offices</i>.</p>
<p>Withdrawal can happen only if the destination Branch (to which the transfer was
<a href="#clients_propose_transfer">proposed</a>) has not already
<a href="#clients_accept_transfer">accepted</a> the transfer proposal </p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/clients/{clientId}?command=withdrawTransfer</code>
<code class="method-request">POST clients/1?command=withdrawTransfer
Content-Type: application/json
Request Body:
{
"note":"Sorry, data entry error"
}
</code>
<code class="method-response">
{
"clientId": 2,
"resourceId": 2
}
</code>
</div>
</div>
<a id="clients_reject_transfer" name="clients_reject_transfer" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Reject a Client Transfer</h4>
<p>Allows the Destination Branch to reject the <a href="#clients_propose_transfer">proposed</a> Client Transfer.</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/clients/{clientId}?command=rejectTransfer</code>
<code class="method-request">POST clients/1?command=rejectTransfer
Content-Type: application/json
Request Body:
{
"note":"We cannot accept tranfers of clients having loans with less than 1 repayment left"
}
</code>
<code class="method-response">
{
"clientId": 2,
"resourceId": 2
}
</code>
</div>
</div>
<a id="clients_accept_transfer" name="clients_accept_transfer" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Reject a Client Transfer</h4>
<p>Allows the Destination Branch to accept the <a href="#clients_propose_transfer">proposed</a> Client Transfer.</p>
<p>The destination branch may also choose to link this client to a group (in which case, any existing active JLG loan of the client is rescheduled to match the meeting frequency of the group) and loan Officer at the time of accepting
the transfer</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/clients/{clientId}?command=acceptTransfer</code>
<code class="method-request">POST clients/1?command=acceptTransfer
Content-Type: application/json
Request Body:
{
"note":"Due Diligence done and all documents received"
}
</code>
<code class="method-response">
{
"clientId": 2,
"resourceId": 2
}
</code>
</div>
</div>
<a id="clients_retrieve" name="clients_retrieve" class="old-syle-anchor">&nbsp;</a> <a id="clients_retrieve" name="clients_retrieve" class="old-syle-anchor">&nbsp;</a>
<div class="method-section"> <div class="method-section">
<div class="method-description"> <div class="method-description">
@@ -3866,7 +3976,8 @@ Request Body:
<td>destinationGroupId</td> <td>destinationGroupId</td>
</tr> </tr>
<tr> <tr>
<td class=fielddesc>The identifier of the group to which the clients are to be transferred.</td> <td class=fielddesc>The identifier of the group to which the clients are to be transferred (
has to be in the same branch as the source Group).</td>
</tr> </tr>
<tr class=alt> <tr class=alt>
<td>clients</td> <td>clients</td>
@@ -3883,15 +3994,6 @@ Request Body:
should be linked to the assigned loan officer for the group should be linked to the assigned loan officer for the group
</td> </td>
</tr> </tr>
<tr class=alt>
<td>transferActiveLoans</td>
</tr>
<tr>
<td class=fielddesc>Flag specifies if transfers should proceed when active loans are encountered.
If set to true, the schedules of the actives loans are updated to match that meeting schedule
of the destination Group
</td>
</tr>
</table> </table>
<br/> <br/>
<table class=matrixHeading> <table class=matrixHeading>
@@ -3911,8 +4013,6 @@ Request Body:
<td>inheritDestinationGroupLoanOfficer (defaults to true), transferActiveLoans (defaults to true)</td> <td>inheritDestinationGroupLoanOfficer (defaults to true), transferActiveLoans (defaults to true)</td>
</tr> </tr>
</table> </table>
</div> </div>
@@ -0,0 +1,9 @@
/***Store destination office Id while client is pending transfers and effective joining date in a particular branch**/
ALTER TABLE `m_client`
ADD COLUMN `office_joining_date` DATE NULL AFTER `activation_date`,
ADD COLUMN `transfer_to_office_id` BIGINT(20) NULL AFTER `office_id`,
ADD CONSTRAINT `FK_m_client_m_office` FOREIGN KEY (`transfer_to_office_id`) REFERENCES `m_office` (`id`);
/**For current Clients, set the office joining date to activation date**/
update m_client set office_joining_date=activation_date;
@@ -363,7 +363,7 @@ public class CommandWrapperBuilder {
} }
public CommandWrapperBuilder withdrawClientTransferRequest(final Long clientId) { public CommandWrapperBuilder withdrawClientTransferRequest(final Long clientId) {
this.actionName = "PROPOSETRANSFER"; this.actionName = "WITHDRAWTRANSFER";
this.entityName = "CLIENT"; this.entityName = "CLIENT";
this.entityId = clientId; this.entityId = clientId;
this.clientId = clientId; this.clientId = clientId;
@@ -22,6 +22,10 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation
public class DateUtils { public class DateUtils {
public static Date getDateOfTenant() {
return getLocalDateOfTenant().toDateMidnight().toDate();
}
public static LocalDate getLocalDateOfTenant() { public static LocalDate getLocalDateOfTenant() {
LocalDate today = new LocalDate(); LocalDate today = new LocalDate();
@@ -54,7 +58,7 @@ public class DateUtils {
} }
} }
public static String formatToSqlDate(final Date date){ public static String formatToSqlDate(final Date date) {
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
final String formattedSqlDate = df.format(date); final String formattedSqlDate = df.format(date);
return formattedSqlDate; return formattedSqlDate;
@@ -27,7 +27,7 @@ public interface CalendarInstanceRepository extends JpaRepository<CalendarInstan
Collection<CalendarInstance> findByCalendarIdAndEntityTypeId(Long calendarId, Integer entityTypeId); Collection<CalendarInstance> findByCalendarIdAndEntityTypeId(Long calendarId, Integer entityTypeId);
/**Should use in clause, can I do it without creating a new class?**/ /**Should use in clause, can I do it without creating a new class?**/
@Query("from CalendarInstance ci where ci.entityId in (select id from Loan loan where loan.client.id = :clientId and loan.group.id=:groupId and (loan.loanStatus = 100 or loan.loanStatus = 200 or loan.loanStatus = 300)) and ci.entityTypeId = 3") @Query("from CalendarInstance ci where ci.entityId in (select id from Loan loan where loan.client.id = :clientId and loan.group.id = :groupId and (loan.loanStatus = 100 or loan.loanStatus = 200 or loan.loanStatus = 300)) and ci.entityTypeId = 3")
List<CalendarInstance> findCalendarInstancesForActiveLoansByGroupIdAndClientId(@Param("clientId") Long clientId, List<CalendarInstance> findCalendarInstancesForActiveLoansByGroupIdAndClientId(@Param("clientId") Long clientId,
@Param("groupId") Long groupId); @Param("groupId") Long groupId);
} }
@@ -30,6 +30,7 @@ public class ClientApiConstants {
public static final String lastnameParamName = "lastname"; public static final String lastnameParamName = "lastname";
public static final String fullnameParamName = "fullname"; public static final String fullnameParamName = "fullname";
public static final String officeIdParamName = "officeId"; public static final String officeIdParamName = "officeId";
public static final String transferOfficeIdParamName = "transferOfficeIdParamName";
public static final String activeParamName = "active"; public static final String activeParamName = "active";
public static final String activationDateParamName = "activationDate"; public static final String activationDateParamName = "activationDate";
public static final String staffIdParamName = "staffId"; public static final String staffIdParamName = "staffId";
@@ -40,6 +41,7 @@ public class ClientApiConstants {
public static final String hierarchyParamName = "hierarchy"; public static final String hierarchyParamName = "hierarchy";
public static final String displayNameParamName = "displayName"; public static final String displayNameParamName = "displayName";
public static final String officeNameParamName = "officeName"; public static final String officeNameParamName = "officeName";
public static final String trasnferOfficeNameParamName = "transferOfficeName";
public static final String imageKeyParamName = "imageKey"; public static final String imageKeyParamName = "imageKey";
public static final String imagePresentParamName = "imagePresent"; public static final String imagePresentParamName = "imagePresent";
@@ -55,8 +57,8 @@ public class ClientApiConstants {
lastnameParamName, fullnameParamName, officeIdParamName, activeParamName, activationDateParamName, staffIdParamName)); lastnameParamName, fullnameParamName, officeIdParamName, activeParamName, activationDateParamName, staffIdParamName));
public static final Set<String> CLIENT_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName, public static final Set<String> CLIENT_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, accountNoParamName, externalIdParamName, firstnameParamName, middlenameParamName, dateFormatParamName, accountNoParamName, externalIdParamName, firstnameParamName, middlenameParamName, lastnameParamName,
lastnameParamName, fullnameParamName, activeParamName, activationDateParamName, staffIdParamName)); fullnameParamName, activeParamName, activationDateParamName, staffIdParamName));
/** /**
* These parameters will match the class level parameters of * These parameters will match the class level parameters of
@@ -65,8 +67,9 @@ public class ClientApiConstants {
*/ */
public static final Set<String> CLIENT_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName, accountNoParamName, public static final Set<String> CLIENT_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName, accountNoParamName,
externalIdParamName, statusParamName, activeParamName, activationDateParamName, firstnameParamName, middlenameParamName, externalIdParamName, statusParamName, activeParamName, activationDateParamName, firstnameParamName, middlenameParamName,
lastnameParamName, fullnameParamName, displayNameParamName, officeIdParamName, officeNameParamName, hierarchyParamName, lastnameParamName, fullnameParamName, displayNameParamName, officeIdParamName, officeNameParamName, transferOfficeIdParamName,
imageKeyParamName, imagePresentParamName, groupsParamName, officeOptionsParamName, staffOptionsParamName)); trasnferOfficeNameParamName, hierarchyParamName, imageKeyParamName, imagePresentParamName, groupsParamName,
officeOptionsParamName, staffOptionsParamName));
public static final Set<String> ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName, public static final Set<String> ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, activationDateParamName)); dateFormatParamName, activationDateParamName));
@@ -86,6 +86,8 @@ public class ClientsApiResource {
context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME);
if (is(commandParam, "close")) { if (is(commandParam, "close")) {
clientData = this.clientReadPlatformService.retrieveAllClosureReasons(ClientApiConstants.CLIENT_CLOSURE_REASON); clientData = this.clientReadPlatformService.retrieveAllClosureReasons(ClientApiConstants.CLIENT_CLOSURE_REASON);
} else if (is(commandParam, "acceptTransfer")) {
clientData = this.clientReadPlatformService.retrieveAllClosureReasons(ClientApiConstants.CLIENT_CLOSURE_REASON);
} else { } else {
clientData = this.clientReadPlatformService.retrieveTemplate(officeId, staffInSelectedOfficeOnly); clientData = this.clientReadPlatformService.retrieveTemplate(officeId, staffInSelectedOfficeOnly);
} }
@@ -40,6 +40,8 @@ final public class ClientData implements Comparable<ClientData> {
private final Long officeId; private final Long officeId;
private final String officeName; private final String officeName;
private final Long transferToOfficeId;
private final String transferToOfficeName;
private final Long imageId; private final Long imageId;
private final Boolean imagePresent; private final Boolean imagePresent;
@@ -57,49 +59,52 @@ final public class ClientData implements Comparable<ClientData> {
public static ClientData template(final Long officeId, final LocalDate joinedDate, final Collection<OfficeData> officeOptions, public static ClientData template(final Long officeId, final LocalDate joinedDate, final Collection<OfficeData> officeOptions,
final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons) { final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons) {
return new ClientData(null, null, officeId, null, null, null, null, null, null, null, null, joinedDate, null, null, null, return new ClientData(null, null, officeId, null, null, null, null, null, null, null, null, null, null, joinedDate, null, null,
officeOptions, null, staffOptions, closureReasons); null, officeOptions, null, staffOptions, closureReasons);
} }
public static ClientData templateOnTop(final ClientData clientData, final ClientData templateData) { public static ClientData templateOnTop(final ClientData clientData, final ClientData templateData) {
return new ClientData(clientData.accountNo, clientData.status, clientData.officeId, clientData.officeName, clientData.id, return new ClientData(clientData.accountNo, clientData.status, clientData.officeId, clientData.officeName,
clientData.firstname, clientData.middlename, clientData.lastname, clientData.fullname, clientData.displayName, clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname, clientData.middlename,
clientData.externalId, clientData.activationDate, clientData.imageId, clientData.staffId, clientData.staffName, clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.activationDate,
templateData.officeOptions, clientData.groups, templateData.staffOptions, null); clientData.imageId, clientData.staffId, clientData.staffName, templateData.officeOptions, clientData.groups,
templateData.staffOptions, null);
} }
public static ClientData setParentGroups(final ClientData clientData, final Collection<GroupGeneralData> parentGroups) { public static ClientData setParentGroups(final ClientData clientData, final Collection<GroupGeneralData> parentGroups) {
return new ClientData(clientData.accountNo, clientData.status, clientData.officeId, clientData.officeName, clientData.id, return new ClientData(clientData.accountNo, clientData.status, clientData.officeId, clientData.officeName,
clientData.firstname, clientData.middlename, clientData.lastname, clientData.fullname, clientData.displayName, clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname, clientData.middlename,
clientData.externalId, clientData.activationDate, clientData.imageId, clientData.staffId, clientData.staffName, clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.activationDate,
clientData.officeOptions, parentGroups, clientData.staffOptions, null); clientData.imageId, clientData.staffId, clientData.staffName, clientData.officeOptions, parentGroups,
clientData.staffOptions, null);
} }
public static ClientData clientIdentifier(final Long id, final String accountNo, final EnumOptionData status, final String firstname, public static ClientData clientIdentifier(final Long id, final String accountNo, final EnumOptionData status, final String firstname,
final String middlename, final String lastname, final String fullname, final String displayName, final Long officeId, final String middlename, final String lastname, final String fullname, final String displayName, final Long officeId,
final String officeName) { final String officeName) {
return new ClientData(accountNo, status, officeId, officeName, id, firstname, middlename, lastname, fullname, displayName, null, return new ClientData(accountNo, status, officeId, officeName, null, null, id, firstname, middlename, lastname, fullname,
null, null, null, null, null, null, null, null); displayName, null, null, null, null, null, null, null, null, null);
} }
public static ClientData lookup(final Long id, final String displayName, final Long officeId, final String officeName) { public static ClientData lookup(final Long id, final String displayName, final Long officeId, final String officeName) {
return new ClientData(null, null, officeId, officeName, id, null, null, null, null, displayName, null, null, null, null, null, return new ClientData(null, null, officeId, officeName, null, null, id, null, null, null, null, displayName, null, null, null,
null, null, null, null); null, null, null, null, null, null);
} }
public static ClientData instance(final String accountNo, final EnumOptionData status, final Long officeId, final String officeName, public static ClientData instance(final String accountNo, final EnumOptionData status, final Long officeId, final String officeName,
final Long id, final String firstname, final String middlename, final String lastname, final String fullname, final Long transferToOfficeId, final String transferToOfficeName, final Long id, final String firstname,
final String displayName, final String externalId, final LocalDate activationDate, final Long imageId, final Long staffId, final String middlename, final String lastname, final String fullname, final String displayName, final String externalId,
final String staffName) { final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName) {
return new ClientData(accountNo, status, officeId, officeName, id, firstname, middlename, lastname, fullname, displayName, return new ClientData(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname, middlename,
externalId, activationDate, imageId, staffId, staffName, null, null, null, null); lastname, fullname, displayName, externalId, activationDate, imageId, staffId, staffName, null, null, null, null);
} }
private ClientData(final String accountNo, final EnumOptionData status, final Long officeId, final String officeName, final Long id, private ClientData(final String accountNo, final EnumOptionData status, final Long officeId, final String officeName,
final String firstname, final String middlename, final String lastname, final String fullname, final String displayName, final Long transferToOfficeId, final String transferToOfficeName, final Long id, final String firstname,
final String externalId, final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName, final String middlename, final String lastname, final String fullname, final String displayName, final String externalId,
final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName,
final Collection<OfficeData> allowedOffices, final Collection<GroupGeneralData> groups, final Collection<OfficeData> allowedOffices, final Collection<GroupGeneralData> groups,
final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons) { final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons) {
this.accountNo = accountNo; this.accountNo = accountNo;
@@ -111,6 +116,8 @@ final public class ClientData implements Comparable<ClientData> {
} }
this.officeId = officeId; this.officeId = officeId;
this.officeName = officeName; this.officeName = officeName;
this.transferToOfficeId = transferToOfficeId;
this.transferToOfficeName = transferToOfficeName;
this.id = id; this.id = id;
this.firstname = StringUtils.defaultIfEmpty(firstname, null); this.firstname = StringUtils.defaultIfEmpty(firstname, null);
this.middlename = StringUtils.defaultIfEmpty(middlename, null); this.middlename = StringUtils.defaultIfEmpty(middlename, null);
@@ -55,6 +55,10 @@ public final class Client extends AbstractPersistable<Long> {
@JoinColumn(name = "office_id", nullable = false) @JoinColumn(name = "office_id", nullable = false)
private Office office; private Office office;
@ManyToOne
@JoinColumn(name = "transfer_to_office_id", nullable = true)
private Office transferToOffice;
@OneToOne(optional = true) @OneToOne(optional = true)
@JoinColumn(name = "image_id", nullable = true) @JoinColumn(name = "image_id", nullable = true)
private Image image; private Image image;
@@ -69,6 +73,10 @@ public final class Client extends AbstractPersistable<Long> {
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
private Date activationDate; private Date activationDate;
@Column(name = "office_joining_date", nullable = true)
@Temporal(TemporalType.DATE)
private Date officeJoiningDate;
@Column(name = "firstname", length = 50) @Column(name = "firstname", length = 50)
private String firstname; private String firstname;
@@ -123,13 +131,15 @@ public final class Client extends AbstractPersistable<Long> {
} }
LocalDate activationDate = null; LocalDate activationDate = null;
LocalDate officeJoiningDate = null;
if (active) { if (active) {
status = ClientStatus.ACTIVE; status = ClientStatus.ACTIVE;
activationDate = command.localDateValueOfParameterNamed(ClientApiConstants.activationDateParamName); activationDate = command.localDateValueOfParameterNamed(ClientApiConstants.activationDateParamName);
officeJoiningDate = activationDate;
} }
return new Client(status, clientOffice, clientParentGroup, accountNo, firstname, middlename, lastname, fullname, activationDate, return new Client(status, clientOffice, clientParentGroup, accountNo, firstname, middlename, lastname, fullname, activationDate,
externalId, staff); officeJoiningDate, externalId, staff);
} }
protected Client() { protected Client() {
@@ -138,7 +148,7 @@ public final class Client extends AbstractPersistable<Long> {
private Client(final ClientStatus status, final Office office, final Group clientParentGroup, final String accountNo, private Client(final ClientStatus status, final Office office, final Group clientParentGroup, final String accountNo,
final String firstname, final String middlename, final String lastname, final String fullname, final LocalDate activationDate, final String firstname, final String middlename, final String lastname, final String fullname, final LocalDate activationDate,
final String externalId, final Staff staff) { final LocalDate officeJoiningDate, final String externalId, final Staff staff) {
if (StringUtils.isBlank(accountNo)) { if (StringUtils.isBlank(accountNo)) {
this.accountNumber = new RandomPasswordGenerator(19).generate(); this.accountNumber = new RandomPasswordGenerator(19).generate();
this.accountNumberRequiresAutoGeneration = true; this.accountNumberRequiresAutoGeneration = true;
@@ -155,6 +165,9 @@ public final class Client extends AbstractPersistable<Long> {
if (activationDate != null) { if (activationDate != null) {
this.activationDate = activationDate.toDateMidnight().toDate(); this.activationDate = activationDate.toDateMidnight().toDate();
} }
if (officeJoiningDate != null) {
this.officeJoiningDate = officeJoiningDate.toDateMidnight().toDate();
}
if (StringUtils.isNotBlank(firstname)) { if (StringUtils.isNotBlank(firstname)) {
this.firstname = firstname.trim(); this.firstname = firstname.trim();
} else { } else {
@@ -243,6 +256,7 @@ public final class Client extends AbstractPersistable<Long> {
} }
this.activationDate = activationLocalDate.toDate(); this.activationDate = activationLocalDate.toDate();
this.officeJoiningDate = activationDate;
this.status = ClientStatus.ACTIVE.getValue(); this.status = ClientStatus.ACTIVE.getValue();
validate(); validate();
@@ -260,6 +274,14 @@ public final class Client extends AbstractPersistable<Long> {
return ClientStatus.fromInt(this.status).isTransferInProgress(); return ClientStatus.fromInt(this.status).isTransferInProgress();
} }
public boolean isTransferOnHold() {
return ClientStatus.fromInt(this.status).isTransferOnHold();
}
public boolean isTransferInProgressOrOnHold() {
return isTransferInProgress() || isTransferOnHold();
}
public boolean isNotPending() { public boolean isNotPending() {
return !isPending(); return !isPending();
} }
@@ -334,6 +356,7 @@ public final class Client extends AbstractPersistable<Long> {
final LocalDate newValue = command.localDateValueOfParameterNamed(ClientApiConstants.activationDateParamName); final LocalDate newValue = command.localDateValueOfParameterNamed(ClientApiConstants.activationDateParamName);
this.activationDate = newValue.toDate(); this.activationDate = newValue.toDate();
this.officeJoiningDate = activationDate;
} }
validate(); validate();
@@ -437,10 +460,22 @@ public final class Client extends AbstractPersistable<Long> {
return this.office; return this.office;
} }
public Office getTransferToOffice() {
return this.transferToOffice;
}
public void updateOffice(final Office office) { public void updateOffice(final Office office) {
this.office = office; this.office = office;
} }
public void updateTransferToOffice(final Office office) {
this.transferToOffice = office;
}
public void updateOfficeJoiningDate(final Date date) {
this.officeJoiningDate = date;
}
private Long staffId() { private Long staffId() {
Long staffId = null; Long staffId = null;
if (this.staff != null) { if (this.staff != null) {
@@ -100,7 +100,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
StringBuilder sqlBuilder = new StringBuilder(200); StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append(this.clientMapper.schema()); sqlBuilder.append(this.clientMapper.schema());
sqlBuilder.append(" where o.hierarchy like ?"); sqlBuilder.append(" where o.hierarchy like ? or transferToOffice.hierarchy like ?");
final String extraCriteria = buildSqlStringFromClientCriteria(searchParameters); final String extraCriteria = buildSqlStringFromClientCriteria(searchParameters);
@@ -124,8 +124,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
} }
final String sqlCountRows = "SELECT FOUND_ROWS()"; final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), new Object[] {
new Object[] { hierarchySearchString }, this.clientMapper); hierarchySearchString, hierarchySearchString }, this.clientMapper);
} }
private String buildSqlStringFromClientCriteria(final SearchParameters searchParameters) { private String buildSqlStringFromClientCriteria(final SearchParameters searchParameters) {
@@ -184,9 +184,10 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
String hierarchy = currentUser.getOffice().getHierarchy(); String hierarchy = currentUser.getOffice().getHierarchy();
String hierarchySearchString = hierarchy + "%"; String hierarchySearchString = hierarchy + "%";
String sql = "select " + this.clientMapper.schema() + " where o.hierarchy like ? and c.id = ?"; String sql = "select " + this.clientMapper.schema()
ClientData clientData = this.jdbcTemplate.queryForObject(sql, this.clientMapper, + " where ( o.hierarchy like ? or transferToOffice.hierarchy like ?) and c.id = ?";
new Object[] { hierarchySearchString, clientId }); ClientData clientData = this.jdbcTemplate.queryForObject(sql, this.clientMapper, new Object[] { hierarchySearchString,
hierarchySearchString, clientId });
String clientGroupsSql = "select " + this.clientGroupsMapper.parentGroupsSchema(); String clientGroupsSql = "select " + this.clientGroupsMapper.parentGroupsSchema();
@@ -255,6 +256,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
sqlBuilder.append("c.id as id, c.account_no as accountNo, c.external_id as externalId, c.status_enum as statusEnum, "); sqlBuilder.append("c.id as id, c.account_no as accountNo, c.external_id as externalId, c.status_enum as statusEnum, ");
sqlBuilder.append("c.office_id as officeId, o.name as officeName, "); sqlBuilder.append("c.office_id as officeId, o.name as officeName, ");
sqlBuilder.append("c.transfer_to_office_id as transferToOfficeId, transferToOffice.name as transferToOfficeName, ");
sqlBuilder.append("c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, "); sqlBuilder.append("c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, ");
sqlBuilder.append("c.fullname as fullname, c.display_name as displayName, "); sqlBuilder.append("c.fullname as fullname, c.display_name as displayName, ");
sqlBuilder.append("c.activation_date as activationDate, c.image_id as imageId, "); sqlBuilder.append("c.activation_date as activationDate, c.image_id as imageId, ");
@@ -263,6 +265,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
sqlBuilder.append("join m_office o on o.id = c.office_id "); sqlBuilder.append("join m_office o on o.id = c.office_id ");
sqlBuilder.append("join m_group_client pgc on pgc.client_id = c.id "); sqlBuilder.append("join m_group_client pgc on pgc.client_id = c.id ");
sqlBuilder.append("left join m_staff s on s.id = c.staff_id "); sqlBuilder.append("left join m_staff s on s.id = c.staff_id ");
sqlBuilder.append("left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id ");
this.schema = sqlBuilder.toString(); this.schema = sqlBuilder.toString();
} }
@@ -280,6 +283,11 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final EnumOptionData status = ClientEnumerations.status(statusEnum); final EnumOptionData status = ClientEnumerations.status(statusEnum);
final Long officeId = JdbcSupport.getLong(rs, "officeId"); final Long officeId = JdbcSupport.getLong(rs, "officeId");
final String officeName = rs.getString("officeName");
final Long transferToOfficeId = JdbcSupport.getLong(rs, "transferToOfficeId");
final String transferToOfficeName = rs.getString("transferToOfficeName");
final Long id = JdbcSupport.getLong(rs, "id"); final Long id = JdbcSupport.getLong(rs, "id");
final String firstname = rs.getString("firstname"); final String firstname = rs.getString("firstname");
final String middlename = rs.getString("middlename"); final String middlename = rs.getString("middlename");
@@ -289,12 +297,11 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final String externalId = rs.getString("externalId"); final String externalId = rs.getString("externalId");
final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate"); final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate");
final Long imageId = JdbcSupport.getLong(rs, "imageId"); final Long imageId = JdbcSupport.getLong(rs, "imageId");
final String officeName = rs.getString("officeName");
final Long staffId = JdbcSupport.getLong(rs, "staffId"); final Long staffId = JdbcSupport.getLong(rs, "staffId");
final String staffName = rs.getString("staffName"); final String staffName = rs.getString("staffName");
return ClientData.instance(accountNo, status, officeId, officeName, id, firstname, middlename, lastname, fullname, displayName, return ClientData.instance(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname,
externalId, activationDate, imageId, staffId, staffName); middlename, lastname, fullname, displayName, externalId, activationDate, imageId, staffId, staffName);
} }
} }
@@ -305,7 +312,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final String hierarchy = currentUser.getOffice().getHierarchy(); final String hierarchy = currentUser.getOffice().getHierarchy();
final String hierarchySearchString = hierarchy + "%"; final String hierarchySearchString = hierarchy + "%";
final String sql = "select " + this.membersOfGroupMapper.schema() final String sql = "select "
+ this.membersOfGroupMapper.schema()
+ " left join m_group g on pgc.group_id=g.id where o.hierarchy like ? and g.parent_id = ? and c.status_enum = ? group by c.id"; + " left join m_group g on pgc.group_id=g.id where o.hierarchy like ? and g.parent_id = ? and c.status_enum = ? group by c.id";
return this.jdbcTemplate.query(sql, this.membersOfGroupMapper, return this.jdbcTemplate.query(sql, this.membersOfGroupMapper,
@@ -321,7 +329,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
builder.append("c.id as id, c.account_no as accountNo, c.external_id as externalId, c.status_enum as statusEnum, "); builder.append("c.id as id, c.account_no as accountNo, c.external_id as externalId, c.status_enum as statusEnum, ");
builder.append("c.office_id as officeId, o.name as officeName, "); builder.append("c.office_id as officeId, o.name as officeName, ");
builder.append("c.office_id as officeId, o.name as officeName, "); builder.append("c.transfer_to_office_id as transferToOfficeId, transferToOffice.name as transferToOfficeName, ");
builder.append("c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, "); builder.append("c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, ");
builder.append("c.fullname as fullname, c.display_name as displayName, "); builder.append("c.fullname as fullname, c.display_name as displayName, ");
builder.append("c.activation_date as activationDate, c.image_id as imageId, "); builder.append("c.activation_date as activationDate, c.image_id as imageId, ");
@@ -329,7 +337,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
builder.append("from m_client c "); builder.append("from m_client c ");
builder.append("join m_office o on o.id = c.office_id "); builder.append("join m_office o on o.id = c.office_id ");
builder.append("left join m_staff s on s.id = c.staff_id "); builder.append("left join m_staff s on s.id = c.staff_id ");
builder.append("left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id ");
this.schema = builder.toString(); this.schema = builder.toString();
} }
@@ -346,6 +354,11 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final EnumOptionData status = ClientEnumerations.status(statusEnum); final EnumOptionData status = ClientEnumerations.status(statusEnum);
final Long officeId = JdbcSupport.getLong(rs, "officeId"); final Long officeId = JdbcSupport.getLong(rs, "officeId");
final String officeName = rs.getString("officeName");
final Long transferToOfficeId = JdbcSupport.getLong(rs, "transferToOfficeId");
final String transferToOfficeName = rs.getString("transferToOfficeName");
final Long id = JdbcSupport.getLong(rs, "id"); final Long id = JdbcSupport.getLong(rs, "id");
final String firstname = rs.getString("firstname"); final String firstname = rs.getString("firstname");
final String middlename = rs.getString("middlename"); final String middlename = rs.getString("middlename");
@@ -354,13 +367,12 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final String displayName = rs.getString("displayName"); final String displayName = rs.getString("displayName");
final String externalId = rs.getString("externalId"); final String externalId = rs.getString("externalId");
final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate"); final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate");
final String officeName = rs.getString("officeName");
final Long imageId = JdbcSupport.getLong(rs, "imageId"); final Long imageId = JdbcSupport.getLong(rs, "imageId");
final Long staffId = JdbcSupport.getLong(rs, "staffId"); final Long staffId = JdbcSupport.getLong(rs, "staffId");
final String staffName = rs.getString("staffName"); final String staffName = rs.getString("staffName");
return ClientData.instance(accountNo, status, officeId, officeName, id, firstname, middlename, lastname, fullname, displayName, return ClientData.instance(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname,
externalId, activationDate, imageId, staffId, staffName); middlename, lastname, fullname, displayName, externalId, activationDate, imageId, staffId, staffName);
} }
} }
@@ -5,7 +5,6 @@
*/ */
package org.mifosplatform.portfolio.group.api; package org.mifosplatform.portfolio.group.api;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
@@ -143,22 +142,11 @@ public class GroupsApiResource {
@QueryParam("officeId") final Long officeId, @QueryParam("externalId") final String externalId, @QueryParam("officeId") final Long officeId, @QueryParam("externalId") final String externalId,
@QueryParam("name") final String name, @QueryParam("underHierarchy") final String hierarchy, @QueryParam("name") final String name, @QueryParam("underHierarchy") final String hierarchy,
@QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit, @QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit,
@QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder, @QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder) {
@QueryParam("templateType") final String templateType, @QueryParam("groupId") final Long groupId) {
this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.GROUP_RESOURCE_NAME); this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.GROUP_RESOURCE_NAME);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (templateType != null && templateType.equalsIgnoreCase("clientstransfertemplate")) {
final Collection<GroupGeneralData> groups;
if (officeId != null && groupId != null) {
groups = this.groupReadPlatformService.retrieveGroupsForLookup(officeId, groupId);
} else {
groups = new ArrayList<GroupGeneralData>();
}
return this.groupGeneralApiJsonSerializer.serialize(settings, groups, GroupingTypesApiConstants.GROUP_RESPONSE_DATA_PARAMETERS);
}
final SearchParameters searchParameters = SearchParameters.forGroups(sqlSearch, officeId, externalId, name, hierarchy, offset, final SearchParameters searchParameters = SearchParameters.forGroups(sqlSearch, officeId, externalId, name, hierarchy, offset,
limit, orderBy, sortOrder); limit, orderBy, sortOrder);
final Page<GroupGeneralData> groups = this.groupReadPlatformService.retrieveAll(searchParameters); final Page<GroupGeneralData> groups = this.groupReadPlatformService.retrieveAll(searchParameters);
@@ -204,19 +192,22 @@ public class GroupsApiResource {
} }
} }
if (associationParameters.contains("parentCalendars")) { if (associationParameters.contains("parentCalendars")) {
final List<Integer> calendarTypeOptions = CalendarUtils.createIntegerListFromQueryParameter("all"); final List<Integer> calendarTypeOptions = CalendarUtils.createIntegerListFromQueryParameter("all");
calendars = this.calendarReadPlatformService.retrieveParentCalendarsByEntity(groupId, CalendarEntityType.GROUPS.getValue(), calendarTypeOptions); calendars = this.calendarReadPlatformService.retrieveParentCalendarsByEntity(groupId, CalendarEntityType.GROUPS.getValue(),
calendarTypeOptions);
if (CollectionUtils.isEmpty(calendars)) { if (CollectionUtils.isEmpty(calendars)) {
calendars = null; calendars = null;
} }
} }
if (associationParameters.contains("collectionMeetingCalendar")) { if (associationParameters.contains("collectionMeetingCalendar")) {
if(group.isChildGroup()){ if (group.isChildGroup()) {
collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(group.getParentId(), CalendarEntityType.CENTERS.getValue()); collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(group.getParentId(),
}else { CalendarEntityType.CENTERS.getValue());
collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(groupId, CalendarEntityType.GROUPS.getValue()); } else {
collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(groupId,
CalendarEntityType.GROUPS.getValue());
} }
if(collectionMeetingCalendar != null){ if (collectionMeetingCalendar != null) {
collectionMeetingCalendar = this.calendarReadPlatformService.generateRecurringDate(collectionMeetingCalendar); collectionMeetingCalendar = this.calendarReadPlatformService.generateRecurringDate(collectionMeetingCalendar);
} }
} }
@@ -388,6 +388,14 @@ public final class Group extends AbstractPersistable<Long> {
return GroupingTypeStatus.fromInt(this.status).isTransferInProgress(); return GroupingTypeStatus.fromInt(this.status).isTransferInProgress();
} }
public boolean isTransferOnHold() {
return GroupingTypeStatus.fromInt(this.status).isTransferOnHold();
}
public boolean isTransferInProgressOrOnHold() {
return isTransferInProgress() || isTransferOnHold();
}
public boolean isChildClient(final Long clientId) { public boolean isChildClient(final Long clientId) {
if (clientId != null && this.clientMembers != null && !this.clientMembers.isEmpty()) { if (clientId != null && this.clientMembers != null && !this.clientMembers.isEmpty()) {
for (final Client client : this.clientMembers) { for (final Client client : this.clientMembers) {
@@ -18,5 +18,5 @@ public interface GroupReadPlatformService {
GroupGeneralData retrieveOne(Long groupId); GroupGeneralData retrieveOne(Long groupId);
Collection<GroupGeneralData> retrieveGroupsForLookup(Long officeId, Long groupId); Collection<GroupGeneralData> retrieveGroupsForLookup(Long officeId);
} }
@@ -206,17 +206,17 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
} }
@Override @Override
public Collection<GroupGeneralData> retrieveGroupsForLookup(final Long officeId, final Long groupId) { public Collection<GroupGeneralData> retrieveGroupsForLookup(final Long officeId) {
this.context.authenticatedUser(); this.context.authenticatedUser();
GroupLookupDataMapper rm = new GroupLookupDataMapper(); GroupLookupDataMapper rm = new GroupLookupDataMapper();
String sql = "Select " + rm.schema() + " where g.office_id=? and g.id !=?"; String sql = "Select " + rm.schema() + " and g.office_id=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { officeId, groupId }); return this.jdbcTemplate.query(sql, rm, new Object[] { officeId });
} }
private static final class GroupLookupDataMapper implements RowMapper<GroupGeneralData> { private static final class GroupLookupDataMapper implements RowMapper<GroupGeneralData> {
public final String schema() { public final String schema() {
return "g.id as id, g.display_name as displayName from m_group g"; return "g.id as id, g.display_name as displayName from m_group g where g.level_id = 2 ";
} }
@Override @Override
@@ -52,7 +52,7 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
public static final String FIND_ACTIVE_LOANS_PRODUCT_IDS_BY_GROUP = "Select loan.loanProduct.id from Loan loan where " public static final String FIND_ACTIVE_LOANS_PRODUCT_IDS_BY_GROUP = "Select loan.loanProduct.id from Loan loan where "
+ "loan.group.id = :groupId and loan.loanStatus = :loanStatus and loan.client.id is NULL group by loan.loanProduct.id"; + "loan.group.id = :groupId and loan.loanStatus = :loanStatus and loan.client.id is NULL group by loan.loanProduct.id";
public static final String DOES_CLIENT_HAVE_ACTIVE_LOANS = "select case when (count (loan) > 0) then true else false end from Loan loan where loan.client.id = :clientId and loan.loanStatus in (100,200,300,303,304)"; public static final String DOES_CLIENT_HAVE_NON_CLOSED_LOANS = "select case when (count (loan) > 0) then true else false end from Loan loan where loan.client.id = :clientId and loan.loanStatus in (100,200,300,303,304)";
@Query(FIND_GROUP_LOANS_DISBURSED_AFTER) @Query(FIND_GROUP_LOANS_DISBURSED_AFTER)
List<Loan> getGroupLoansDisbursedAfter(@Param("disbursementDate") Date disbursementDate, @Param("groupId") Long groupId, List<Loan> getGroupLoansDisbursedAfter(@Param("disbursementDate") Date disbursementDate, @Param("groupId") Long groupId,
@@ -117,7 +117,7 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
@Query(FIND_ACTIVE_LOANS_PRODUCT_IDS_BY_GROUP) @Query(FIND_ACTIVE_LOANS_PRODUCT_IDS_BY_GROUP)
List<Long> findActiveLoansLoanProductIdsByGroup(@Param("groupId") Long groupId, @Param("loanStatus") Integer loanStatus); List<Long> findActiveLoansLoanProductIdsByGroup(@Param("groupId") Long groupId, @Param("loanStatus") Integer loanStatus);
@Query(DOES_CLIENT_HAVE_ACTIVE_LOANS) @Query(DOES_CLIENT_HAVE_NON_CLOSED_LOANS)
boolean doesClientHaveActiveLoans(@Param("clientId") Long clientId); boolean doNonClosedLoanAccountsExistForClient(@Param("clientId") Long clientId);
} }
@@ -137,6 +137,13 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
.getTotalPenaltyChargesOutstanding(), false, null); .getTotalPenaltyChargesOutstanding(), false, null);
} }
public static LoanTransaction withdrawTransfer(final Office office, final Loan loan, final LocalDate transferDate) {
return new LoanTransaction(loan, office, LoanTransactionType.APPROVE_TRANSFER.getValue(), transferDate.toDateMidnight().toDate(),
loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary()
.getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary()
.getTotalPenaltyChargesOutstanding(), false, null);
}
public static LoanTransaction refund(final Office office, final Money amount, final PaymentDetail paymentDetail, public static LoanTransaction refund(final Office office, final Money amount, final PaymentDetail paymentDetail,
final LocalDate paymentDate, final String externalId) { final LocalDate paymentDate, final String externalId) {
return new LoanTransaction(null, office, LoanTransactionType.REFUND, paymentDetail, amount.getAmount(), paymentDate, externalId); return new LoanTransaction(null, office, LoanTransactionType.REFUND, paymentDetail, amount.getAmount(), paymentDate, externalId);
@@ -178,7 +178,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
/*** TODO Vishwas: Remove references to "Contra" from the codebase ***/ /*** TODO Vishwas: Remove references to "Contra" from the codebase ***/
String sql = "select " String sql = "select "
+ rm.LoanPaymentsSchema() + rm.LoanPaymentsSchema()
+ " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 3) and tr.is_reversed=0 order by tr.transaction_date ASC"; + " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 3) and tr.is_reversed=0 order by tr.transaction_date ASC,id ";
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId }); return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
} catch (EmptyResultDataAccessException e) { } catch (EmptyResultDataAccessException e) {
return null; return null;
@@ -11,6 +11,8 @@ import java.util.Map;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.portfolio.calendar.domain.Calendar; import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance; import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand; import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
@@ -59,9 +61,10 @@ public interface LoanWritePlatformService {
LoanTransaction initiateLoanTransfer(Long accountId, LocalDate TransferDate); LoanTransaction initiateLoanTransfer(Long accountId, LocalDate TransferDate);
LoanTransaction acceptLoanTransfer(Long accountId, LocalDate TransferDate);
LoanTransaction withdrawLoanTransfer(Long accountId, LocalDate TransferDate); LoanTransaction withdrawLoanTransfer(Long accountId, LocalDate TransferDate);
LoanTransaction rejectLoanTransfer(Long accountId, LocalDate TransferDate); void rejectLoanTransfer(Long accountId);
LoanTransaction acceptLoanTransfer(Long accountId, LocalDate TransferDate, Office acceptedInOffice, Staff loanOfficer);
} }
@@ -53,7 +53,6 @@ import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedExce
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException; import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException; import org.mifosplatform.portfolio.client.exception.ClientNotActiveException;
import org.mifosplatform.portfolio.client.exception.ClientNotAwaitingTransferApprovalException;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand; import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand; import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
import org.mifosplatform.portfolio.collectionsheet.command.SingleDisbursalCommand; import org.mifosplatform.portfolio.collectionsheet.command.SingleDisbursalCommand;
@@ -922,15 +921,38 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Transactional @Transactional
@Override @Override
public LoanTransaction acceptLoanTransfer(final Long accountId, final LocalDate TransferDate) { public LoanTransaction acceptLoanTransfer(final Long accountId, final LocalDate transferDate, final Office acceptedInOffice,
final Staff loanOfficer) {
final Loan loan = this.loanAssembler.assembleFrom(accountId); final Loan loan = this.loanAssembler.assembleFrom(accountId);
validateClientOrGroupAwaitingTransferAcceptance(loan);
final List<Long> existingTransactionIds = new ArrayList<Long>(loan.findExistingTransactionIds()); final List<Long> existingTransactionIds = new ArrayList<Long>(loan.findExistingTransactionIds());
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(loan.findExistingReversedTransactionIds()); final List<Long> existingReversedTransactionIds = new ArrayList<Long>(loan.findExistingReversedTransactionIds());
final LoanTransaction newTransferAcceptanceTransaction = LoanTransaction.approveTransfer(loan.getOffice(), loan, TransferDate); final LoanTransaction newTransferAcceptanceTransaction = LoanTransaction.approveTransfer(acceptedInOffice, loan, transferDate);
loan.getLoanTransactions().add(newTransferAcceptanceTransaction);
loan.setLoanStatus(LoanStatus.ACTIVE.getValue());
if (loanOfficer != null) {
loan.reassignLoanOfficer(loanOfficer, transferDate);
}
this.loanTransactionRepository.save(newTransferAcceptanceTransaction);
this.loanRepository.save(loan);
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
return newTransferAcceptanceTransaction;
}
@Transactional
@Override
public LoanTransaction withdrawLoanTransfer(Long accountId, LocalDate TransferDate) {
final Loan loan = this.loanAssembler.assembleFrom(accountId);
final List<Long> existingTransactionIds = new ArrayList<Long>(loan.findExistingTransactionIds());
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(loan.findExistingReversedTransactionIds());
final LoanTransaction newTransferAcceptanceTransaction = LoanTransaction.withdrawTransfer(loan.getOffice(), loan, TransferDate);
loan.getLoanTransactions().add(newTransferAcceptanceTransaction); loan.getLoanTransactions().add(newTransferAcceptanceTransaction);
loan.setLoanStatus(LoanStatus.ACTIVE.getValue()); loan.setLoanStatus(LoanStatus.ACTIVE.getValue());
@@ -944,16 +966,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Transactional @Transactional
@Override @Override
public LoanTransaction withdrawLoanTransfer(Long accountId, LocalDate TransferDate) { public void rejectLoanTransfer(Long accountId) {
// TODO Auto-generated method stub final Loan loan = this.loanAssembler.assembleFrom(accountId);
return null; loan.setLoanStatus(LoanStatus.TRANSFER_ON_HOLD.getValue());
} this.loanRepository.save(loan);
@Transactional
@Override
public LoanTransaction rejectLoanTransfer(Long accountId, LocalDate TransferDate) {
// TODO Auto-generated method stub
return null;
} }
@Transactional @Transactional
@@ -1321,15 +1337,4 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
} }
private void validateClientOrGroupAwaitingTransferAcceptance(final Loan loan) {
final Client client = loan.client();
if (client != null) {
if (!client.isTransferInProgress()) { throw new ClientNotAwaitingTransferApprovalException(client.getId()); }
}
final Group group = loan.group();
if (group != null) {
if (!group.isTransferInProgress()) { throw new ClientNotAwaitingTransferApprovalException(group.getId()); }
}
}
} }
@@ -76,7 +76,7 @@ public class Note extends AbstractAuditableCustom<AppUser, Long> {
return new Note(account, note); return new Note(account, note);
} }
private Note(final Client client, final String note) { public Note(final Client client, final String note) {
this.client = client; this.client = client;
this.note = note; this.note = note;
this.noteTypeId = NoteType.CLIENT.getValue(); this.noteTypeId = NoteType.CLIENT.getValue();
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.note.service;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.client.domain.Client;
public interface NoteWritePlatformService { public interface NoteWritePlatformService {
@@ -15,4 +16,6 @@ public interface NoteWritePlatformService {
CommandProcessingResult updateNote(JsonCommand command); CommandProcessingResult updateNote(JsonCommand command);
CommandProcessingResult deleteNote(JsonCommand command); CommandProcessingResult deleteNote(JsonCommand command);
void createAndPersistClientNote(Client client, JsonCommand command);
} }
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.note.service;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
@@ -73,6 +74,15 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
} }
@Override
public void createAndPersistClientNote(final Client client, final JsonCommand command) {
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
final Note newNote = new Note(client, noteText);
this.noteRepository.save(newNote);
}
}
private CommandProcessingResult createGroupNote(final JsonCommand command) { private CommandProcessingResult createGroupNote(final JsonCommand command) {
final Long resourceId = command.getSupportedEntityId(); final Long resourceId = command.getSupportedEntityId();
@@ -20,7 +20,9 @@ public interface SavingsAccountRepository extends JpaRepository<SavingsAccount,
@Query("from SavingsAccount s_acc where s_acc.status = :status") @Query("from SavingsAccount s_acc where s_acc.status = :status")
List<SavingsAccount> findSavingAccountByStatus(@Param("status") Integer status); List<SavingsAccount> findSavingAccountByStatus(@Param("status") Integer status);
@Query("from SavingsAccount sa where sa.client.id = :clientId and sa.group.id = :groupId") @Query("from SavingsAccount sa where sa.client.id = :clientId and sa.group.id = :groupId")
List<SavingsAccount> findByClientIdAndGroupId(@Param("clientId") Long clientId, @Param("groupId") Long groupId); List<SavingsAccount> findByClientIdAndGroupId(@Param("clientId") Long clientId, @Param("groupId") Long groupId);
@Query("select case when (count (saving) > 0) then true else false end from SavingsAccount saving where saving.client.id = :clientId and saving.status in (100,200,300,303,304)")
boolean doNonClosedSavingAccountsExistForClient(@Param("clientId") Long clientId);
} }
@@ -20,15 +20,23 @@ public class TransferApiConstants {
public static final String destinationGroupIdParamName = "destinationGroupId"; public static final String destinationGroupIdParamName = "destinationGroupId";
public static final String clients = "clients"; public static final String clients = "clients";
public static final String inheritDestinationGroupLoanOfficer = "inheritDestinationGroupLoanOfficer"; public static final String inheritDestinationGroupLoanOfficer = "inheritDestinationGroupLoanOfficer";
public static final String newStaffIdParamName = "newStaffId"; public static final String newStaffIdParamName = "staffId";
public static final String transferActiveLoans = "transferActiveLoans"; public static final String transferActiveLoans = "transferActiveLoans";
public static final String destinationOfficeIdParamName = "destinationOfficeId"; public static final String destinationOfficeIdParamName = "destinationOfficeId";
public static final String note = "note";
public static final Set<String> TRANSFER_CLIENTS_BETWEEN_GROUPS_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName, public static final Set<String> TRANSFER_CLIENTS_BETWEEN_GROUPS_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, destinationGroupIdParamName, clients, inheritDestinationGroupLoanOfficer, newStaffIdParamName, dateFormatParamName, destinationGroupIdParamName, clients, inheritDestinationGroupLoanOfficer, newStaffIdParamName,
transferActiveLoans)); transferActiveLoans));
public static final Set<String> PROPOSE_CLIENT_TRANSFER_BETWEEN_BRANCHES_DATA_PARAMETERS = new HashSet<String>(Arrays.asList( public static final Set<String> PROPOSE_CLIENT_TRANSFER_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
localeParamName, dateFormatParamName, destinationOfficeIdParamName, newStaffIdParamName, transferActiveLoans)); dateFormatParamName, destinationOfficeIdParamName, transferActiveLoans, note));
public static final Set<String> ACCEPT_CLIENT_TRANSFER_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(newStaffIdParamName,
destinationGroupIdParamName, note));
public static final Set<String> REJECT_CLIENT_TRANSFER_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(note));
public static final Set<String> WITHDRAW_CLIENT_TRANSFER_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(note));
} }
@@ -63,13 +63,6 @@ public final class TransfersDataValidator {
.integerGreaterThanZero(); .integerGreaterThanZero();
} }
if (this.fromApiJsonHelper.parameterExists(TransferApiConstants.transferActiveLoans, element)) {
final Boolean inheritDestinationGroupLoanOfficer = this.fromApiJsonHelper.extractBooleanNamed(
TransferApiConstants.transferActiveLoans, element);
baseDataValidator.reset().parameter(TransferApiConstants.transferActiveLoans).value(inheritDestinationGroupLoanOfficer)
.notNull();
}
if (this.fromApiJsonHelper.parameterExists(TransferApiConstants.inheritDestinationGroupLoanOfficer, element)) { if (this.fromApiJsonHelper.parameterExists(TransferApiConstants.inheritDestinationGroupLoanOfficer, element)) {
final Boolean inheritDestinationGroupLoanOfficer = this.fromApiJsonHelper.extractBooleanNamed( final Boolean inheritDestinationGroupLoanOfficer = this.fromApiJsonHelper.extractBooleanNamed(
TransferApiConstants.inheritDestinationGroupLoanOfficer, element); TransferApiConstants.inheritDestinationGroupLoanOfficer, element);
@@ -80,13 +73,12 @@ public final class TransfersDataValidator {
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
public void validateForProposeClientTransferBetweenBranches(final String json) { public void validateForProposeClientTransfer(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, TransferApiConstants.PROPOSE_CLIENT_TRANSFER_DATA_PARAMETERS);
TransferApiConstants.PROPOSE_CLIENT_TRANSFER_BETWEEN_BRANCHES_DATA_PARAMETERS);
final JsonElement element = this.fromApiJsonHelper.parse(json); final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
@@ -99,13 +91,76 @@ public final class TransfersDataValidator {
baseDataValidator.reset().parameter(TransferApiConstants.destinationOfficeIdParamName).value(destinationOfficeId).notNull() baseDataValidator.reset().parameter(TransferApiConstants.destinationOfficeIdParamName).value(destinationOfficeId).notNull()
.integerGreaterThanZero(); .integerGreaterThanZero();
if (this.fromApiJsonHelper.parameterExists(TransferApiConstants.newStaffIdParamName, element)) { validateNote(baseDataValidator, element);
final Long newStaffId = this.fromApiJsonHelper.extractLongNamed(TransferApiConstants.newStaffIdParamName, element);
baseDataValidator.reset().parameter(TransferApiConstants.newStaffIdParamName).value(newStaffId).ignoreIfNull()
.integerGreaterThanZero();
}
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
public void validateForAcceptClientTransfer(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, TransferApiConstants.ACCEPT_CLIENT_TRANSFER_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(ClientApiConstants.CLIENT_RESOURCE_NAME);
final JsonElement element = fromApiJsonHelper.parse(json);
if (this.fromApiJsonHelper.parameterExists(TransferApiConstants.newStaffIdParamName, element)) {
final Long newStaffId = this.fromApiJsonHelper.extractLongNamed(TransferApiConstants.newStaffIdParamName, element);
baseDataValidator.reset().parameter(TransferApiConstants.newStaffIdParamName).value(newStaffId).notNull()
.integerGreaterThanZero();
}
if (this.fromApiJsonHelper.parameterExists(TransferApiConstants.destinationGroupIdParamName, element)) {
final Long destinationGroupId = this.fromApiJsonHelper.extractLongNamed(TransferApiConstants.destinationGroupIdParamName,
element);
baseDataValidator.reset().parameter(TransferApiConstants.destinationGroupIdParamName).value(destinationGroupId).notNull()
.integerGreaterThanZero();
}
validateNote(baseDataValidator, element);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForRejectClientTransfer(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, TransferApiConstants.REJECT_CLIENT_TRANSFER_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(ClientApiConstants.CLIENT_RESOURCE_NAME);
final JsonElement element = fromApiJsonHelper.parse(json);
validateNote(baseDataValidator, element);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForWithdrawClientTransfer(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper
.checkForUnsupportedParameters(typeOfMap, json, TransferApiConstants.WITHDRAW_CLIENT_TRANSFER_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(ClientApiConstants.CLIENT_RESOURCE_NAME);
final JsonElement element = fromApiJsonHelper.parse(json);
validateNote(baseDataValidator, element);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void validateNote(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
final String note = fromApiJsonHelper.extractStringNamed(TransferApiConstants.note, element);
baseDataValidator.reset().parameter(TransferApiConstants.note).value(note).notExceedingLengthOf(1000);
}
} }
@@ -1,4 +1,4 @@
package org.mifosplatform.portfolio.client.exception; package org.mifosplatform.portfolio.transfer.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
@@ -0,0 +1,12 @@
package org.mifosplatform.portfolio.transfer.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class ClientNotAwaitingTransferApprovalOrOnHoldException extends AbstractPlatformDomainRuleException {
public ClientNotAwaitingTransferApprovalOrOnHoldException(final Long clientId) {
super("error.msg.client.not.awaiting.transfer.approval.or.on.hold.exception", "The Client with id `" + clientId
+ "` is neither awaiting a transfer nor on hold", clientId);
}
}
@@ -13,39 +13,39 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRul
*/ */
public class TransferNotSupportedException extends AbstractPlatformDomainRuleException { public class TransferNotSupportedException extends AbstractPlatformDomainRuleException {
/** /*** enum of reasons for invalid Journal Entry **/
* Default Constructor (cannot transfer entities with active loan/savings public static enum TRANSFER_NOT_SUPPORTED_REASON {
* accounts) SOURCE_AND_DESTINATION_GROUP_CANNOT_BE_SAME, ACTIVE_SAVINGS_ACCOUNT, BULK_CLIENT_TRANSFER_ACROSS_BRANCHES, DESTINATION_GROUP_MEETING_FREQUENCY_MISMATCH, DESTINATION_GROUP_HAS_NO_MEETING;
*/
public TransferNotSupportedException() { public String errorMessage() {
super("error.msg.entity.transfers.with.active.accounts", "Cannot transfer Clients/Groups having active loan or savings accounts"); if (name().toString().equalsIgnoreCase("ACTIVE_SAVINGS_ACCOUNT")) {
return "Cannot transfer Clients/Groups having active Savings accounts";
} else if (name().toString().equalsIgnoreCase("BULK_CLIENT_TRANSFER_ACROSS_BRANCHES")) {
return "Bulk Transfers of clients between Groups in different branches not allowed ";
} else if (name().toString().equalsIgnoreCase("DESTINATION_GROUP_MEETING_FREQUENCY_MISMATCH")) {
return "Cannot transfer Clients with active accounts between groups with different meeting frequency";
} else if (name().toString().equalsIgnoreCase("SOURCE_AND_DESTINATION_GROUP_CANNOT_BE_SAME")) {
return "Source and destination groups for bulk client transfers should be different";
} else if (name().toString().equalsIgnoreCase("DESTINATION_GROUP_HAS_NO_MEETING")) { return "Cannot transfer Client with active accounts to a groups with no meeting frequency"; }
return name().toString();
}
public String errorCode() {
if (name().toString().equalsIgnoreCase("ACTIVE_SAVINGS_ACCOUNT")) {
return "error.msg.entity.transfers.with.active.savings.accounts";
} else if (name().toString().equalsIgnoreCase("BULK_CLIENT_TRANSFER_ACROSS_BRANCHES")) {
return "error.msg.groups.bulk.client.transfers.to.different.office";
} else if (name().toString().equalsIgnoreCase("DESTINATION_GROUP_MEETING_FREQUENCY_MISMATCH")) {
return "error.msg.client.transfers.with.active.accounts.between.groups.with.different.meeting.frequency";
} else if (name().toString().equalsIgnoreCase("SOURCE_AND_DESTINATION_GROUP_CANNOT_BE_SAME")) {
return "error.msg.groups.bulk.client.transfers.to.same.group";
} else if (name().toString().equalsIgnoreCase("DESTINATION_GROUP_HAS_NO_MEETING")) { return "error.msg.client.transfers.with.active.accounts.to.group.with.no.meeting.frequencys"; }
return name().toString();
}
} }
/** public TransferNotSupportedException(final TRANSFER_NOT_SUPPORTED_REASON reason, final Object... defaultUserMessageArgs) {
* Overloaded Constructor (Cannot transfer Clients with active accounts super(reason.errorCode(), reason.errorMessage(), defaultUserMessageArgs);
* between groups with different meeting frequency)
*
* @param clientId
* @param sourceGroupId
* @param destinationGroupId
*/
public TransferNotSupportedException(Long clientId, Long sourceGroupId, Long destinationGroupId) {
super("error.msg.client.transfers.with.active.accounts.between.groups.with.different.meeting.frequency",
"Cannot transfer Clients with active accounts between groups with different meeting frequency", clientId, sourceGroupId,
destinationGroupId);
} }
/**
* Overloaded Constructor (Cannot transfer Clients with active (JLG)
* accounts to a group with no meetings defined)
*
* @param clientId
* @param sourceGroupId
* @param destinationGroupId
*/
public TransferNotSupportedException(Long clientId, Long sourceGroupId, Long destinationGroupId, boolean destinationGroupMeetingAbsent) {
super("error.msg.client.transfers.with.active.accounts.to.group.with.no.meeting.frequency",
"Cannot transfer Client with active accounts to a groups with no meeting frequency", clientId, sourceGroupId,
destinationGroupId,destinationGroupMeetingAbsent);
}
} }
@@ -6,6 +6,7 @@
package org.mifosplatform.portfolio.transfer.service; package org.mifosplatform.portfolio.transfer.service;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
@@ -15,6 +16,7 @@ import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.organisation.office.domain.Office; import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.office.domain.OfficeRepositoryWrapper; import org.mifosplatform.organisation.office.domain.OfficeRepositoryWrapper;
import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
import org.mifosplatform.portfolio.calendar.domain.Calendar; import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType; import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance; import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
@@ -31,13 +33,19 @@ import org.mifosplatform.portfolio.group.exception.ClientNotInGroupException;
import org.mifosplatform.portfolio.loanaccount.domain.Loan; import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository; import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService; import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
import org.mifosplatform.portfolio.note.service.NoteWritePlatformService;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepository;
import org.mifosplatform.portfolio.transfer.api.TransferApiConstants; import org.mifosplatform.portfolio.transfer.api.TransferApiConstants;
import org.mifosplatform.portfolio.transfer.data.TransfersDataValidator; import org.mifosplatform.portfolio.transfer.data.TransfersDataValidator;
import org.mifosplatform.portfolio.transfer.exception.ClientNotAwaitingTransferApprovalException;
import org.mifosplatform.portfolio.transfer.exception.ClientNotAwaitingTransferApprovalOrOnHoldException;
import org.mifosplatform.portfolio.transfer.exception.TransferNotSupportedException; import org.mifosplatform.portfolio.transfer.exception.TransferNotSupportedException;
import org.mifosplatform.portfolio.transfer.exception.TransferNotSupportedException.TRANSFER_NOT_SUPPORTED_REASON;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Iterables;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@@ -50,13 +58,18 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
private final GroupRepositoryWrapper groupRepository; private final GroupRepositoryWrapper groupRepository;
private final LoanWritePlatformService loanWritePlatformService; private final LoanWritePlatformService loanWritePlatformService;
private final LoanRepository loanRepository; private final LoanRepository loanRepository;
private final SavingsAccountRepository savingsAccountRepository;
private final TransfersDataValidator transfersDataValidator; private final TransfersDataValidator transfersDataValidator;
private final NoteWritePlatformService noteWritePlatformService;
private final StaffRepositoryWrapper staffRepositoryWrapper;
@Autowired @Autowired
public TransferWritePlatformServiceJpaRepositoryImpl(final ClientRepositoryWrapper clientRepository, public TransferWritePlatformServiceJpaRepositoryImpl(final ClientRepositoryWrapper clientRepository,
final OfficeRepositoryWrapper officeRepository, final CalendarInstanceRepository calendarInstanceRepository, final OfficeRepositoryWrapper officeRepository, final CalendarInstanceRepository calendarInstanceRepository,
final LoanWritePlatformService loanWritePlatformService, final GroupRepositoryWrapper groupRepository, final LoanWritePlatformService loanWritePlatformService, final GroupRepositoryWrapper groupRepository,
final LoanRepository loanRepository, final TransfersDataValidator transfersDataValidator) { final LoanRepository loanRepository, final TransfersDataValidator transfersDataValidator,
final NoteWritePlatformService noteWritePlatformService, final StaffRepositoryWrapper staffRepositoryWrapper,
final SavingsAccountRepository savingsAccountRepository) {
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
this.officeRepository = officeRepository; this.officeRepository = officeRepository;
this.calendarInstanceRepository = calendarInstanceRepository; this.calendarInstanceRepository = calendarInstanceRepository;
@@ -64,6 +77,9 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
this.groupRepository = groupRepository; this.groupRepository = groupRepository;
this.loanRepository = loanRepository; this.loanRepository = loanRepository;
this.transfersDataValidator = transfersDataValidator; this.transfersDataValidator = transfersDataValidator;
this.noteWritePlatformService = noteWritePlatformService;
this.staffRepositoryWrapper = staffRepositoryWrapper;
this.savingsAccountRepository = savingsAccountRepository;
} }
@Override @Override
@@ -74,11 +90,26 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
final Group sourceGroup = this.groupRepository.findOneWithNotFoundDetection(sourceGroupId); final Group sourceGroup = this.groupRepository.findOneWithNotFoundDetection(sourceGroupId);
final Long destinationGroupId = jsonCommand.longValueOfParameterNamed(TransferApiConstants.destinationGroupIdParamName); final Long destinationGroupId = jsonCommand.longValueOfParameterNamed(TransferApiConstants.destinationGroupIdParamName);
final Group destinationGroup = this.groupRepository.findOneWithNotFoundDetection(destinationGroupId); final Group destinationGroup = this.groupRepository.findOneWithNotFoundDetection(destinationGroupId);
final Long staffId = jsonCommand.longValueOfParameterNamed(TransferApiConstants.newStaffIdParamName);
final Boolean inheritDestinationGroupLoanOfficer = jsonCommand
.booleanObjectValueOfParameterNamed(TransferApiConstants.inheritDestinationGroupLoanOfficer);
Staff staff = null;
final Office sourceOffice = sourceGroup.getOffice();
if (staffId != null) {
staff = this.staffRepositoryWrapper.findByOfficeHierarchyWithNotFoundDetection(staffId, sourceOffice.getHierarchy());
}
final List<Client> clients = this.assembleListOfClients(jsonCommand); final List<Client> clients = this.assembleListOfClients(jsonCommand);
if (sourceGroupId == destinationGroupId) { throw new TransferNotSupportedException(
TRANSFER_NOT_SUPPORTED_REASON.SOURCE_AND_DESTINATION_GROUP_CANNOT_BE_SAME, sourceGroupId, destinationGroupId); }
/*** Do not allow bulk client transfers across branches ***/
if (!(sourceOffice.getId() == destinationGroup.getOffice().getId())) { throw new TransferNotSupportedException(
TRANSFER_NOT_SUPPORTED_REASON.BULK_CLIENT_TRANSFER_ACROSS_BRANCHES, sourceGroupId, destinationGroupId); }
for (Client client : clients) { for (Client client : clients) {
transferClientBetweenGroups(sourceGroup, client, destinationGroup); transferClientBetweenGroups(sourceGroup, client, destinationGroup, inheritDestinationGroupLoanOfficer, staff);
} }
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
@@ -89,80 +120,64 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
/**** /****
* Variables that would make sense <br/> * Variables that would make sense <br/>
* <ul> * <ul>
* <li>inheritDestinationGroupLoanOfficer: Default False</li> * <li>inheritDestinationGroupLoanOfficer: Default true</li>
* <li>newStaffId: Optional field with Id of new Loan Officer to be linked * <li>newStaffId: Optional field with Id of new Loan Officer to be linked
* to this client and all his JLG loans for this group</li> * to this client and all his JLG loans for this group</li>
* <li>transferActiveLoans:Default False, unless overridden, this client
* cannot be transferred between groups within the same branch if he has
* active JLG loans and across branches if he has any active loan</li>
* <li></li>
* <li></li>
* <li></li>
* <li></li>
* <li></li>
* <li></li>
* <li></li>
* </ul>
* ***/ * ***/
@Transactional @Transactional
public void transferClientBetweenGroups(final Group sourceGroup, final Client client, final Group destinationGroup) { public void transferClientBetweenGroups(final Group sourceGroup, final Client client, final Group destinationGroup,
final Boolean inheritDestinationGroupLoanOfficer, final Staff newLoanOfficer) {
// next I shall validate that the client is present in this group // next I shall validate that the client is present in this group
if (!sourceGroup.hasClientAsMember(client)) { throw new ClientNotInGroupException(client.getId(), sourceGroup.getId()); } if (!sourceGroup.hasClientAsMember(client)) { throw new ClientNotInGroupException(client.getId(), sourceGroup.getId()); }
// Is client active? // Is client active?
if (client.isNotActive()) { throw new ClientHasBeenClosedException(client.getId()); } if (client.isNotActive()) { throw new ClientHasBeenClosedException(client.getId()); }
/*** Code for intra-branch transfers ***/ /**
if (client.getOffice().getId() == destinationGroup.getOffice().getId()) { * TODO: for now we need to ensure that only one collection sheet
/** * calendar can be linked with a center or group entity <br/>
* TODO: for now we need to ensure that only one collection sheet **/
* calendar can be linked with a center or group entity <br/> final CalendarInstance sourceGroupCalendarInstance = this.calendarInstanceRepository
**/ .findByEntityIdAndEntityTypeIdAndCalendarTypeId(sourceGroup.getId(), CalendarEntityType.GROUPS.getValue(),
final CalendarInstance sourceGroupCalendarInstance = this.calendarInstanceRepository CalendarType.COLLECTION.getValue());
.findByEntityIdAndEntityTypeIdAndCalendarTypeId(sourceGroup.getId(), CalendarEntityType.GROUPS.getValue(), // get all customer loans synced with this group calendar Instance
final List<CalendarInstance> activeLoanCalendarInstances = this.calendarInstanceRepository
.findCalendarInstancesForActiveLoansByGroupIdAndClientId(sourceGroup.getId(), client.getId());
/**
* if a calendar is present in the source group along with loans synced
* with it, we should ensure that the destination group also has a
* collection calendar
**/
if (sourceGroupCalendarInstance != null && !activeLoanCalendarInstances.isEmpty()) {
// get the destination calendar
final CalendarInstance destinationGroupCalendarInstance = this.calendarInstanceRepository
.findByEntityIdAndEntityTypeIdAndCalendarTypeId(destinationGroup.getId(), CalendarEntityType.GROUPS.getValue(),
CalendarType.COLLECTION.getValue()); CalendarType.COLLECTION.getValue());
// get all customer loans synced with this group calendar Instance
final List<CalendarInstance> activeLoanCalendarInstances = this.calendarInstanceRepository
.findCalendarInstancesForActiveLoansByGroupIdAndClientId(sourceGroup.getId(), client.getId());
/** if (destinationGroupCalendarInstance == null) { throw new TransferNotSupportedException(
* if a calendar is present in the source group along with loans TRANSFER_NOT_SUPPORTED_REASON.DESTINATION_GROUP_HAS_NO_MEETING, destinationGroup.getId());
* synced with it, we should ensure that the destination group also
* has a collection calendar
**/
if (sourceGroupCalendarInstance != null && !activeLoanCalendarInstances.isEmpty()) {
// get the destination calendar
final CalendarInstance destinationGroupCalendarInstance = this.calendarInstanceRepository
.findByEntityIdAndEntityTypeIdAndCalendarTypeId(destinationGroup.getId(), CalendarEntityType.GROUPS.getValue(),
CalendarType.COLLECTION.getValue());
if (destinationGroupCalendarInstance == null) { throw new TransferNotSupportedException(client.getId(),
sourceGroup.getId(), destinationGroup.getId(), false);
}
Calendar sourceGroupCalendar = destinationGroupCalendarInstance.getCalendar();
Calendar destinationGroupCalendar = destinationGroupCalendarInstance.getCalendar();
/***
* Ensure that the recurrence pattern are same for collection
* meeting in both the source and the destination calendar
***/
if (!(CalendarUtils.isFrequencySame(sourceGroupCalendar.getRecurrence(), destinationGroupCalendar.getRecurrence()) && CalendarUtils
.isIntervalSame(sourceGroupCalendar.getRecurrence(), destinationGroupCalendar.getRecurrence()))) { throw new TransferNotSupportedException(
client.getId(), sourceGroup.getId(), destinationGroup.getId()); }
/** map all JLG loans for this client to the destinationGroup **/
for (CalendarInstance calendarInstance : activeLoanCalendarInstances) {
calendarInstance.updateCalendar(destinationGroupCalendar);
}
// reschedule all JLG Loans to follow new Calendar
this.loanWritePlatformService.applyMeetingDateChanges(destinationGroupCalendar, activeLoanCalendarInstances);
} }
Calendar sourceGroupCalendar = sourceGroupCalendarInstance.getCalendar();
Calendar destinationGroupCalendar = destinationGroupCalendarInstance.getCalendar();
} else { /***
Office destinationOffice = destinationGroup.getOffice(); * Ensure that the recurrence pattern are same for collection
// handleClientTransfer(client, destinationOffice); * meeting in both the source and the destination calendar
// TODO: Fill in the blanks ***/
if (!(CalendarUtils.isFrequencySame(sourceGroupCalendar.getRecurrence(), destinationGroupCalendar.getRecurrence()) && CalendarUtils
.isIntervalSame(sourceGroupCalendar.getRecurrence(), destinationGroupCalendar.getRecurrence()))) { throw new TransferNotSupportedException(
TRANSFER_NOT_SUPPORTED_REASON.DESTINATION_GROUP_MEETING_FREQUENCY_MISMATCH, sourceGroup.getId(),
destinationGroup.getId()); }
/** map all JLG loans for this client to the destinationGroup **/
for (CalendarInstance calendarInstance : activeLoanCalendarInstances) {
calendarInstance.updateCalendar(destinationGroupCalendar);
this.calendarInstanceRepository.save(calendarInstance);
}
// reschedule all JLG Loans to follow new Calendar
this.loanWritePlatformService.applyMeetingDateChanges(destinationGroupCalendar, activeLoanCalendarInstances);
} }
/** /**
@@ -184,8 +199,11 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
for (Loan loan : allClientJLGLoans) { for (Loan loan : allClientJLGLoans) {
if (loan.status().isActiveOrAwaitingApprovalOrDisbursal()) { if (loan.status().isActiveOrAwaitingApprovalOrDisbursal()) {
loan.updateGroup(destinationGroup); loan.updateGroup(destinationGroup);
if (destinationGroupLoanOfficer != null) { if (inheritDestinationGroupLoanOfficer != null && inheritDestinationGroupLoanOfficer == true
&& destinationGroupLoanOfficer != null) {
loan.reassignLoanOfficer(destinationGroupLoanOfficer, DateUtils.getLocalDateOfTenant()); loan.reassignLoanOfficer(destinationGroupLoanOfficer, DateUtils.getLocalDateOfTenant());
} else if (newLoanOfficer != null) {
loan.reassignLoanOfficer(newLoanOfficer, DateUtils.getLocalDateOfTenant());
} }
this.loanRepository.saveAndFlush(loan); this.loanRepository.saveAndFlush(loan);
} }
@@ -212,14 +230,14 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
@Override @Override
public CommandProcessingResult proposeClientTransfer(final Long clientId, final JsonCommand jsonCommand) { public CommandProcessingResult proposeClientTransfer(final Long clientId, final JsonCommand jsonCommand) {
// validation // validation
this.transfersDataValidator.validateForProposeClientTransferBetweenBranches(jsonCommand.json()); this.transfersDataValidator.validateForProposeClientTransfer(jsonCommand.json());
final Long destinationOfficeId = jsonCommand.longValueOfParameterNamed(TransferApiConstants.destinationOfficeIdParamName); final Long destinationOfficeId = jsonCommand.longValueOfParameterNamed(TransferApiConstants.destinationOfficeIdParamName);
final Office office = this.officeRepository.findOneWithNotFoundDetection(destinationOfficeId); final Office office = this.officeRepository.findOneWithNotFoundDetection(destinationOfficeId);
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId); final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
/*** Remove all group associations for this client ***/ /*** Remove all group associations for this client ***/
client.getGroups().clear(); client.getGroups().clear();
handleClientTransfer(client, office, TransferEventType.PROPOSAL); handleClientTransferLifecycleEvent(client, office, TransferEventType.PROPOSAL, jsonCommand);
this.clientRepository.save(client); this.clientRepository.save(client);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
@@ -243,10 +261,14 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
@Transactional @Transactional
@Override @Override
public CommandProcessingResult acceptClientTransfer(final Long clientId, final JsonCommand jsonCommand) { public CommandProcessingResult acceptClientTransfer(final Long clientId, final JsonCommand jsonCommand) {
// validation
this.transfersDataValidator.validateForAcceptClientTransfer(jsonCommand.json());
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId); final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
/*** Remove all group associations for this client ***/ validateClientAwaitingTransferAcceptance(client);
/*** Remove all (old) group associations for this client ***/
client.getGroups().clear(); client.getGroups().clear();
handleClientTransfer(client, client.getOffice(), TransferEventType.ACCEPTANCE); handleClientTransferLifecycleEvent(client, client.getTransferToOffice(), TransferEventType.ACCEPTANCE, jsonCommand);
this.clientRepository.save(client); this.clientRepository.save(client);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
@@ -258,10 +280,12 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
@Override @Override
@Transactional @Transactional
public CommandProcessingResult withdrawClientTransfer(Long clientId, JsonCommand jsonCommand) { public CommandProcessingResult withdrawClientTransfer(Long clientId, JsonCommand jsonCommand) {
// validation
this.transfersDataValidator.validateForWithdrawClientTransfer(jsonCommand.json());
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId); final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
/*** Remove all group associations for this client ***/ validateClientAwaitingTransferAcceptanceOnHold(client);
client.getGroups().clear();
handleClientTransfer(client, client.getOffice(), TransferEventType.WITHDRAWAL); handleClientTransferLifecycleEvent(client, client.getOffice(), TransferEventType.WITHDRAWAL, jsonCommand);
this.clientRepository.save(client); this.clientRepository.save(client);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
@@ -273,10 +297,10 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
@Override @Override
@Transactional @Transactional
public CommandProcessingResult rejectClientTransfer(Long clientId, JsonCommand jsonCommand) { public CommandProcessingResult rejectClientTransfer(Long clientId, JsonCommand jsonCommand) {
// validation
this.transfersDataValidator.validateForRejectClientTransfer(jsonCommand.json());
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId); final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
/*** Remove all group associations for this client ***/ handleClientTransferLifecycleEvent(client, client.getOffice(), TransferEventType.REJECTION, jsonCommand);
client.getGroups().clear();
handleClientTransfer(client, client.getOffice(), TransferEventType.REJECTION);
this.clientRepository.save(client); this.clientRepository.save(client);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
@@ -285,20 +309,36 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
.build(); .build();
} }
private void handleClientTransfer(final Client client, final Office destinationOffice, TransferEventType transferEventType) { private void handleClientTransferLifecycleEvent(final Client client, final Office destinationOffice,
if (loanRepository.doesClientHaveActiveLoans(client.getId())) { TransferEventType transferEventType, JsonCommand jsonCommand) {
Date todaysDate = DateUtils.getDateOfTenant();
/** Get destination loan officer if exists **/
Staff staff = null;
Group destinationGroup = null;
final Long staffId = jsonCommand.longValueOfParameterNamed(TransferApiConstants.newStaffIdParamName);
final Long destinationGroupId = jsonCommand.longValueOfParameterNamed(TransferApiConstants.destinationGroupIdParamName);
if (staffId != null) {
staff = this.staffRepositoryWrapper.findByOfficeHierarchyWithNotFoundDetection(staffId, destinationOffice.getHierarchy());
}
if (destinationGroupId != null) {
destinationGroup = this.groupRepository.findOneWithNotFoundDetection(destinationGroupId);
}
/*** Handle Active Loans ***/
if (loanRepository.doNonClosedLoanAccountsExistForClient(client.getId())) {
// get each individual loan for the client // get each individual loan for the client
for (Loan loan : loanRepository.findLoanByClientId(client.getId())) { for (Loan loan : loanRepository.findLoanByClientId(client.getId())) {
if (!loan.isClosed()) { if (!loan.isClosed()) {
switch (transferEventType) { switch (transferEventType) {
case ACCEPTANCE: case ACCEPTANCE:
this.loanWritePlatformService.acceptLoanTransfer(loan.getId(), DateUtils.getLocalDateOfTenant()); this.loanWritePlatformService.acceptLoanTransfer(loan.getId(), DateUtils.getLocalDateOfTenant(),
destinationOffice, staff);
break; break;
case PROPOSAL: case PROPOSAL:
this.loanWritePlatformService.initiateLoanTransfer(loan.getId(), DateUtils.getLocalDateOfTenant()); this.loanWritePlatformService.initiateLoanTransfer(loan.getId(), DateUtils.getLocalDateOfTenant());
break; break;
case REJECTION: case REJECTION:
this.loanWritePlatformService.rejectLoanTransfer(loan.getId(), DateUtils.getLocalDateOfTenant()); // do nothing
break; break;
case WITHDRAWAL: case WITHDRAWAL:
this.loanWritePlatformService.withdrawLoanTransfer(loan.getId(), DateUtils.getLocalDateOfTenant()); this.loanWritePlatformService.withdrawLoanTransfer(loan.getId(), DateUtils.getLocalDateOfTenant());
@@ -307,21 +347,34 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
} }
} }
/*** Handle Active Savings (Currently throw and exception) ***/
if (savingsAccountRepository.doNonClosedSavingAccountsExistForClient(client.getId())) { throw new TransferNotSupportedException(
TRANSFER_NOT_SUPPORTED_REASON.ACTIVE_SAVINGS_ACCOUNT, client.getId()); }
switch (transferEventType) { switch (transferEventType) {
case ACCEPTANCE: case ACCEPTANCE:
client.setStatus(ClientStatus.ACTIVE.getValue()); client.setStatus(ClientStatus.ACTIVE.getValue());
client.updateTransferToOffice(null);
client.updateOffice(destinationOffice);
client.updateOfficeJoiningDate(todaysDate);
if (client.getGroups().size() == 1) {
transferClientBetweenGroups(Iterables.get(client.getGroups(), 0), client, destinationGroup, true, staff);
}
break; break;
case PROPOSAL: case PROPOSAL:
client.setStatus(ClientStatus.TRANSFER_IN_PROGRESS.getValue()); client.setStatus(ClientStatus.TRANSFER_IN_PROGRESS.getValue());
client.updateOffice(destinationOffice); client.updateTransferToOffice(destinationOffice);
break; break;
case REJECTION: case REJECTION:
client.setStatus(ClientStatus.TRANSFER_ON_HOLD.getValue()); client.setStatus(ClientStatus.TRANSFER_ON_HOLD.getValue());
client.updateTransferToOffice(null);
break; break;
// TODO update client with previous office
case WITHDRAWAL: case WITHDRAWAL:
client.setStatus(ClientStatus.ACTIVE.getValue()); client.setStatus(ClientStatus.ACTIVE.getValue());
client.updateTransferToOffice(null);
} }
noteWritePlatformService.createAndPersistClientNote(client, jsonCommand);
} }
private List<Client> assembleListOfClients(final JsonCommand command) { private List<Client> assembleListOfClients(final JsonCommand command) {
@@ -345,4 +398,20 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
return clients; return clients;
} }
private void validateClientAwaitingTransferAcceptance(final Client client) {
if (!client.isTransferInProgress()) { throw new ClientNotAwaitingTransferApprovalException(client.getId()); }
}
private void validateGroupAwaitingTransferAcceptance(final Group group) {
if (!group.isTransferInProgress()) { throw new ClientNotAwaitingTransferApprovalException(group.getId()); }
}
private void validateClientAwaitingTransferAcceptanceOnHold(final Client client) {
if (!client.isTransferInProgressOrOnHold()) { throw new ClientNotAwaitingTransferApprovalOrOnHoldException(client.getId()); }
}
private void validateGroupAwaitingTransferAcceptanceOnHold(final Group group) {
if (!group.isTransferInProgressOrOnHold()) { throw new ClientNotAwaitingTransferApprovalException(group.getId()); }
}
} }
@@ -17,6 +17,7 @@
<!-- <property name="hibernate.hbm2ddl.auto" value="update"/> --> <!-- <property name="hibernate.hbm2ddl.auto" value="update"/> -->
<property name="hibernate.jdbc.batch_size" value="100" /> <property name="hibernate.jdbc.batch_size" value="100" />
<property name="hibernate.order_inserts" value="true" /> <property name="hibernate.order_inserts" value="true" />
<!-- <property name = "hibernate.show_sql" value = "true" /> -->
</properties> </properties>
</persistence-unit> </persistence-unit>
</persistence> </persistence>