add basic capability to support transfer of money transactions between offices (micro-banks).
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
-- create fund table
|
||||
DROP TABLE IF EXISTS `mifosngprovider`.`portfolio_office_funds_transfers`;
|
||||
CREATE TABLE `portfolio_office_funds_transfers` (
|
||||
DROP TABLE IF EXISTS `mifosngprovider`.`portfolio_office_monetary_transfers`;
|
||||
CREATE TABLE `portfolio_office_monetary_transfers` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`from_office_id` bigint(20) DEFAULT NULL,
|
||||
`to_office_id` bigint(20) DEFAULT NULL,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.mifosng.platform.api;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
@@ -15,6 +17,7 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.commands.BranchMoneyTransferCommand;
|
||||
import org.mifosng.platform.api.commands.OfficeCommand;
|
||||
@@ -22,6 +25,7 @@ import org.mifosng.platform.api.data.EntityIdentifier;
|
||||
import org.mifosng.platform.api.data.OfficeData;
|
||||
import org.mifosng.platform.api.infrastructure.ApiDataConversionService;
|
||||
import org.mifosng.platform.api.infrastructure.ApiJSONFormattingService;
|
||||
import org.mifosng.platform.exceptions.UnrecognizedQueryParamException;
|
||||
import org.mifosng.platform.organisation.service.OfficeReadPlatformService;
|
||||
import org.mifosng.platform.organisation.service.OfficeWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -129,14 +133,38 @@ public class OfficeApiResource {
|
||||
|
||||
@POST
|
||||
@Path("{officeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON})
|
||||
@Produces({ MediaType.APPLICATION_JSON})
|
||||
public Response transferMoney(@PathParam("officeId") final Long loanId,
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public Response transferMoneyFrom(@PathParam("officeId") final Long officeId,
|
||||
@QueryParam("command") final String commandParam,
|
||||
final BranchMoneyTransferCommand command) {
|
||||
|
||||
Long officeId = this.writePlatformService.transferMoney(command);
|
||||
command.setFromOfficeId(officeId);
|
||||
|
||||
LocalDate transactionLocalDate = apiDataConversionService.convertFrom(command.getTransactionDate(), "transactionDate", command.getDateFormat());
|
||||
command.setTransactionLocalDate(transactionLocalDate);
|
||||
|
||||
Locale clientLocale = this.apiDataConversionService.localeFromString(command.getLocale());
|
||||
|
||||
return Response.ok().entity(new EntityIdentifier(officeId)).build();
|
||||
BigDecimal transactionAmountValue = apiDataConversionService.convertFrom(command.getTransactionAmount(), "transactionAmount", clientLocale);
|
||||
command.setTransactionAmountValue(transactionAmountValue);
|
||||
|
||||
Response response = null;
|
||||
|
||||
if (is(commandParam, "transfer")) {
|
||||
Long id = this.writePlatformService.transferMoney(command);
|
||||
response = Response.ok().entity(new EntityIdentifier(id)).build();
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
throw new UnrecognizedQueryParamException("command", commandParam);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private boolean is(final String commandParam, final String commandValue) {
|
||||
return StringUtils.isNotBlank(commandParam)
|
||||
&& commandParam.trim().equalsIgnoreCase(commandValue);
|
||||
}
|
||||
}
|
||||
+9
@@ -21,6 +21,7 @@ public class BranchMoneyTransferCommand {
|
||||
private LocalDate transactionLocalDate;
|
||||
|
||||
private String locale;
|
||||
private String currencyCode;
|
||||
private String transactionAmount;
|
||||
private BigDecimal transactionAmountValue;
|
||||
|
||||
@@ -99,4 +100,12 @@ public class BranchMoneyTransferCommand {
|
||||
public void setTransactionAmountValue(BigDecimal transactionAmountValue) {
|
||||
this.transactionAmountValue = transactionAmountValue;
|
||||
}
|
||||
|
||||
public String getCurrencyCode() {
|
||||
return currencyCode;
|
||||
}
|
||||
|
||||
public void setCurrencyCode(String currencyCode) {
|
||||
this.currencyCode = currencyCode;
|
||||
}
|
||||
}
|
||||
@@ -182,4 +182,12 @@ public class Office extends AbstractAuditableCustom<AppUser, Long> {
|
||||
public String getHierarchy() {
|
||||
return hierarchy;
|
||||
}
|
||||
|
||||
public boolean hasParentOf(final Office office) {
|
||||
boolean isParent = false;
|
||||
if (this.parent != null) {
|
||||
isParent = this.parent.equals(office);
|
||||
}
|
||||
return isParent;
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package org.mifosng.platform.organisation.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.currency.domain.MonetaryCurrency;
|
||||
import org.mifosng.platform.currency.domain.Money;
|
||||
import org.mifosng.platform.infrastructure.AbstractAuditableCustom;
|
||||
import org.mifosng.platform.user.domain.AppUser;
|
||||
|
||||
@Entity
|
||||
@Table(name = "portfolio_office_monetary_transfers")
|
||||
public class OfficeMonetaryTransfer extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "from_office_id")
|
||||
private Office from;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "to_office_id")
|
||||
private Office to;
|
||||
|
||||
@Column(name = "transaction_date", nullable = false)
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date transactionDate;
|
||||
|
||||
@Embedded
|
||||
private MonetaryCurrency currency;
|
||||
|
||||
@Column(name = "transaction_amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal transactionAmount;
|
||||
|
||||
protected OfficeMonetaryTransfer() {
|
||||
this.transactionDate = null;
|
||||
}
|
||||
|
||||
public static OfficeMonetaryTransfer create(Office fromOffice, Office toOffice, LocalDate transactionLocalDate, Money amount) {
|
||||
|
||||
Date transactionDate = null;
|
||||
if (transactionLocalDate != null) {
|
||||
transactionDate = transactionLocalDate.toDate();
|
||||
}
|
||||
|
||||
return new OfficeMonetaryTransfer(fromOffice, toOffice, transactionDate, amount);
|
||||
}
|
||||
|
||||
private OfficeMonetaryTransfer(final Office fromOffice,final Office toOffice, final Date transactionDate, final Money amount) {
|
||||
this.from = fromOffice;
|
||||
this.to = toOffice;
|
||||
this.transactionDate = transactionDate;
|
||||
this.currency = amount.getCurrency();
|
||||
this.transactionAmount = amount.getAmount();
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package org.mifosng.platform.organisation.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface OfficeMonetaryTransferRepository extends
|
||||
JpaRepository<OfficeMonetaryTransfer, Long>,
|
||||
JpaSpecificationExecutor<OfficeMonetaryTransfer> {
|
||||
// no added behaviour
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package org.mifosng.platform.organisation.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosng.platform.DataValidatorBuilder;
|
||||
import org.mifosng.platform.api.commands.BranchMoneyTransferCommand;
|
||||
import org.mifosng.platform.api.data.ApiParameterError;
|
||||
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
|
||||
|
||||
public class BranchMoneyTransferCommandValidator {
|
||||
|
||||
private final BranchMoneyTransferCommand command;
|
||||
|
||||
public BranchMoneyTransferCommandValidator(final BranchMoneyTransferCommand command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("office.money.transfer");
|
||||
|
||||
baseDataValidator.reset().parameter("fromOfficeId").value(command.getFromOfficeId()).notNull();
|
||||
baseDataValidator.reset().parameter("toOfficeId").value(command.getToOfficeId()).notNull();
|
||||
baseDataValidator.reset().parameter("transactionDate").value(command.getTransactionLocalDate()).notNull();
|
||||
baseDataValidator.reset().parameter("currencyCode").value(command.getCurrencyCode()).notBlank();
|
||||
baseDataValidator.reset().parameter("transactionAmount").value(command.getTransactionAmountValue()).notNull();
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
-16
@@ -4,12 +4,17 @@ import static org.mifosng.platform.Specifications.officesThatMatch;
|
||||
|
||||
import org.mifosng.platform.api.commands.BranchMoneyTransferCommand;
|
||||
import org.mifosng.platform.api.commands.OfficeCommand;
|
||||
import org.mifosng.platform.currency.domain.ApplicationCurrency;
|
||||
import org.mifosng.platform.currency.domain.ApplicationCurrencyRepository;
|
||||
import org.mifosng.platform.currency.domain.MonetaryCurrency;
|
||||
import org.mifosng.platform.currency.domain.Money;
|
||||
import org.mifosng.platform.exceptions.CurrencyNotFoundException;
|
||||
import org.mifosng.platform.exceptions.NoAuthorizationException;
|
||||
import org.mifosng.platform.exceptions.OfficeNotFoundException;
|
||||
import org.mifosng.platform.exceptions.PlatformDataIntegrityException;
|
||||
import org.mifosng.platform.organisation.domain.Office;
|
||||
import org.mifosng.platform.organisation.domain.OfficeMonetaryTransfer;
|
||||
import org.mifosng.platform.organisation.domain.OfficeMonetaryTransferRepository;
|
||||
import org.mifosng.platform.organisation.domain.OfficeRepository;
|
||||
import org.mifosng.platform.security.PlatformSecurityContext;
|
||||
import org.mifosng.platform.user.domain.AppUser;
|
||||
@@ -27,11 +32,18 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final OfficeRepository officeRepository;
|
||||
private final OfficeMonetaryTransferRepository officeMonetaryTransferRepository;
|
||||
private final ApplicationCurrencyRepository applicationCurrencyRepository;
|
||||
|
||||
@Autowired
|
||||
public OfficeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final OfficeRepository officeRepository) {
|
||||
public OfficeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final OfficeRepository officeRepository,
|
||||
final OfficeMonetaryTransferRepository officeMonetaryTransferRepository,
|
||||
final ApplicationCurrencyRepository applicationCurrencyRepository) {
|
||||
this.context = context;
|
||||
this.officeRepository = officeRepository;
|
||||
this.officeMonetaryTransferRepository = officeMonetaryTransferRepository;
|
||||
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -92,31 +104,42 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public Long transferMoney(BranchMoneyTransferCommand command) {
|
||||
public Long transferMoney(final BranchMoneyTransferCommand command) {
|
||||
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
Office fromOffice = this.officeRepository.findOne(command.getFromOfficeId());
|
||||
if (fromOffice == null) {
|
||||
throw new OfficeNotFoundException(command.getFromOfficeId());
|
||||
BranchMoneyTransferCommandValidator validator = new BranchMoneyTransferCommandValidator(command);
|
||||
validator.validate();
|
||||
|
||||
Office fromOffice = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, command.getFromOfficeId());
|
||||
Office toOffice = null;
|
||||
if (fromOffice.isHeadOffice()) {
|
||||
toOffice = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, command.getToOfficeId());
|
||||
} else {
|
||||
toOffice = this.officeRepository.findOne(command.getToOfficeId());
|
||||
if (toOffice == null) {
|
||||
throw new OfficeNotFoundException(command.getToOfficeId());
|
||||
}
|
||||
|
||||
if (!fromOffice.hasParentOf(toOffice)) {
|
||||
throw new NoAuthorizationException("User does not have sufficient priviledges to act on the provided office.");
|
||||
}
|
||||
}
|
||||
|
||||
final String currencyCode = command.getCurrencyCode();
|
||||
ApplicationCurrency appCurrency = this.applicationCurrencyRepository.findOneByCode(currencyCode);
|
||||
if (appCurrency == null) {
|
||||
throw new CurrencyNotFoundException(currencyCode);
|
||||
}
|
||||
|
||||
Office toOffice = this.officeRepository.findOne(command.getToOfficeId());
|
||||
if (toOffice == null) {
|
||||
throw new OfficeNotFoundException(command.getToOfficeId());
|
||||
}
|
||||
|
||||
MonetaryCurrency currency = new MonetaryCurrency("USD", 2);
|
||||
MonetaryCurrency currency = new MonetaryCurrency(appCurrency.getCode(), appCurrency.getDecimalPlaces());
|
||||
Money amount = Money.of(currency, command.getTransactionAmountValue());
|
||||
|
||||
OfficeFundsTransfer entity = OfficeFundsTransfer.create(currentUser.getOrganisation(), fromOffice, toOffice,
|
||||
|
||||
command.getTransactionDate(), amount);
|
||||
OfficeMonetaryTransfer entity = OfficeMonetaryTransfer.create(fromOffice, toOffice, command.getTransactionLocalDate(), amount);
|
||||
|
||||
this.officeFundsTransferRepository.save(entity);
|
||||
this.officeMonetaryTransferRepository.save(entity);
|
||||
|
||||
return entity.getId();
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user