/* 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.controls.payments; import java.math.BigDecimal; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import nl.strohalm.cyclos.controls.ActionContext; import nl.strohalm.cyclos.entities.access.Channel; import nl.strohalm.cyclos.entities.accounts.AccountOwner; import nl.strohalm.cyclos.entities.accounts.Currency; import nl.strohalm.cyclos.entities.accounts.SystemAccountOwner; import nl.strohalm.cyclos.entities.accounts.transactions.TransferTypeQuery; import nl.strohalm.cyclos.entities.groups.MemberGroup; import nl.strohalm.cyclos.entities.groups.MemberGroupSettings; import nl.strohalm.cyclos.entities.members.Element; import nl.strohalm.cyclos.entities.members.Member; import nl.strohalm.cyclos.entities.settings.LocalSettings; import nl.strohalm.cyclos.services.transactions.DoPaymentDTO; import nl.strohalm.cyclos.services.transactions.ScheduledPaymentDTO; import nl.strohalm.cyclos.services.transactions.TransactionContext; import nl.strohalm.cyclos.utils.ActionHelper; import nl.strohalm.cyclos.utils.EntityHelper; import nl.strohalm.cyclos.utils.TimePeriod; import nl.strohalm.cyclos.utils.binding.BeanBinder; import nl.strohalm.cyclos.utils.binding.BeanCollectionBinder; import nl.strohalm.cyclos.utils.binding.DataBinder; import nl.strohalm.cyclos.utils.binding.PropertyBinder; import nl.strohalm.cyclos.utils.conversion.AccountOwnerConverter; import nl.strohalm.cyclos.utils.conversion.CoercionHelper; import nl.strohalm.cyclos.utils.conversion.IdConverter; import nl.strohalm.cyclos.utils.validation.ValidationException; import org.apache.commons.lang.time.DateUtils; import org.apache.struts.action.ActionForward; /** * Action for performing payments from an account owner to another one * @author luis */ public class PaymentAction extends BasePaymentAction { @Override protected AccountOwner getFromOwner(final ActionContext context) { final PaymentForm form = context.getForm(); final Long fromId = IdConverter.instance().valueOf(form.getFrom()); if (fromId == null) { return context.getAccountOwner(); } final Element element = elementService.load(fromId, Element.Relationships.GROUP); if (element instanceof Member) { return (Member) element; } return null; } @Override protected ActionForward handleSubmit(final ActionContext context) throws Exception { final PaymentForm form = context.getForm(); final Map<String, Object> params = new HashMap<String, Object>(); params.put("selectMember", form.isSelectMember()); params.put("toSystem", form.isToSystem()); params.put("from", form.getFrom()); return ActionHelper.redirectWithParams(context.getRequest(), super.handleSubmit(context), params); } @Override protected DataBinder<DoPaymentDTO> initDataBinder() { final BeanBinder<DoPaymentDTO> binder = (BeanBinder<DoPaymentDTO>) super.initDataBinder(); binder.registerBinder("to", PropertyBinder.instance(AccountOwner.class, "to", AccountOwnerConverter.instance())); final LocalSettings localSettings = settingsService.getLocalSettings(); final BeanBinder<ScheduledPaymentDTO> scheduledPayments = BeanBinder.instance(ScheduledPaymentDTO.class); scheduledPayments.registerBinder("date", PropertyBinder.instance(Calendar.class, "date", localSettings.getRawDateConverter())); scheduledPayments.registerBinder("amount", PropertyBinder.instance(BigDecimal.class, "amount", localSettings.getNumberConverter())); binder.registerBinder("payments", BeanCollectionBinder.instance(scheduledPayments, "payments")); return binder; } @Override protected void prepareForm(final ActionContext context) throws Exception { super.prepareForm(context); final HttpServletRequest request = context.getRequest(); final PaymentForm form = context.getForm(); String titleKey = null; final boolean toSystem = form.isToSystem(); final boolean selectMember = form.isSelectMember(); final boolean asMember = (Boolean) request.getAttribute("asMember"); final Member fromMember = (Member) request.getAttribute("member"); if (toSystem) { // Payment to system if (asMember) { // from selected member to system if (context.isAdmin()) { // admin making member to system payment titleKey = "payment.title.systemMemberToSystem"; } else { // broker making member to system payment titleKey = "payment.title.brokerMemberToSystem"; } } else { // payment from logged member to system titleKey = "payment.title.memberToSystem"; } } else if (selectMember) { // Payment to an yet unknown member if (asMember) { // from selected member to another member if (context.isAdmin()) { // admin making member to another member titleKey = "payment.title.systemMemberToMember"; } else { // broker making member to another member titleKey = "payment.title.brokerMemberToMember"; } } else { // from logged user to another member if (context.isAdmin()) { titleKey = "payment.title.systemToMember"; } else { titleKey = "payment.title.memberToMember"; } } } else { // Payment to a pre-selected member Member member = null; final Long memberId = IdConverter.instance().valueOf(form.getTo()); final Element loggedElement = context.getElement(); if (memberId != null && memberId != loggedElement.getId()) { final Element element = elementService.load(memberId, Element.Relationships.USER); if (element instanceof Member) { member = (Member) element; } } if (member == null) { throw new ValidationException(); } request.setAttribute("member", member); if (context.isAdmin()) { titleKey = "payment.title.systemToMember"; } else { titleKey = "payment.title.memberToMember"; } } request.setAttribute("titleKey", titleKey); request.setAttribute("toSystem", toSystem); request.setAttribute("toMember", !toSystem); request.setAttribute("selectMember", selectMember); request.setAttribute("currentTime", System.currentTimeMillis()); request.setAttribute("fromMember", fromMember); // Check whether scheduled payments may be performed boolean allowsScheduling = false; boolean allowsMultipleScheduling = false; if (context.isAdmin() && fromMember == null) { allowsScheduling = true; allowsMultipleScheduling = true; } else { MemberGroup memberGroup; if (fromMember == null) { memberGroup = ((Member) context.getAccountOwner()).getMemberGroup(); } else { memberGroup = fromMember.getMemberGroup(); } final MemberGroupSettings memberSettings = memberGroup.getMemberSettings(); allowsScheduling = memberSettings.isAllowsScheduledPayments(); allowsMultipleScheduling = memberSettings.isAllowsMultipleScheduledPayments(); } if (allowsScheduling) { request.setAttribute("allowsScheduling", allowsScheduling); request.setAttribute("allowsMultipleScheduling", allowsMultipleScheduling); final Collection<SchedulingType> schedulingTypes = EnumSet.of(SchedulingType.IMMEDIATELY, SchedulingType.SINGLE_FUTURE); if (allowsMultipleScheduling) { schedulingTypes.add(SchedulingType.MULTIPLE_FUTURE); } request.setAttribute("schedulingTypes", schedulingTypes); request.setAttribute("schedulingFields", Arrays.asList(TimePeriod.Field.MONTHS, TimePeriod.Field.WEEKS, TimePeriod.Field.DAYS)); } } /** * Reads the payment DTO from the form */ @Override protected DoPaymentDTO resolvePaymentDTO(final ActionContext context) { final DoPaymentDTO dto = super.resolvePaymentDTO(context); dto.setContext(TransactionContext.PAYMENT); final PaymentForm form = context.getForm(); if (form.isToSystem()) { dto.setTo(SystemAccountOwner.instance()); } // When there is a single payment scheduled for today, remove it, making the payment to be processed now final List<ScheduledPaymentDTO> payments = dto.getPayments(); if (payments != null && payments.size() == 1) { final ScheduledPaymentDTO payment = payments.get(0); if (DateUtils.isSameDay(Calendar.getInstance(), payment.getDate())) { // A single payment scheduled for today is handled as not scheduled dto.setPayments(null); } } return dto; } @SuppressWarnings("unchecked") @Override protected TransferTypeQuery resolveTransferTypeQuery(final ActionContext context) { final PaymentForm form = context.getForm(); final Long fromId = IdConverter.instance().valueOf(form.getFrom()); final Long toId = IdConverter.instance().valueOf(form.getTo()); final boolean fromMe = fromId == null; final boolean asMember = !fromMe; final boolean toSpecificMember = !form.isSelectMember() && !form.isToSystem(); final boolean toUnknownMember = form.isSelectMember(); final boolean toSystem = form.isToSystem(); if (toUnknownMember || (asMember && !toSystem)) { // Since we don't know who will receive the payment yet, we cannot resolve transfer types return null; } // Check the preselected currency Currency currency = CoercionHelper.coerce(Currency.class, form.getCurrency()); // When there's none, use the first one if (currency == null) { final HttpServletRequest request = context.getRequest(); final Collection<Currency> currencies = (Collection<Currency>) request.getAttribute("currencies"); if (!currencies.isEmpty()) { currency = currencies.iterator().next(); } } // Build the query final TransferTypeQuery query = new TransferTypeQuery(); query.setChannel(Channel.WEB); query.setContext(TransactionContext.PAYMENT); query.setUsePriority(true); // query.setCurrency(currency); // Determine the from if (fromMe) { query.setGroup(context.getGroup()); query.setFromOwner(context.getAccountOwner()); } else { query.setBy(context.getElement()); query.setFromOwner(EntityHelper.reference(Member.class, fromId)); } // Determine the to if (toSystem) { query.setToOwner(SystemAccountOwner.instance()); } else if (toSpecificMember) { query.setToOwner(EntityHelper.reference(Member.class, toId)); } return query; } }