/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Cyclos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package nl.strohalm.cyclos.webservices.rest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import nl.strohalm.cyclos.entities.access.Channel;
import nl.strohalm.cyclos.entities.access.User.TransactionPasswordStatus;
import nl.strohalm.cyclos.entities.accounts.AccountOwner;
import nl.strohalm.cyclos.entities.accounts.AccountType;
import nl.strohalm.cyclos.entities.accounts.Currency;
import nl.strohalm.cyclos.entities.accounts.MemberAccountType;
import nl.strohalm.cyclos.entities.accounts.SystemAccountOwner;
import nl.strohalm.cyclos.entities.accounts.transactions.Payment;
import nl.strohalm.cyclos.entities.accounts.transactions.TransferType;
import nl.strohalm.cyclos.entities.accounts.transactions.TransferTypeQuery;
import nl.strohalm.cyclos.entities.customization.fields.PaymentCustomField;
import nl.strohalm.cyclos.entities.customization.fields.PaymentCustomFieldValue;
import nl.strohalm.cyclos.entities.exceptions.EntityNotFoundException;
import nl.strohalm.cyclos.entities.members.Member;
import nl.strohalm.cyclos.entities.settings.LocalSettings;
import nl.strohalm.cyclos.services.access.AccessService;
import nl.strohalm.cyclos.services.access.exceptions.BlockedCredentialsException;
import nl.strohalm.cyclos.services.access.exceptions.InvalidCredentialsException;
import nl.strohalm.cyclos.services.accounts.AccountDTO;
import nl.strohalm.cyclos.services.accounts.AccountService;
import nl.strohalm.cyclos.services.accounts.AccountTypeService;
import nl.strohalm.cyclos.services.customization.PaymentCustomFieldService;
import nl.strohalm.cyclos.services.elements.ElementService;
import nl.strohalm.cyclos.services.elements.MemberService;
import nl.strohalm.cyclos.services.settings.SettingsService;
import nl.strohalm.cyclos.services.transactions.DoPaymentDTO;
import nl.strohalm.cyclos.services.transactions.PaymentService;
import nl.strohalm.cyclos.services.transactions.TransactionContext;
import nl.strohalm.cyclos.services.transactions.exceptions.MaxAmountPerDayExceededException;
import nl.strohalm.cyclos.services.transactions.exceptions.NotEnoughCreditsException;
import nl.strohalm.cyclos.services.transactions.exceptions.PaymentException;
import nl.strohalm.cyclos.services.transactions.exceptions.TransferMinimumPaymentException;
import nl.strohalm.cyclos.services.transactions.exceptions.UpperCreditLimitReachedException;
import nl.strohalm.cyclos.services.transfertypes.TransactionFeePreviewDTO;
import nl.strohalm.cyclos.services.transfertypes.TransactionFeeService;
import nl.strohalm.cyclos.services.transfertypes.TransferTypeService;
import nl.strohalm.cyclos.utils.CustomFieldHelper;
import nl.strohalm.cyclos.utils.RelationshipHelper;
import nl.strohalm.cyclos.utils.access.LoggedUser;
import nl.strohalm.cyclos.utils.query.QueryParameters.ResultType;
import nl.strohalm.cyclos.utils.validation.ValidationException;
import nl.strohalm.cyclos.webservices.model.AccountStatusVO;
import nl.strohalm.cyclos.webservices.model.DetailedTransferTypeVO;
import nl.strohalm.cyclos.webservices.model.FieldValueVO;
import nl.strohalm.cyclos.webservices.model.MemberVO;
import nl.strohalm.cyclos.webservices.model.PaymentDataVO;
import nl.strohalm.cyclos.webservices.model.ServerErrorVO;
import nl.strohalm.cyclos.webservices.model.TransactionFeeVO;
import nl.strohalm.cyclos.webservices.model.TransferTypeVO;
import nl.strohalm.cyclos.webservices.rest.TransferTypesRestController.Destination;
import nl.strohalm.cyclos.webservices.rest.TransferTypesRestController.TransferTypeSearchParams;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* Controller which handles /payments paths
*
* @author luis
*/
@Controller
public class PaymentsRestController extends BaseRestController {
/**
* Result after doing a payment confirmation
* @author jcomas
*/
public static class ConfirmPaymentResult {
private Long id;
private boolean pending;
public Long getId() {
return id;
}
public boolean isPending() {
return pending;
}
public void setId(final Long id) {
this.id = id;
}
public void setPending(final boolean pending) {
this.pending = pending;
}
}
/**
* Parameters for doing a payment to a member
* @author luis
*/
public static class DoMemberPaymentParameters extends DoPaymentParameters {
private Long toMemberId;
private String toMemberPrincipal;
private Integer installments = 0;
private Calendar firstInstallmentDate;
public Calendar getFirstInstallmentDate() {
return firstInstallmentDate;
}
public int getInstallments() {
return installments;
}
public Long getToMemberId() {
return toMemberId;
}
public String getToMemberPrincipal() {
return toMemberPrincipal;
}
public void setFirstInstallmentDate(final Calendar firstInstallmentDate) {
this.firstInstallmentDate = firstInstallmentDate;
}
public void setInstallments(final int installments) {
this.installments = installments;
}
public void setToMemberId(final Long toMemberId) {
this.toMemberId = toMemberId;
}
public void setToMemberPrincipal(final String toMemberPrincipal) {
this.toMemberPrincipal = toMemberPrincipal;
}
}
/**
* Parameters for doing a payment to system
* @author luis
*/
public static class DoPaymentParameters {
private Long currencyId;
private String currencySymbol;
private Long transferTypeId;
private BigDecimal amount;
private String description;
private String transactionPassword;
private List<FieldValueVO> customValues;
public BigDecimal getAmount() {
return amount;
}
public Long getCurrencyId() {
return currencyId;
}
public String getCurrencySymbol() {
return currencySymbol;
}
public List<FieldValueVO> getCustomValues() {
return customValues;
}
public String getDescription() {
return description;
}
public String getTransactionPassword() {
return transactionPassword;
}
public Long getTransferTypeId() {
return transferTypeId;
}
public void setAmount(final BigDecimal amount) {
this.amount = amount;
}
public void setCurrencyId(final Long currencyId) {
this.currencyId = currencyId;
}
public void setCurrencySymbol(final String currencySymbol) {
this.currencySymbol = currencySymbol;
}
public void setCustomValues(final List<FieldValueVO> customValues) {
this.customValues = customValues;
}
public void setDescription(final String description) {
this.description = description;
}
public void setTransactionPassword(final String transactionPassword) {
this.transactionPassword = transactionPassword;
}
public void setTransferTypeId(final Long transferTypeId) {
this.transferTypeId = transferTypeId;
}
@Override
public String toString() {
return "DoPaymentParameters [currencyId=" + currencyId + ", currencySymbol=" + currencySymbol + ", transferTypeId=" + transferTypeId + ", amount=" + amount + ", description=" + description + ", transactionPassword=" + transactionPassword + ", customValues=" + customValues + "]";
}
}
/**
* Result after doing a payment
* @author luis
*/
public static class DoPaymentResult {
private boolean wouldRequireAuthorization;
private MemberVO from;
private MemberVO to;
private BigDecimal finalAmount;
private String formattedFinalAmount;
private List<TransactionFeeVO> fees;
private TransferTypeVO transferType;
private Map<String, String> customValues;
public Map<String, String> getCustomValues() {
return customValues;
}
public List<TransactionFeeVO> getFees() {
return fees;
}
public BigDecimal getFinalAmount() {
return finalAmount;
}
public String getFormattedFinalAmount() {
return formattedFinalAmount;
}
public MemberVO getFrom() {
return from;
}
public MemberVO getTo() {
return to;
}
public TransferTypeVO getTransferType() {
return transferType;
}
public boolean isWouldRequireAuthorization() {
return wouldRequireAuthorization;
}
public void setCustomValues(final Map<String, String> customValues) {
this.customValues = customValues;
}
public void setFees(final List<TransactionFeeVO> fees) {
this.fees = fees;
}
public void setFinalAmount(final BigDecimal finalAmount) {
this.finalAmount = finalAmount;
}
public void setFormattedFinalAmount(final String formattedFinalAmount) {
this.formattedFinalAmount = formattedFinalAmount;
}
public void setFrom(final MemberVO from) {
this.from = from;
}
public void setTo(final MemberVO to) {
this.to = to;
}
public void setTransferType(final TransferTypeVO transferType) {
this.transferType = transferType;
}
public void setWouldRequireAuthorization(final boolean wouldRequireAuthorization) {
this.wouldRequireAuthorization = wouldRequireAuthorization;
}
}
private static final String BLOCKED_TRANSACTION_PASSWORD_ERROR = "BLOCKED_TRANSACTION_PASSWORD";
private static final String INVALID_TRANSACTION_PASSWORD_ERROR = "INVALID_TRANSACTION_PASSWORD";
private static final String MISSING_TRANSACTION_PASSWORD_ERROR = "MISSING_TRANSACTION_PASSWORD";
private static final String INACTIVE_TRANSACTION_PASSWORD_ERROR = "INACTIVE_TRANSACTION_PASSWORD";
private static final String NO_POSSIBLE_TRANSFER_TYPES_ERROR = "NO_POSSIBLE_TRANSFER_TYPES";
private static final String INVALID_AMOUNT_ERROR = "INVALID_AMOUNT";
private static final String MAX_AMOUNT_PER_DAY_EXCEEDED = "MAX_AMOUNT_PER_DAY_EXCEEDED";
private static final String NOT_ENOUGH_CREDITS = "NOT_ENOUGH_FUNDS";
private static final String UPPER_CREDIT_LIMIT_REACHED = "UPPER_CREDIT_LIMIT_REACHED";
protected static final String TRANSFER_MINIMUM_PAYMENT = "TRANSFER_MINIMUM_PAYMENT";
protected static final String UNKNOWN_PAYMENT_ERROR = "UNKNOWN_PAYMENT_ERROR";
private PaymentService paymentService;
private TransferTypeService transferTypeService;
private AccountTypeService accountTypeService;
private AccountService accountService;
private AccessService accessService;
private ElementService elementService;
private TransactionFeeService transactionFeeService;
private SettingsService settingsService;
private MemberService memberService;
private CustomFieldHelper customFieldHelper;
private PaymentCustomFieldService paymentCustomFieldService;
private TransferTypesRestController transferTypesRestController;
private AccessRestController accessRestController;
private AccountsRestController accountsRestController;
/**
* Confirms a payment to another member
*/
@RequestMapping(value = "payments/confirmMemberPayment", method = RequestMethod.POST)
@ResponseBody
public ConfirmPaymentResult confirmPaymentToMember(@RequestBody final DoMemberPaymentParameters params) {
if (params == null) {
throw new ValidationException();
}
Member toMember = memberService.loadByIdOrPrincipal(params.getToMemberId(), null, params.getToMemberPrincipal());
if (toMember == null) {
throw new EntityNotFoundException(Member.class);
}
return confirmPayment(params, toMember);
}
/**
* Confirms a payment to a system account
*/
@RequestMapping(value = "payments/confirmSystemPayment", method = RequestMethod.POST)
@ResponseBody
public ConfirmPaymentResult confirmPaymentToSystem(@RequestBody final DoPaymentParameters params) {
return confirmPayment(params, SystemAccountOwner.instance());
}
/**
* Performs a payment between accounts
*/
// TODO not possible now because transfer types with context self payment cannot have channels. Should we change this?
// @RequestMapping(value = "payments/selfPayment", method = RequestMethod.POST)
// @ResponseBody
// public DoPaymentResult doPaymentToSelf(@RequestBody final DoPaymentParameters params) {
// return doPayment(params, LoggedUser.member());
// }
/**
* Performs a payment to another member
*/
@RequestMapping(value = "payments/memberPayment", method = RequestMethod.POST)
@ResponseBody
public DoPaymentResult doPaymentToMember(@RequestBody final DoMemberPaymentParameters params) {
AccountOwner to = memberService.loadByIdOrPrincipal(params.getToMemberId(), null, params.getToMemberPrincipal());
if (to == null) {
throw new EntityNotFoundException(Member.class);
}
return doPayment(params, to);
}
/**
* Performs a payment to a system account
*/
@RequestMapping(value = "payments/systemPayment", method = RequestMethod.POST)
@ResponseBody
public DoPaymentResult doPaymentToSystem(@RequestBody final DoPaymentParameters params) {
return doPayment(params, SystemAccountOwner.instance());
}
/**
* Returns the necessary information to prepare a payment
*/
@RequestMapping(value = "payments/paymentData", method = RequestMethod.GET)
@ResponseBody
public PaymentDataVO getPaymentData(final TransferTypeSearchParams params) {
PaymentDataVO paymentData = new PaymentDataVO();
TransferTypeQuery query = transferTypesRestController.toTransferTypeQuery(params);
List<TransferType> transferTypes = transferTypeService.search(query);
List<DetailedTransferTypeVO> transferTypeVOs = new ArrayList<DetailedTransferTypeVO>();
for (TransferType transferType : transferTypes) {
transferTypeVOs.add((DetailedTransferTypeVO) transferTypeService.getTransferTypeVO(transferType.getId(), true));
}
paymentData.setTransferTypes(transferTypeVOs);
Map<Long, AccountStatusVO> statuses = new HashMap<Long, AccountStatusVO>();
for (TransferType tt : transferTypes) {
if (statuses.get(tt.getFrom().getId()) == null) {
AccountDTO accountDTO = new AccountDTO(LoggedUser.member(), tt.getFrom());
statuses.put(tt.getFrom().getId(), accountService.getCurrentAccountStatusVO(accountDTO));
}
}
paymentData.setAccountsStatus(statuses);
if (params.getDestination() == Destination.MEMBER) {
Member toMember = null;
if (params.getToMemberId() != null) {
toMember = elementService.load(params.getToMemberId());
} else if (params.getToMemberPrincipal() != null) {
toMember = elementService.loadByPrincipal(null, params.getToMemberPrincipal());
}
paymentData.setToMember(memberService.getMemberVO(toMember, false, false));
}
return paymentData;
}
/**
* Handles {@link PaymentException}s
*/
@ExceptionHandler(PaymentException.class)
@ResponseBody
@ResponseStatus(HttpStatus.METHOD_FAILURE)
public ServerErrorVO handlePaymentException(final PaymentException ex) {
String errorCode = UNKNOWN_PAYMENT_ERROR;
if (ex instanceof MaxAmountPerDayExceededException) {
errorCode = MAX_AMOUNT_PER_DAY_EXCEEDED;
} else if (ex instanceof NotEnoughCreditsException) {
errorCode = NOT_ENOUGH_CREDITS;
} else if (ex instanceof TransferMinimumPaymentException) {
errorCode = TRANSFER_MINIMUM_PAYMENT;
} else if (ex instanceof UpperCreditLimitReachedException) {
errorCode = UPPER_CREDIT_LIMIT_REACHED;
}
return new ServerErrorVO(errorCode, null);
}
public void setAccessRestController(final AccessRestController accessRestController) {
this.accessRestController = accessRestController;
}
public void setAccessService(final AccessService accessService) {
this.accessService = accessService;
}
public void setAccountService(final AccountService accountService) {
this.accountService = accountService;
}
public void setAccountsRestController(final AccountsRestController accountsRestController) {
this.accountsRestController = accountsRestController;
}
public void setAccountTypeService(final AccountTypeService accountTypeService) {
this.accountTypeService = accountTypeService;
}
public void setCustomFieldHelper(final CustomFieldHelper customFieldHelper) {
this.customFieldHelper = customFieldHelper;
}
public void setElementService(final ElementService elementService) {
this.elementService = elementService;
}
public void setMemberService(final MemberService memberService) {
this.memberService = memberService;
}
public void setPaymentCustomFieldService(final PaymentCustomFieldService paymentCustomFieldService) {
this.paymentCustomFieldService = paymentCustomFieldService;
}
public void setPaymentService(final PaymentService paymentService) {
this.paymentService = paymentService;
}
public void setSettingsService(final SettingsService settingsService) {
this.settingsService = settingsService;
}
// Create the result
public void setTransactionFeeService(final TransactionFeeService transactionFeeService) {
this.transactionFeeService = transactionFeeService;
}
public void setTransferTypeService(final TransferTypeService transferTypeService) {
this.transferTypeService = transferTypeService;
}
public void setTransferTypesRestController(final TransferTypesRestController transferTypesRestController) {
this.transferTypesRestController = transferTypesRestController;
}
private DoPaymentDTO buildDoPaymentDTO(final DoPaymentParameters params, final AccountOwner toOwner, final TransferType transferType) {
DoPaymentDTO dto = new DoPaymentDTO();
dto.setContext(TransactionContext.PAYMENT);
dto.setChannel(Channel.REST);
dto.setAmount(params.getAmount());
dto.setCurrency(null);
dto.setTo(toOwner);
dto.setTransferType(transferType);
dto.setDescription(params.getDescription());
// dto.setPayments(installments);
List<PaymentCustomField> allowedFields = paymentCustomFieldService.list(transferType, true);
final Collection<PaymentCustomFieldValue> customValues = customFieldHelper.toValueCollection(allowedFields, params.getCustomValues());
dto.setCustomValues(customValues);
return dto;
}
/*
*
* private List<ScheduledPaymentDTO> buildInstallments(final DoPaymentParameters params, final Member loggedMember, final BigDecimal amount, final
* TransferType transferType) { List<ScheduledPaymentDTO> installments = null; if (params instanceof DoMemberPaymentParameters) {
* DoMemberPaymentParameters mp = (DoMemberPaymentParameters) params; Integer installmentCount = mp.getInstallments(); if (installmentCount !=
* null && installmentCount > 0) { Calendar firstDate = mp.getFirstInstallmentDate(); if (firstDate == null) { firstDate = Calendar.getInstance();
* } ProjectionDTO projection = new ProjectionDTO(); projection.setAmount(amount); projection.setFrom(loggedMember);
* projection.setRecurrence(TimePeriod.ONE_MONTH); projection.setTransferType(transferType); projection.setFirstExpirationDate(firstDate);
* projection.setPaymentCount(installmentCount); installments = paymentService.calculatePaymentProjection(projection); } } return installments; }
*/
private ConfirmPaymentResult confirmPayment(final DoPaymentParameters params, final AccountOwner toOwner) {
if (params == null) {
throw new ValidationException();
}
Member loggedMember = LoggedUser.member();
BigDecimal amount = params.getAmount();
if (amount == null) {
throw new IllegalArgumentException(INVALID_AMOUNT_ERROR);
}
TransferType transferType = resolveTransferType(params, toOwner);
// Calculate the installments
// List<ScheduledPaymentDTO> installments = buildInstallments(params, amount, transferType);
// Check the transaction password, if needed
if (accessRestController.isRequireTransactionPassword()) {
String transactionPassword = params.getTransactionPassword();
TransactionPasswordStatus status = loggedMember.getUser().getTransactionPasswordStatus();
if (status == null || status == TransactionPasswordStatus.PENDING || status == TransactionPasswordStatus.NEVER_CREATED) {
throw new IllegalArgumentException(INACTIVE_TRANSACTION_PASSWORD_ERROR);
}
if (StringUtils.isEmpty(transactionPassword)) {
throw new IllegalArgumentException(MISSING_TRANSACTION_PASSWORD_ERROR);
}
try {
accessService.checkTransactionPassword(transactionPassword);
} catch (InvalidCredentialsException e) {
throw new IllegalArgumentException(INVALID_TRANSACTION_PASSWORD_ERROR);
} catch (BlockedCredentialsException e) {
throw new IllegalArgumentException(BLOCKED_TRANSACTION_PASSWORD_ERROR);
}
}
// Create the DoPaymentDTO
DoPaymentDTO dto = buildDoPaymentDTO(params, toOwner, transferType);
// Perform the payment
Payment payment = paymentService.doPayment(dto);
// Create the result
ConfirmPaymentResult result = new ConfirmPaymentResult();
result.setId(payment.getId());
result.setPending(payment.getProcessDate() == null);
return result;
}
private DoPaymentResult doPayment(final DoPaymentParameters params, final AccountOwner to) {
DoPaymentResult result = new DoPaymentResult();
if (params == null) {
throw new ValidationException();
}
AccountOwner from = LoggedUser.accountOwner();
TransferType transferType = resolveTransferType(params, to);
transferType = transferTypeService.load(transferType.getId(), RelationshipHelper.nested(TransferType.Relationships.FROM, AccountType.Relationships.CURRENCY), TransferType.Relationships.TO);
DoPaymentDTO doPaymentDTO = buildDoPaymentDTO(params, to, transferType);
paymentService.validate(doPaymentDTO);
result.setTransferType(transferTypeService.getTransferTypeVO(transferType.getId(), false));
final boolean wouldRequireAuthorization = paymentService.wouldRequireAuthorization(transferType, params.getAmount(), LoggedUser.accountOwner());
result.setWouldRequireAuthorization(wouldRequireAuthorization);
// TODO support past dates
// if (wouldRequireAuthorization && params.getDate() != null) {
// throw new ValidationException("payment.error.authorizedInPast");
// }
// Fetch related data
result.setFrom(memberService.getMemberVO((Member) from, false, false));
if (to != null && to instanceof Member) {
result.setTo(memberService.getMemberVO((Member) to, false, false));
}
// Store the transaction fees
final TransactionFeePreviewDTO preview = transactionFeeService.preview(from, to, transferType, params.getAmount());
result.setFinalAmount(preview.getFinalAmount());
final LocalSettings localSettings = settingsService.getLocalSettings();
String formattedAmount = localSettings.getUnitsConverter(transferType.getCurrency().getPattern()).toString(preview.getFinalAmount());
result.setFees(transactionFeeService.getTransactionFeeVOs(preview));
result.setFormattedFinalAmount(formattedAmount);
// TODO: support scheduled payments
// Calculate the transaction fees for every scheduled payment
/*
* final List<ScheduledPaymentDTO> payments = payment.getPayments(); final boolean isScheduled = CollectionUtils.isNotEmpty(payments); if
* (isScheduled) { for (final ScheduledPaymentDTO current : payments) { final TransactionFeePreviewDTO currentPreview =
* transactionFeeService.preview(from, to, transferType, current.getAmount()); current.setFinalAmount(currentPreview.getFinalAmount()); } }
* request.setAttribute("isScheduled", isScheduled);
*/
// Add the custom values to the result.
if (doPaymentDTO.getCustomValues() != null) {
Map<String, String> customValues = new LinkedHashMap<String, String>();
for (PaymentCustomFieldValue cfv : doPaymentDTO.getCustomValues()) {
customValues.put(cfv.getField().getName(), cfv.getValue());
}
result.setCustomValues(customValues);
}
return result;
}
private TransferType resolveTransferType(final DoPaymentParameters params, final AccountOwner toOwner) {
Member loggedMember = LoggedUser.member();
Currency currency = accountsRestController.loadCurrencyByIdOrSymbol(params.getCurrencyId(), params.getCurrencySymbol());
final TransferTypeQuery query = new TransferTypeQuery();
query.setResultType(ResultType.LIST);
query.setContext(loggedMember.equals(toOwner) ? TransactionContext.SELF_PAYMENT : TransactionContext.PAYMENT);
query.setChannel(Channel.REST);
query.setFromOwner(loggedMember);
query.setToOwner(toOwner);
query.setCurrency(currency);
List<TransferType> possibleTransferTypes = transferTypeService.search(query);
if (possibleTransferTypes.isEmpty()) {
throw new IllegalArgumentException(NO_POSSIBLE_TRANSFER_TYPES_ERROR);
}
// Resolve the transfer type
Long transferTypeId = params.getTransferTypeId();
TransferType transferType = null;
if (transferTypeId != null) {
for (TransferType tt : possibleTransferTypes) {
if (tt.getId().equals(transferTypeId)) {
transferType = tt;
break;
}
}
} else {
// When there are multiple transfer types, prefer the first one from the default account
if (possibleTransferTypes.size() > 1) {
MemberAccountType defaultType = accountTypeService.getDefault(loggedMember.getMemberGroup());
for (TransferType current : possibleTransferTypes) {
if (current.getFrom().equals(defaultType)) {
transferType = current;
break;
}
}
}
// No TT found so far. Get the first one
if (transferType == null) {
transferType = possibleTransferTypes.isEmpty() ? null : possibleTransferTypes.get(0);
}
}
if (transferType == null) {
throw new EntityNotFoundException(TransferType.class);
}
return transferType;
}
}