Merge pull request #788 from pramodn02/MIFOSX-954

MIFOSX-954 - added update of default savings
This commit is contained in:
Vishwas Babu A J
2014-03-06 01:00:55 -08:00
18 changed files with 395 additions and 50 deletions
+68 -16
View File
@@ -240,6 +240,14 @@
<td></td>
<td></td>
</tr>
<tr class="alt">
<td></td>
<td>clients/{clientId}?command=updateSavingsAccount</td>
<td><a href="#clients_updateSavingsAccount">Update Default Savings Account</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td class="alt"></td>
<td>clients/{clientId}?command=proposeAndAcceptTransfer</td>
@@ -2268,6 +2276,35 @@ Request Body:
</div>
</div>
<a id="clients_updateSavingsAccount" name="clients_updateSavingsAccount" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Update Default Savings Account</h4>
<p>Allows you to modify or assign default overdraft savings account for existed Client.</p>
<p>The selected savings account should be belongs to the client's.</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/clients/{clientId}?command=updateSavingsAccount</code>
<code class="method-request">POST clients/1?command=updateSavingsAccount
Content-Type: application/json
Request Body:
{
"savingsAccountId": "22"
}
</code>
<code class="method-response">
{
"officeId":1,
"clientId":1,
"resourceId":1
,"changes":{
"savingsAccountId":22
}
}
</code>
</div>
</div>
<a id="clients_propose_transfer" name="clients_propose_transfer" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
@@ -2431,38 +2468,45 @@ GET https://DomainName/api/v1/clients/{clientId}
</code>
<code class="method-response">
{
"id": 2,
"accountNo": "000000002",
"id": 27,
"accountNo": "000000027",
"status": {
"id": 300,
"code": "clientStatusType.active",
"value": "Active"
},
"active": true,
"activationDate": [
2009,
3,
4
2013,
1,
1
],
"fullname": "Client of group",
"displayName": "Client of group",
"firstname": "savings",
"lastname": "test",
"displayName": "savings test",
"officeId": 1,
"officeName": "Head Office",
"timeline": {
"submittedOnDate": [
2013,
1,
1
],
"submittedByUsername": "mifos",
"submittedByFirstname": "App",
"submittedByLastname": "Administrator",
"activatedOnDate": [
2009,
3,
4
2013,
1,
1
],
"activatedByUsername": "mifos",
"activatedByFirstname": "App",
"activatedByLastname": "Administrator"
},
"groups": [
{
"id": 1,
"name": "Example Group"
}
]
"savingsProductId": 4,
"savingsProductName": "account overdraft",
"groups": []
}
</code>
</div>
@@ -21832,6 +21876,14 @@ No Request Body:
<td></td>
<td></td>
</tr>
<tr class="alt">
<td></td>
<td>clients/{clientId}?command=updateSavingsAccount</td>
<td><a href="#clients_updateSavingsAccount">Update Default Savings Account</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="#client_identifiers">Client Identifiers</a></td>
<td>clients/{clientId}/identifiers</td>
@@ -0,0 +1,5 @@
ALTER TABLE `m_client`
ADD COLUMN `default_savings_account` BIGINT(20) NULL DEFAULT NULL AFTER `default_savings_product`,
ADD CONSTRAINT `FK_m_client_m_savings_account` FOREIGN KEY (`default_savings_account`) REFERENCES `m_savings_account` (`id`);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'UPDATESAVINGSACCOUNT_CLIENT', 'CLIENT', 'UPDATESAVINGSACCOUNT', 0);
@@ -660,6 +660,10 @@ public class CommandWrapper {
public boolean isRejectClientTransfer() {
return this.actionName.equalsIgnoreCase("REJECTTRANSFER") && this.entityName.equalsIgnoreCase("CLIENT");
}
public boolean isUpdateClientSavingsAccount() {
return this.actionName.equalsIgnoreCase("UPDATESAVINGSACCOUNT") && this.entityName.equalsIgnoreCase("CLIENT");
}
public boolean isProductMixResource() {
return this.entityName.equalsIgnoreCase("PRODUCTMIX");
@@ -1425,6 +1425,16 @@ public class CommandWrapperBuilder {
this.href = "/clients/" + clientId + "?command=assignStaff";
return this;
}
public CommandWrapperBuilder updateClientSavingsAccount(final Long clientId) {
this.actionName = "UPDATESAVINGSACCOUNT";
this.entityName = "CLIENT";
this.entityId = clientId;
this.clientId = clientId;
this.href = "/clients/" + clientId + "?command=updateSavingsAccount";
return this;
}
public CommandWrapperBuilder createProductMix(final Long productId) {
this.actionName = "CREATE";
@@ -177,6 +177,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
handler = this.applicationContext.getBean("acceptClientTransferCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isRejectClientTransfer()) {
handler = this.applicationContext.getBean("rejectClientTransferCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdateClientSavingsAccount()) {
handler = this.applicationContext.getBean("updateClientSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
@@ -39,6 +39,7 @@ public class ClientApiConstants {
public static final String closureReasonIdParamName = "closureReasonId";
public static final String submittedOnDateParamName = "submittedOnDate";
public static final String savingsProductIdParamName = "savingsProductId";
public static final String savingsAccountIdParamName = "savingsAccountId";
// response parameters
public static final String statusParamName = "status";
public static final String hierarchyParamName = "hierarchy";
@@ -6,6 +6,7 @@
package org.mifosplatform.portfolio.client.api;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@@ -39,6 +40,8 @@ import org.mifosplatform.portfolio.accountdetails.service.AccountDetailsReadPlat
import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
import org.mifosplatform.portfolio.group.service.SearchParameters;
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
import org.mifosplatform.portfolio.savings.service.SavingsAccountReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@@ -55,6 +58,7 @@ public class ClientsApiResource {
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
private final SavingsAccountReadPlatformService savingsAccountReadPlatformService;
@Autowired
public ClientsApiResource(final PlatformSecurityContext context, final ClientReadPlatformService readPlatformService,
@@ -62,7 +66,8 @@ public class ClientsApiResource {
final ToApiJsonSerializer<AccountSummaryCollectionData> clientAccountSummaryToApiJsonSerializer,
final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final AccountDetailsReadPlatformService accountDetailsReadPlatformService) {
final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
final SavingsAccountReadPlatformService savingsAccountReadPlatformService) {
this.context = context;
this.clientReadPlatformService = readPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
@@ -70,6 +75,7 @@ public class ClientsApiResource {
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
this.savingsAccountReadPlatformService = savingsAccountReadPlatformService;
}
@GET
@@ -133,6 +139,11 @@ public class ClientsApiResource {
final ClientData templateData = this.clientReadPlatformService.retrieveTemplate(clientData.officeId(),
staffInSelectedOfficeOnly);
clientData = ClientData.templateOnTop(clientData, templateData);
Collection<SavingsAccountData> savingAccountOptions = this.savingsAccountReadPlatformService.retrieveForLookup(
clientId, true);
if (savingAccountOptions != null && savingAccountOptions.size() > 0) {
clientData = ClientData.templateWithSavingAccountOptions(clientData, savingAccountOptions);
}
}
return this.toApiJsonSerializer.serialize(settings, clientData, ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS);
@@ -224,10 +235,14 @@ public class ClientsApiResource {
} else if (is(commandParam, "rejectTransfer")) {
commandRequest = builder.rejectClientTransfer(clientId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "updateSavingsAccount")) {
commandRequest = builder.updateClientSavingsAccount(clientId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
if (result == null) { throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate",
"unassignStaff", "assignStaff", "close", "proposeTransfer", "withdrawTransfer", "acceptTransfer", "rejectTransfer" }); }
"unassignStaff", "assignStaff", "close", "proposeTransfer", "withdrawTransfer", "acceptTransfer", "rejectTransfer",
"updateSavingsAccount" }); }
return this.toApiJsonSerializer.serialize(result);
}
@@ -17,6 +17,7 @@ import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.organisation.office.data.OfficeData;
import org.mifosplatform.organisation.staff.data.StaffData;
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
/**
@@ -54,6 +55,8 @@ final public class ClientData implements Comparable<ClientData> {
private final Long savingsProductId;
private final String savingsProductName;
private final Long savingsAccountId;
// associations
private final Collection<GroupGeneralData> groups;
@@ -63,12 +66,13 @@ final public class ClientData implements Comparable<ClientData> {
@SuppressWarnings("unused")
private final Collection<CodeValueData> closureReasons;
private final Collection<SavingsProductData> savingProductOptions;
private final Collection<SavingsAccountData> savingAccountOptions;
public static ClientData template(final Long officeId, final LocalDate joinedDate, final Collection<OfficeData> officeOptions,
final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons,
final Collection<SavingsProductData> savingProductOptions) {
return new ClientData(null, null, officeId, null, null, null, null, null, null, null, null, null, null, null, joinedDate, null,
null, null, officeOptions, null, staffOptions, closureReasons, null, savingProductOptions, null, null);
null, null, officeOptions, null, staffOptions, closureReasons, null, savingProductOptions, null, null, null, null);
}
@@ -79,7 +83,19 @@ final public class ClientData implements Comparable<ClientData> {
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.mobileNo,
clientData.activationDate, clientData.imageId, clientData.staffId, clientData.staffName, templateData.officeOptions,
clientData.groups, templateData.staffOptions, null, null, templateData.savingProductOptions, clientData.savingsProductId,
clientData.savingsProductName);
clientData.savingsProductName, clientData.savingsAccountId, clientData.savingAccountOptions);
}
public static ClientData templateWithSavingAccountOptions(final ClientData clientData,
final Collection<SavingsAccountData> savingAccountOptions) {
return new ClientData(clientData.accountNo, clientData.status, clientData.officeId, clientData.officeName,
clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname, clientData.middlename,
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.mobileNo,
clientData.activationDate, clientData.imageId, clientData.staffId, clientData.staffName, clientData.officeOptions,
clientData.groups, clientData.staffOptions, null, null, clientData.savingProductOptions, clientData.savingsProductId,
clientData.savingsProductName, clientData.savingsAccountId, savingAccountOptions);
}
@@ -89,7 +105,7 @@ final public class ClientData implements Comparable<ClientData> {
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.mobileNo,
clientData.activationDate, clientData.imageId, clientData.staffId, clientData.staffName, clientData.officeOptions,
parentGroups, clientData.staffOptions, null, clientData.timeline, clientData.savingProductOptions,
clientData.savingsProductId, clientData.savingsProductName);
clientData.savingsProductId, clientData.savingsProductName, clientData.savingsAccountId, clientData.savingAccountOptions);
}
@@ -98,13 +114,13 @@ final public class ClientData implements Comparable<ClientData> {
final String officeName) {
return new ClientData(accountNo, status, officeId, officeName, null, null, id, firstname, middlename, lastname, fullname,
displayName, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
displayName, null, null, null, null, null, null, null, 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) {
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, null);
null, null, null, null, null, null, null, null, null, null, null, null, null);
}
@@ -112,10 +128,10 @@ final public class ClientData implements Comparable<ClientData> {
final Long transferToOfficeId, final String transferToOfficeName, final Long id, final String firstname,
final String middlename, final String lastname, final String fullname, final String displayName, final String externalId,
final String mobileNo, final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName,
final ClientTimelineData timeline, final Long savingsProductId, final String savingsProductName) {
final ClientTimelineData timeline, final Long savingsProductId, final String savingsProductName, final Long savingsAccountId) {
return new ClientData(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname, middlename,
lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName, null, null, null, null,
timeline, null, savingsProductId, savingsProductName);
timeline, null, savingsProductId, savingsProductName, savingsAccountId, null);
}
@@ -125,7 +141,8 @@ final public class ClientData implements Comparable<ClientData> {
final String mobileNo, final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName,
final Collection<OfficeData> allowedOffices, final Collection<GroupGeneralData> groups,
final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons, final ClientTimelineData timeline,
final Collection<SavingsProductData> savingProductOptions, final Long savingsProductId, final String savingsProductName) {
final Collection<SavingsProductData> savingProductOptions, final Long savingsProductId, final String savingsProductName,
final Long savingsAccountId, final Collection<SavingsAccountData> savingAccountOptions) {
this.accountNo = accountNo;
this.status = status;
if (status != null) {
@@ -167,6 +184,8 @@ final public class ClientData implements Comparable<ClientData> {
this.savingProductOptions = savingProductOptions;
this.savingsProductId = savingsProductId;
this.savingsProductName = savingsProductName;
this.savingsAccountId = savingsAccountId;
this.savingAccountOptions = savingAccountOptions;
}
public Long id() {
@@ -425,5 +425,30 @@ public final class ClientDataValidator {
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForSavingsAccount(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
final Set<String> supportedParameters = new HashSet<String>(Arrays.asList(ClientApiConstants.savingsAccountIdParamName));
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(ClientApiConstants.CLIENT_RESOURCE_NAME);
final String savingsIdParameterName = ClientApiConstants.savingsAccountIdParamName;
final Long savingsId = this.fromApiJsonHelper.extractLongNamed(savingsIdParameterName, element);
baseDataValidator.reset().parameter(savingsIdParameterName).value(savingsId).notNull().longGreaterThanZero();
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
}
@@ -45,6 +45,7 @@ import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.portfolio.client.api.ClientApiConstants;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
import org.mifosplatform.portfolio.savings.domain.SavingsProduct;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -143,6 +144,10 @@ public final class Client extends AbstractPersistable<Long> {
@ManyToOne
@JoinColumn(name = "default_savings_product", nullable = true)
private SavingsProduct savingsProduct;
@ManyToOne
@JoinColumn(name = "default_savings_account", nullable = true)
private SavingsAccount savingsAccount;
public static Client createNew(final AppUser currentUser, final Office clientOffice, final Group clientParentGroup, final Staff staff,
final SavingsProduct savingsProduct, final JsonCommand command) {
@@ -179,7 +184,7 @@ public final class Client extends AbstractPersistable<Long> {
}
return new Client(currentUser, status, clientOffice, clientParentGroup, accountNo, firstname, middlename, lastname, fullname,
activationDate, officeJoiningDate, externalId, mobileNo, staff, submittedOnDate, savingsProduct);
activationDate, officeJoiningDate, externalId, mobileNo, staff, submittedOnDate, savingsProduct, null);
}
protected Client() {
@@ -189,7 +194,7 @@ public final class Client extends AbstractPersistable<Long> {
private Client(final AppUser currentUser, 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 LocalDate officeJoiningDate, final String externalId, final String mobileNo,
final Staff staff, final LocalDate submittedOnDate, final SavingsProduct savingsProduct) {
final Staff staff, final LocalDate submittedOnDate, final SavingsProduct savingsProduct,final SavingsAccount savingsAccount) {
if (StringUtils.isBlank(accountNo)) {
this.accountNumber = new RandomPasswordGenerator(19).generate();
@@ -253,6 +258,7 @@ public final class Client extends AbstractPersistable<Long> {
this.staff = staff;
this.savingsProduct = savingsProduct;
this.savingsAccount = savingsAccount;
deriveDisplayName();
validate();
@@ -659,4 +665,12 @@ public final class Client extends AbstractPersistable<Long> {
public AppUser activatedBy() {
return this.activatedBy;
}
public SavingsAccount savingsAccount() {
return this.savingsAccount;
}
public void updateSavingsAccount(SavingsAccount savingsAccount) {
this.savingsAccount = savingsAccount;
}
}
@@ -0,0 +1,27 @@
package org.mifosplatform.portfolio.client.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.client.service.ClientWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UpdateClientSavingsAccountCommandHandler implements NewCommandSourceHandler {
private final ClientWritePlatformService clientWritePlatformService;
@Autowired
public UpdateClientSavingsAccountCommandHandler(final ClientWritePlatformService clientWritePlatformService){
this.clientWritePlatformService = clientWritePlatformService;
}
@Override
@Transactional
public CommandProcessingResult processCommand(JsonCommand command) {
return this.clientWritePlatformService.updateDefaultSavingsAccount(command.entityId(), command);
}
}
@@ -273,6 +273,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
sqlBuilder.append("c.activation_date as activationDate, c.image_id as imageId, ");
sqlBuilder.append("c.staff_id as staffId, s.display_name as staffName,");
sqlBuilder.append("c.default_savings_product as savingsProductId, sp.name as savingsProductName, ");
sqlBuilder.append("c.default_savings_account as savingsAccountId");
sqlBuilder.append("c.submittedon_date as submittedOnDate, ");
sqlBuilder.append("sbu.username as submittedByUsername, ");
@@ -336,6 +337,9 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final Long savingsProductId = JdbcSupport.getLong(rs, "savingsProductId");
final String savingsProductName = rs.getString("savingsProductName");
final Long savingsAccountId = JdbcSupport.getLong(rs, "savingsAccountId");
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
final String closedByUsername = rs.getString("closedByUsername");
@@ -357,7 +361,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
return ClientData.instance(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname,
middlename, lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName,
timeline, savingsProductId, savingsProductName);
timeline, savingsProductId, savingsProductName,savingsAccountId);
}
}
@@ -408,7 +412,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
builder.append("c.activation_date as activationDate, c.image_id as imageId, ");
builder.append("c.staff_id as staffId, s.display_name as staffName, ");
builder.append("c.default_savings_product as savingsProductId, sp.name as savingsProductName ");
builder.append("c.default_savings_product as savingsProductId, sp.name as savingsProductName, ");
builder.append("c.default_savings_account as savingsAccountId ");
builder.append("from m_client c ");
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 ");
@@ -454,6 +459,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final Long savingsProductId = JdbcSupport.getLong(rs, "savingsProductId");
final String savingsProductName = rs.getString("savingsProductName");
final Long savingsAccountId = JdbcSupport.getLong(rs, "savingsAccountId");
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
final String closedByUsername = rs.getString("closedByUsername");
@@ -475,7 +482,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
return ClientData.instance(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname,
middlename, lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName,
timeline, savingsProductId, savingsProductName);
timeline, savingsProductId, savingsProductName,savingsAccountId);
}
}
@@ -24,4 +24,6 @@ public interface ClientWritePlatformService {
CommandProcessingResult assignClientStaff(Long clientId, JsonCommand command);
CommandProcessingResult updateDefaultSavingsAccount(Long clientId, JsonCommand command);
}
@@ -52,6 +52,7 @@ import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepository;
import org.mifosplatform.portfolio.savings.domain.SavingsProduct;
import org.mifosplatform.portfolio.savings.domain.SavingsProductRepository;
import org.mifosplatform.portfolio.savings.exception.SavingsAccountNotFoundException;
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
import org.mifosplatform.portfolio.savings.service.SavingsApplicationProcessWritePlatformService;
import org.mifosplatform.useradministration.domain.AppUser;
@@ -88,7 +89,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final ClientDataValidator fromApiJsonDeserializer, final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory,
final GroupRepository groupRepository, final StaffRepositoryWrapper staffRepository,
final CodeValueRepositoryWrapper codeValueRepository, final LoanRepository loanRepository,
final SavingsAccountRepository savingsRepository,final SavingsProductRepository savingsProductRepository,
final SavingsAccountRepository savingsRepository, final SavingsProductRepository savingsProductRepository,
final SavingsApplicationProcessWritePlatformService savingsApplicationProcessWritePlatformService,
final CommandProcessingService commandProcessingService) {
this.context = context;
@@ -181,18 +182,18 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
if (staffId != null) {
staff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId, clientOffice.getHierarchy());
}
SavingsProduct savingsProduct = null;
final Long savingsProductId = command.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
if(savingsProductId != null){
if (savingsProductId != null) {
savingsProduct = this.savingsProductRepository.findOne(savingsProductId);
if (savingsProduct == null) { throw new SavingsProductNotFoundException(savingsProductId); }
}
final Client newClient = Client.createNew(currentUser,clientOffice, clientParentGroup, staff, savingsProduct, command);
final Client newClient = Client.createNew(currentUser, clientOffice, clientParentGroup, staff, savingsProduct, command);
boolean rollbackTransaction = false;
if(newClient.isActive()){
if (newClient.isActive()) {
final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateClient(null).build();
rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser);
}
@@ -205,10 +206,13 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
newClient.updateAccountNo(accountNoGenerator.generate());
this.clientRepository.save(newClient);
}
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
CommandProcessingResult result = openOverdraftSavingsAccount(newClient, fmt);
if (result.getSavingsId() != null) {
this.clientRepository.save(newClient);
}
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -237,7 +241,6 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final String clientHierarchy = clientForUpdate.getOffice().getHierarchy();
this.context.validateAccessRights(clientHierarchy);
final Map<String, Object> changes = clientForUpdate.update(command);
@@ -251,21 +254,19 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
}
clientForUpdate.updateStaff(newStaff);
}
if (changes.containsKey(ClientApiConstants.savingsProductIdParamName)) {
if(clientForUpdate.isActive()){
throw new ClientActiveForUpdateException(clientId, ClientApiConstants.savingsProductIdParamName);
}
if (clientForUpdate.isActive()) { throw new ClientActiveForUpdateException(clientId,
ClientApiConstants.savingsProductIdParamName); }
SavingsProduct savingsProduct = null;
final Long savingsProductId = command.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
if(savingsProductId != null){
if (savingsProductId != null) {
savingsProduct = this.savingsProductRepository.findOne(savingsProductId);
if (savingsProduct == null) { throw new SavingsProductNotFoundException(savingsProductId); }
}
clientForUpdate.updateSavingsProduct(savingsProduct);
}
if (!changes.isEmpty()) {
this.clientRepository.saveAndFlush(clientForUpdate);
}
@@ -316,13 +317,19 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
private CommandProcessingResult openOverdraftSavingsAccount(final Client client, final DateTimeFormatter fmt) {
CommandProcessingResult commandProcessingResult = CommandProcessingResult.empty();
if(client.isActive() && client.SavingsProduct() != null){
if(!client.SavingsProduct().isAllowOverdraft()){
if (client.isActive() && client.SavingsProduct() != null) {
if (!client.SavingsProduct().isAllowOverdraft()) {
String defaultUserMessage = "Client's saving account must be a overdraft account";
throw new InvalidClientSavingProductException("saving.product", "must.be.ovrdraft.account", defaultUserMessage, client.SavingsProduct().getId(),client.getId());
throw new InvalidClientSavingProductException("saving.product", "must.be.ovrdraft.account", defaultUserMessage, client
.SavingsProduct().getId(), client.getId());
}
SavingsAccountDataDTO savingsAccountDataDTO = new SavingsAccountDataDTO(client, null, client.SavingsProduct(), client.getActivationLocalDate(), client.activatedBy(), fmt);
SavingsAccountDataDTO savingsAccountDataDTO = new SavingsAccountDataDTO(client, null, client.SavingsProduct(),
client.getActivationLocalDate(), client.activatedBy(), fmt);
commandProcessingResult = this.savingsApplicationProcessWritePlatformService.createActiveApplication(savingsAccountDataDTO);
if (commandProcessingResult.getSavingsId() != null) {
SavingsAccount savingsAccount = this.savingsRepository.findOne(commandProcessingResult.getSavingsId());
client.updateSavingsAccount(savingsAccount);
}
}
return commandProcessingResult;
}
@@ -463,7 +470,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
}
}
client.close(currentUser,closureReason, closureDate.toDate());
client.close(currentUser, closureReason, closureDate.toDate());
this.clientRepository.saveAndFlush(client);
return new CommandProcessingResultBuilder() //
@@ -477,4 +484,46 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
}
}
@Override
public CommandProcessingResult updateDefaultSavingsAccount(final Long clientId, final JsonCommand command) {
this.context.authenticatedUser();
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(5);
this.fromApiJsonDeserializer.validateForSavingsAccount(command.json());
final Client clientForUpdate = this.clientRepository.findOneWithNotFoundDetection(clientId);
SavingsAccount savingsAccount = null;
final Long savingsId = command.longValueOfParameterNamed(ClientApiConstants.savingsAccountIdParamName);
if (savingsId != null) {
savingsAccount = this.savingsRepository.findOne(savingsId);
if (savingsAccount == null) { throw new SavingsAccountNotFoundException(savingsId); }
if(!savingsAccount.getClient().identifiedBy(clientId)){
String defaultUserMessage = "saving account must belongs to client";
throw new InvalidClientSavingProductException("saving.account", "must.belongs.to.client", defaultUserMessage, savingsId,
clientForUpdate.getId());
}
if (!savingsAccount.allowOverdraft()) {
String defaultUserMessage = "Client's saving account must be a overdraft account";
throw new InvalidClientSavingProductException("saving.account", "must.be.ovrdraft.account", defaultUserMessage, savingsId,
clientForUpdate.getId());
}
clientForUpdate.updateSavingsAccount(savingsAccount);
}
this.clientRepository.saveAndFlush(clientForUpdate);
actualChanges.put(ClientApiConstants.savingsAccountIdParamName, savingsId);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withOfficeId(clientForUpdate.officeId()) //
.withEntityId(clientForUpdate.getId()) //
.withClientId(clientId) //
.with(actualChanges) //
.build();
}
}
@@ -157,6 +157,59 @@ public class SavingsAccountData {
withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit);
}
public static SavingsAccountData lookupWithProductDetails(final Long accountId, final String accountNo, final Long productId,
final String productName, final SavingsAccountStatusEnumData status) {
final String externalId = null;
final Long groupId = null;
final Long clientId = null;
final String clientName = null;
final String groupName = null;
final Long fieldOfficerId = null;
final String fieldOfficerName = null;
final SavingsAccountApplicationTimelineData timeline = null;
final CurrencyData currency = null;
final BigDecimal nominalAnnualInterestRate = null;
final EnumOptionData interestPeriodType = null;
final EnumOptionData interestPostingPeriodType = null;
final EnumOptionData interestCalculationType = null;
final EnumOptionData interestCalculationDaysInYearType = null;
final BigDecimal minRequiredOpeningBalance = null;
final Integer lockinPeriodFrequency = null;
final EnumOptionData lockinPeriodFrequencyType = null;
// final BigDecimal withdrawalFeeAmount = null;
// final EnumOptionData withdrawalFeeType = null;
final boolean withdrawalFeeForTransfers = false;
// final BigDecimal annualFeeAmount = null;
// final MonthDay annualFeeOnMonthDay = null;
// final LocalDate annualFeeNextDueDate = null;
final boolean allowOverdraft = false;
final BigDecimal overdraftLimit = null;
final SavingsAccountSummaryData summary = null;
final Collection<SavingsAccountTransactionData> transactions = null;
final Collection<SavingsProductData> productOptions = null;
final Collection<StaffData> fieldOfficerOptions = null;
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
final Collection<SavingsAccountChargeData> charges = null;
final Collection<ChargeData> chargeOptions = null;
return new SavingsAccountData(accountId, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, transactions, productOptions,
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit);
}
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account, final SavingsAccountData template,
final Collection<SavingsAccountTransactionData> transactions, final Collection<SavingsAccountChargeData> charges) {
@@ -2001,4 +2001,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
public boolean allowOverdraft() {
return this.allowOverdraft;
}
}
@@ -30,4 +30,6 @@ public interface SavingsAccountReadPlatformService {
// retrieveAccountsWithAnnualFeeDue();
SavingsAccountTransactionData retrieveSavingsTransaction(Long savingsId, Long transactionId);
Collection<SavingsAccountData> retrieveForLookup(Long clientId,Boolean overdraft);
}
@@ -101,7 +101,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
public Collection<SavingsAccountData> retrieveAllForLookup(final Long clientId) {
final StringBuilder sqlBuilder = new StringBuilder("select " + this.savingAccountMapper.schema());
sqlBuilder.append(" where sa.client_id = ? and sa.status_enum = 300");
sqlBuilder.append(" where sa.client_id = ? and sa.status_enum = 300 ");
final Object[] queryParameters = new Object[] { clientId };
return this.jdbcTemplate.query(sqlBuilder.toString(), this.savingAccountMapper, queryParameters);
@@ -404,6 +404,42 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
}
}
private static final class SavingAccountMapperForLookup implements RowMapper<SavingsAccountData> {
private final String schemaSql;
public SavingAccountMapperForLookup() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("sa.id as id, sa.account_no as accountNo, ");
sqlBuilder.append("sp.id as productId, sp.name as productName, ");
sqlBuilder.append("sa.status_enum as statusEnum ");
sqlBuilder.append("from m_savings_account sa ");
sqlBuilder.append("join m_savings_product sp ON sa.product_id = sp.id ");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public SavingsAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String accountNo = rs.getString("accountNo");
final Long productId = rs.getLong("productId");
final String productName = rs.getString("productName");
final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum");
final SavingsAccountStatusEnumData status = SavingsEnumerations.status(statusEnum);
return SavingsAccountData.lookupWithProductDetails(id, accountNo, productId, productName, status);
}
}
@Override
public SavingsAccountData retrieveTemplate(final Long clientId, final Long groupId, final Long productId,
final boolean staffInSelectedOfficeOnly) {
@@ -861,6 +897,23 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
}
}
@Override
public Collection<SavingsAccountData> retrieveForLookup(Long clientId, Boolean overdraft) {
SavingAccountMapperForLookup accountMapperForLookup = new SavingAccountMapperForLookup();
final StringBuilder sqlBuilder = new StringBuilder("select " + accountMapperForLookup.schema());
sqlBuilder.append(" where sa.client_id = ? and sa.status_enum = 300");
Object[] queryParameters = null;
if (overdraft == null) {
queryParameters = new Object[] { clientId };
} else {
sqlBuilder.append(" and sa.allow_overdraft = ?");
queryParameters = new Object[] { clientId, overdraft };
}
return this.jdbcTemplate.query(sqlBuilder.toString(), accountMapperForLookup, queryParameters);
}
/*
* private static final class SavingsAccountAnnualFeeMapper implements
* RowMapper<SavingsAccountAnnualFeeData> {
@@ -879,6 +932,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
* public String schema() { return this.schemaSql; }
*
* @Override public SavingsAccountAnnualFeeData mapRow(final ResultSet rs,
*
* @SuppressWarnings("unused") final int rowNum) throws SQLException {
*
* final Long id = rs.getLong("id"); final String accountNo =