/*
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.services.elements;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import nl.strohalm.cyclos.access.AdminMemberPermission;
import nl.strohalm.cyclos.access.BrokerPermission;
import nl.strohalm.cyclos.access.MemberPermission;
import nl.strohalm.cyclos.access.OperatorPermission;
import nl.strohalm.cyclos.dao.members.ElementDAO;
import nl.strohalm.cyclos.dao.sms.MemberSmsStatusDAO;
import nl.strohalm.cyclos.entities.access.User;
import nl.strohalm.cyclos.entities.accounts.Account;
import nl.strohalm.cyclos.entities.accounts.AccountStatus;
import nl.strohalm.cyclos.entities.accounts.MemberAccount;
import nl.strohalm.cyclos.entities.accounts.MemberAccountType;
import nl.strohalm.cyclos.entities.accounts.loans.Loan;
import nl.strohalm.cyclos.entities.accounts.loans.LoanQuery;
import nl.strohalm.cyclos.entities.accounts.transactions.Invoice;
import nl.strohalm.cyclos.entities.accounts.transactions.InvoiceQuery;
import nl.strohalm.cyclos.entities.accounts.transactions.InvoiceSummaryDTO;
import nl.strohalm.cyclos.entities.accounts.transactions.TransferQuery;
import nl.strohalm.cyclos.entities.accounts.transactions.TransferType;
import nl.strohalm.cyclos.entities.accounts.transactions.TransfersAwaitingAuthorizationQuery;
import nl.strohalm.cyclos.entities.customization.fields.MemberCustomField;
import nl.strohalm.cyclos.entities.exceptions.EntityNotFoundException;
import nl.strohalm.cyclos.entities.groups.BrokerGroup;
import nl.strohalm.cyclos.entities.groups.Group.Nature;
import nl.strohalm.cyclos.entities.groups.MemberGroup;
import nl.strohalm.cyclos.entities.groups.OperatorGroup;
import nl.strohalm.cyclos.entities.members.Administrator;
import nl.strohalm.cyclos.entities.members.BrokeringQuery;
import nl.strohalm.cyclos.entities.members.Element;
import nl.strohalm.cyclos.entities.members.FullTextMemberQuery;
import nl.strohalm.cyclos.entities.members.Member;
import nl.strohalm.cyclos.entities.members.Operator;
import nl.strohalm.cyclos.entities.members.PaymentsAwaitingFeedbackQuery;
import nl.strohalm.cyclos.entities.members.Reference;
import nl.strohalm.cyclos.entities.members.ReferenceQuery;
import nl.strohalm.cyclos.entities.members.brokerings.BrokerCommissionContract;
import nl.strohalm.cyclos.entities.members.brokerings.BrokerCommissionContractQuery;
import nl.strohalm.cyclos.entities.members.messages.MessageBox;
import nl.strohalm.cyclos.entities.members.messages.MessageQuery;
import nl.strohalm.cyclos.entities.members.preferences.NotificationPreference;
import nl.strohalm.cyclos.entities.sms.MemberSmsStatus;
import nl.strohalm.cyclos.exceptions.PermissionDeniedException;
import nl.strohalm.cyclos.services.access.AccessServiceLocal;
import nl.strohalm.cyclos.services.access.ChannelServiceLocal;
import nl.strohalm.cyclos.services.accounts.AccountServiceLocal;
import nl.strohalm.cyclos.services.accounts.GetTransactionsDTO;
import nl.strohalm.cyclos.services.accounts.rates.ConversionSimulationDTO;
import nl.strohalm.cyclos.services.accounts.rates.RateServiceLocal;
import nl.strohalm.cyclos.services.ads.AdServiceLocal;
import nl.strohalm.cyclos.services.customization.MemberCustomFieldService;
import nl.strohalm.cyclos.services.fetch.FetchServiceLocal;
import nl.strohalm.cyclos.services.groups.GroupServiceLocal;
import nl.strohalm.cyclos.services.permissions.PermissionServiceLocal;
import nl.strohalm.cyclos.services.preferences.PreferenceServiceLocal;
import nl.strohalm.cyclos.services.sms.ISmsContext;
import nl.strohalm.cyclos.services.sms.MemberGroupSmsContextImpl;
import nl.strohalm.cyclos.services.sms.exceptions.SmsContextInitializationException;
import nl.strohalm.cyclos.services.transactions.InvoiceServiceLocal;
import nl.strohalm.cyclos.services.transactions.LoanServiceLocal;
import nl.strohalm.cyclos.services.transactions.PaymentServiceLocal;
import nl.strohalm.cyclos.services.transactions.TransactionSummaryVO;
import nl.strohalm.cyclos.services.transactions.TransferAuthorizationServiceLocal;
import nl.strohalm.cyclos.services.transfertypes.TransactionFeePreviewForRatesDTO;
import nl.strohalm.cyclos.services.transfertypes.TransferTypeServiceLocal;
import nl.strohalm.cyclos.utils.CustomFieldHelper;
import nl.strohalm.cyclos.utils.CustomObjectHandler;
import nl.strohalm.cyclos.utils.DateHelper;
import nl.strohalm.cyclos.utils.IteratorListImpl;
import nl.strohalm.cyclos.utils.Period;
import nl.strohalm.cyclos.utils.RelationshipHelper;
import nl.strohalm.cyclos.utils.TimePeriod;
import nl.strohalm.cyclos.utils.TransactionHelper;
import nl.strohalm.cyclos.utils.Transactional;
import nl.strohalm.cyclos.utils.access.LoggedUser;
import nl.strohalm.cyclos.utils.lock.LockHandler;
import nl.strohalm.cyclos.utils.lock.LockHandlerFactory;
import nl.strohalm.cyclos.utils.query.IteratorList;
import nl.strohalm.cyclos.utils.query.PageHelper;
import nl.strohalm.cyclos.webservices.WebServiceContext;
import nl.strohalm.cyclos.webservices.members.FullTextMemberSearchParameters;
import nl.strohalm.cyclos.webservices.members.MemberResultPage;
import nl.strohalm.cyclos.webservices.model.MemberVO;
import nl.strohalm.cyclos.webservices.model.MyProfileVO;
import nl.strohalm.cyclos.webservices.utils.MemberHelper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.transaction.TransactionStatus;
/**
* Implementation for MemberService
* @author luis
*/
public class MemberServiceImpl implements MemberServiceLocal {
private FetchServiceLocal fetchService;
private PreferenceServiceLocal preferenceService;
private AccountServiceLocal accountService;
private InvoiceServiceLocal invoiceService;
private PermissionServiceLocal permissionService;
private BrokeringServiceLocal brokeringService;
private LoanServiceLocal loanService;
private AdServiceLocal adService;
private ReferenceServiceLocal referenceService;
private PaymentServiceLocal paymentService;
private TransferAuthorizationServiceLocal transferAuthorizationService;
private MessageServiceLocal messageService;
private ElementDAO elementDao;
private RateServiceLocal rateService;
private TransferTypeServiceLocal transferTypeService;
private AccessServiceLocal accessService;
private ChannelServiceLocal channelService;
private MemberSmsStatusDAO memberSmsStatusDao;
private GroupServiceLocal groupService;
private LockHandlerFactory lockHandlerFactory;
private TransactionHelper transactionHelper;
private CommissionServiceLocal commissionService;
private CustomObjectHandler customObjectHandler;
private ElementServiceLocal elementService;
private MemberHelper memberHelper;
private MemberCustomFieldService memberCustomFieldService;
private CustomFieldHelper customFieldHelper;
/**
* Ensure the sms status has the "allow charging sms" flag set correctly.<br>
* If there isn't free sms, the additional charged package's size is one and the member accept any feature by sms then the flag is set to true.
*/
@Override
public void ensureAllowChargingSms(final MemberSmsStatus memberSmsStatus, final boolean hasNotificationsBySms) {
// Check if we must set the allowChargingSms flag
Member member = memberSmsStatus.getMember();
final ISmsContext smsContext = getSmsContext(member);
final int smsFree = smsContext.getFreeSms(member);
final int smsAdditionalCharged = smsContext.getAdditionalChargedSms(member);
if (smsAdditionalCharged == 1 && smsFree == 0) {
Member fetchedMember = fetchService.fetch(member, Member.Relationships.CHANNELS);
final boolean smsChannelEnabled = accessService.getChannelsEnabledForMember(fetchedMember).contains(channelService.getSmsChannel());
final boolean allowChargingSms = smsChannelEnabled || memberSmsStatus.isAcceptPaidMailing() || hasNotificationsBySms;
memberSmsStatus.setAllowChargingSms(allowChargingSms);
}
}
@Override
public ActivitiesVO getActivities(Member member) {
member = fetchService.fetch(member, Element.Relationships.GROUP);
return doGetActivities(member);
}
@Override
public Map<MemberGroup, Integer> getGroupMemberCount(final Collection<MemberGroup> groups, final Calendar timePoint) {
Map<Long, Integer> countPerGroupId;
if (timePoint == null) {
countPerGroupId = elementDao.getCountPerGroup(groups);
} else {
countPerGroupId = elementDao.getCountPerGroup(groups, timePoint);
}
final Map<MemberGroup, Integer> groupMemberCount = new TreeMap<MemberGroup, Integer>();
// Initialize with zeros
for (MemberGroup group : groups) {
group = groupService.load(group.getId());
groupMemberCount.put(group, 0);
}
// Count
for (final Entry<Long, Integer> entry : countPerGroupId.entrySet()) {
MemberGroup group = groupService.load(entry.getKey());
Integer count = entry.getValue();
groupMemberCount.put(group, count);
}
return groupMemberCount;
}
@Override
public MemberResultPage getMemberResultPage(final FullTextMemberSearchParameters params) {
FullTextMemberQuery query = memberHelper.toFullTextQuery(params);
if (!elementService.applyQueryRestrictions(query)) {
throw new PermissionDeniedException();
}
@SuppressWarnings("unchecked")
List<Member> members = (List<Member>) elementService.fullTextSearch(query);
return memberHelper.toResultPage(members, params.getShowCustomFields(), params.getShowImages());
}
@Override
public MemberVO getMemberVO(final Member member, final boolean useMemberFields, final boolean useImages) {
List<MemberCustomField> fields = null;
if (useMemberFields) {
fields = memberCustomFieldService.list();
if (!LoggedUser.isUnrestrictedClient()) {
MemberGroup group = LoggedUser.member().getMemberGroup();
fields = customFieldHelper.onlyVisibleFields(fields, group);
}
}
return memberHelper.toVO(member, fields, useImages);
}
@Override
public MyProfileVO getMyProfileVO(final Member member) {
return memberHelper.toMyProfileVO(member);
}
@Override
public QuickAccessVO getQuickAccess() {
final Member member = (Member) LoggedUser.accountOwner();
final QuickAccessVO quickAccess = new QuickAccessVO();
quickAccess.setUpdateProfile(true); // Update profile is always visible
quickAccess.setSearchMembers(CollectionUtils.isNotEmpty(permissionService.getVisibleMemberGroups()));
quickAccess.setAccountInformation(permissionService.permission(member).member().operator(OperatorPermission.ACCOUNT_ACCOUNT_INFORMATION).hasPermission() && CollectionUtils.isNotEmpty(accountService.getAccounts(member)));
if (LoggedUser.isOperator()) {
quickAccess.setMemberPayment(permissionService.permission().operator(OperatorPermission.PAYMENTS_PAYMENT_TO_MEMBER).hasPermission() && permissionService.permission().operator(OperatorPermission.ACCOUNT_ACCOUNT_INFORMATION).hasPermission());
} else if (LoggedUser.isMember()) {
quickAccess.setMemberPayment(permissionService.permission().member(MemberPermission.PAYMENTS_PAYMENT_TO_MEMBER).hasPermission());
}
quickAccess.setPublishAd(permissionService.permission().member(MemberPermission.ADS_PUBLISH).operator(OperatorPermission.ADS_PUBLISH).hasPermission());
quickAccess.setSearchAds(permissionService.permission().member(MemberPermission.ADS_VIEW).operator(MemberPermission.ADS_VIEW).hasPermission());
quickAccess.setViewMessages(permissionService.permission().member(MemberPermission.MESSAGES_VIEW).operator(OperatorPermission.MESSAGES_VIEW).hasPermission());
quickAccess.setViewContacts(permissionService.permission().member().operator(OperatorPermission.CONTACTS_VIEW).hasPermission());
return quickAccess;
}
@Override
public ISmsContext getSmsContext(final Member member) throws SmsContextInitializationException {
MemberGroup memberGroup = member.getMemberGroup();
String className = memberGroup.getMemberSettings().getSmsContextClassName();
if (StringUtils.isEmpty(className)) {
return MemberGroupSmsContextImpl.getInstance();
} else {
try {
return customObjectHandler.get(className);
} catch (Exception e) {
throw new SmsContextInitializationException(memberGroup, className, e.getMessage());
}
}
}
@Override
public MemberSmsStatus getSmsStatus(final Member member, final boolean update) {
boolean isNewTransaction = !update;
if (isNewTransaction) {
// Run in a new transaction to support retry if there is a locking exception
MemberSmsStatus status = transactionHelper.runInNewTransaction(new Transactional<MemberSmsStatus>() {
@Override
public MemberSmsStatus afterCommit(final MemberSmsStatus result) {
// Ensure the status is attached to the current transaction
return fetchService.fetch(result, RelationshipHelper.nested(MemberSmsStatus.Relationships.MEMBER, Element.Relationships.GROUP));
}
@Override
public MemberSmsStatus doInTransaction(final TransactionStatus status) {
if (!update) {
status.setRollbackOnly();
}
return performGetSmsStatus(member);
}
});
// because the Tx is rolled back we set the member directly
status.setMember(member);
return status;
} else {
return performGetSmsStatus(member);
}
}
@Override
public MemberStatusVO getStatus() {
final MemberStatusVO status = new MemberStatusVO();
final Member member = (Member) LoggedUser.accountOwner();
MemberGroup group = member.getMemberGroup();
final User user = LoggedUser.user();
final Calendar lastLogin = user.getLastLogin();
final boolean isOperator = LoggedUser.isOperator();
// Count the unread messages
if (permissionService.hasPermission(isOperator ? OperatorPermission.MESSAGES_VIEW : MemberPermission.MESSAGES_VIEW)) {
final MessageQuery messages = new MessageQuery();
messages.setGetter(member);
messages.setMessageBox(MessageBox.INBOX);
messages.setRead(false);
messages.setPageForCount();
status.setUnreadMessages(PageHelper.getTotalCount(messageService.search(messages)));
}
// Count the new payments since the last login
group = fetchService.fetch(group, MemberGroup.Relationships.ACCOUNT_SETTINGS);
final Collection<MemberAccountType> accountTypes = group.getAccountTypes();
if (CollectionUtils.isNotEmpty(accountTypes) && !(isOperator && !permissionService.hasPermission(OperatorPermission.ACCOUNT_ACCOUNT_INFORMATION))) {
final TransferQuery transfers = new TransferQuery();
transfers.setRootOnly(true);
transfers.setToAccountOwner(member);
transfers.setLoanTransfer(false);
if (lastLogin != null) {
transfers.setPeriod(Period.begginingAt(lastLogin).useTime());
}
transfers.setPageForCount();
status.setNewPayments(PageHelper.getTotalCount(paymentService.search(transfers)));
}
// Count the new references since the last login
if (permissionService.hasPermission(isOperator ? OperatorPermission.REFERENCES_VIEW : MemberPermission.REFERENCES_VIEW)) {
final ReferenceQuery references = new ReferenceQuery();
references.setNature(Reference.Nature.GENERAL);
references.setTo(member);
if (lastLogin != null) {
references.setPeriod(Period.begginingAt(lastLogin).useTime());
}
references.setPageForCount();
status.setNewReferences(PageHelper.getTotalCount(referenceService.search(references)));
}
// Count the open invoices
if (permissionService.hasPermission(isOperator ? OperatorPermission.INVOICES_VIEW : MemberPermission.INVOICES_VIEW)) {
final InvoiceQuery invoices = new InvoiceQuery();
invoices.setOwner(member);
invoices.setDirection(InvoiceQuery.Direction.INCOMING);
invoices.setStatus(Invoice.Status.OPEN);
invoices.setPageForCount();
status.setOpenInvoices(PageHelper.getTotalCount(invoiceService.search(invoices)));
}
// Count the open loans
if (permissionService.hasPermission(isOperator ? OperatorPermission.LOANS_VIEW : MemberPermission.LOANS_VIEW)) {
final LoanQuery loans = new LoanQuery();
loans.setMember(member);
loans.setStatus(Loan.Status.OPEN);
loans.setPageForCount();
status.setOpenLoans(PageHelper.getTotalCount(loanService.search(loans)));
}
// Count the payments awaiting feedback
if (!(isOperator && !permissionService.hasPermission(OperatorPermission.REFERENCES_MANAGE_MEMBER_TRANSACTION_FEEDBACKS))) {
final PaymentsAwaitingFeedbackQuery awaitingFeedback = new PaymentsAwaitingFeedbackQuery();
awaitingFeedback.setPageForCount();
awaitingFeedback.setExpired(false);
awaitingFeedback.setMember(member);
status.setPaymentsAwaitingFeedback(PageHelper.getTotalCount(referenceService.searchPaymentsAwaitingFeedback(awaitingFeedback)));
}
// Count the payment awaiting authorization
if (permissionService.hasPermission(isOperator ? OperatorPermission.PAYMENTS_AUTHORIZE : MemberPermission.PAYMENTS_AUTHORIZE)) {
final TransfersAwaitingAuthorizationQuery awaitingAuthorization = new TransfersAwaitingAuthorizationQuery();
awaitingAuthorization.setPageForCount();
status.setPaymentsToAuthorize(PageHelper.getTotalCount(transferAuthorizationService.searchTransfersAwaitingAuthorization(awaitingAuthorization)));
}
// Check if there are pending commission contracts
if (member.getBroker() != null && !isOperator) {
BrokerCommissionContractQuery contractsQuery = new BrokerCommissionContractQuery();
contractsQuery.setPageForCount();
contractsQuery.setMember(member);
contractsQuery.setStatus(BrokerCommissionContract.Status.PENDING);
status.setHasPendingCommissionContracts(PageHelper.hasResults(commissionService.searchBrokerCommissionContracts(contractsQuery)));
}
return status;
}
@Override
public boolean hasValueForField(final Member member, final MemberCustomField field) {
return elementDao.hasValueForField(member, field);
}
@Override
public IteratorList<Member> iterateByGroup(final boolean ordered, final MemberGroup... groups) {
return new IteratorListImpl<Member>(elementDao.iterateMembers(ordered, groups));
}
@Override
public IteratorList<Member> iterateByGroup(final MemberGroup... groups) {
return iterateByGroup(false, groups);
}
@Override
public Member loadByIdOrPrincipal(final Long id, final String principalType, final String principal) {
Member member;
if (id != null) {
// By id
try {
member = (Member) elementService.load(id);
} catch (ClassCastException e) {
throw new EntityNotFoundException(Member.class);
}
} else if (StringUtils.isNotEmpty(principal)) {
// By principal
member = memberHelper.loadByPrincipal(principalType, principal);
} else {
// No data
return null;
}
Member restrictedMember = WebServiceContext.getMember();
if (restrictedMember != null && !permissionService.relatesTo(member)) {
throw new EntityNotFoundException(Member.class);
}
return member;
}
public void setAccessServiceLocal(final AccessServiceLocal accessService) {
this.accessService = accessService;
}
public void setAccountServiceLocal(final AccountServiceLocal accountService) {
this.accountService = accountService;
}
public void setAdServiceLocal(final AdServiceLocal adService) {
this.adService = adService;
}
public void setBrokeringServiceLocal(final BrokeringServiceLocal brokeringService) {
this.brokeringService = brokeringService;
}
public void setChannelServiceLocal(final ChannelServiceLocal channelService) {
this.channelService = channelService;
}
public void setCommissionServiceLocal(final CommissionServiceLocal commissionService) {
this.commissionService = commissionService;
}
public void setCustomFieldHelper(final CustomFieldHelper customFieldHelper) {
this.customFieldHelper = customFieldHelper;
}
public void setCustomObjectHandler(final CustomObjectHandler customObjectHandler) {
this.customObjectHandler = customObjectHandler;
}
public void setElementDao(final ElementDAO elementDao) {
this.elementDao = elementDao;
}
public void setElementServiceLocal(final ElementServiceLocal elementService) {
this.elementService = elementService;
}
public void setFetchServiceLocal(final FetchServiceLocal fetchService) {
this.fetchService = fetchService;
}
public void setGroupServiceLocal(final GroupServiceLocal groupService) {
this.groupService = groupService;
}
public void setInvoiceServiceLocal(final InvoiceServiceLocal invoiceService) {
this.invoiceService = invoiceService;
}
public void setLoanServiceLocal(final LoanServiceLocal loanService) {
this.loanService = loanService;
}
public void setLockHandlerFactory(final LockHandlerFactory lockHandlerFactory) {
this.lockHandlerFactory = lockHandlerFactory;
}
public void setMemberCustomFieldService(final MemberCustomFieldService memberCustomFieldService) {
this.memberCustomFieldService = memberCustomFieldService;
}
public void setMemberHelper(final MemberHelper memberHelper) {
this.memberHelper = memberHelper;
}
public void setMemberSmsStatusDao(final MemberSmsStatusDAO memberSmsStatusDao) {
this.memberSmsStatusDao = memberSmsStatusDao;
}
public void setMessageServiceLocal(final MessageServiceLocal messageService) {
this.messageService = messageService;
}
public void setPaymentServiceLocal(final PaymentServiceLocal paymentService) {
this.paymentService = paymentService;
}
public void setPermissionServiceLocal(final PermissionServiceLocal permissionService) {
this.permissionService = permissionService;
}
public void setPreferenceServiceLocal(final PreferenceServiceLocal preferenceService) {
this.preferenceService = preferenceService;
}
public void setRateServiceLocal(final RateServiceLocal rateService) {
this.rateService = rateService;
}
public void setReferenceServiceLocal(final ReferenceServiceLocal referenceService) {
this.referenceService = referenceService;
}
public void setTransactionHelper(final TransactionHelper transactionHelper) {
this.transactionHelper = transactionHelper;
}
public void setTransferAuthorizationServiceLocal(final TransferAuthorizationServiceLocal transferAuthorizationService) {
this.transferAuthorizationService = transferAuthorizationService;
}
public void setTransferTypeServiceLocal(final TransferTypeServiceLocal transferTypeService) {
this.transferTypeService = transferTypeService;
}
@Override
public MemberSmsStatus updateSmsStatus(final MemberSmsStatus memberSmsStatus) {
return memberSmsStatusDao.update(memberSmsStatus);
}
private boolean canViewAccountInformation(final Element element, MemberAccount memberAccount) {
memberAccount = fetchService.fetch(memberAccount, Account.Relationships.TYPE, RelationshipHelper.nested(MemberAccount.Relationships.MEMBER, Member.Relationships.BROKER));
if (element instanceof Administrator) {
return true;
} else if (element instanceof Operator) {
final Operator operator = fetchService.fetch((Operator) element, RelationshipHelper.nested(Operator.Relationships.MEMBER, Element.Relationships.GROUP), RelationshipHelper.nested(Element.Relationships.GROUP, OperatorGroup.Relationships.CAN_VIEW_INFORMATION_OF));
if (memberAccount.getMember().equals(operator.getMember())) {
if (operator.getOperatorGroup().getCanViewInformationOf().contains(memberAccount.getType())) {
return true;
}
} else {
final MemberGroup operatorsMemberGroup = fetchService.fetch(operator.getMember().getMemberGroup(), MemberGroup.Relationships.CAN_VIEW_INFORMATION_OF);
if (operatorsMemberGroup.getCanViewInformationOf().contains(memberAccount.getType())) {
return true;
}
}
} else if (element instanceof Member) {
final Member member = fetchService.fetch((Member) element, RelationshipHelper.nested(Element.Relationships.GROUP, MemberGroup.Relationships.CAN_VIEW_INFORMATION_OF), RelationshipHelper.nested(Element.Relationships.GROUP, BrokerGroup.Relationships.BROKER_CAN_VIEW_INFORMATION_OF));
if (member.getGroup() instanceof BrokerGroup) {
if (member.equals(memberAccount.getMember().getBroker())) {
final BrokerGroup brokerGroup = (BrokerGroup) member.getMemberGroup();
if (brokerGroup.getBrokerCanViewInformationOf().contains(memberAccount.getType())) {
return true;
} else {
return false;
}
}
}
final MemberGroup memberGroup = member.getMemberGroup();
if (memberGroup.getCanViewInformationOf().contains(memberAccount.getType())) {
return true;
}
}
return false;
}
@SuppressWarnings("unchecked")
private ActivitiesVO doGetActivities(final Member member) {
final ActivitiesVO vo = new ActivitiesVO();
// Check if account information will be retrieved
boolean showAccountInformation;
boolean showAdsInformation = adService.visibleGroupsForAds().contains(member.getGroup());
boolean showNonActiveAdsInformation = false;
final Element loggedElement = LoggedUser.element();
if (permissionService.manages(member)) {
// A managed member
showAccountInformation = permissionService.permission(member)
.admin(AdminMemberPermission.REPORTS_SHOW_ACCOUNT_INFORMATION)
.broker(BrokerPermission.ACCOUNTS_INFORMATION)
.member()
.operator(OperatorPermission.ACCOUNT_ACCOUNT_INFORMATION)
.hasPermission();
showNonActiveAdsInformation = showAdsInformation;
} else {
// Another related member
showAccountInformation = permissionService.permission()
.member(MemberPermission.REPORTS_SHOW_ACCOUNT_INFORMATION)
.operator(MemberPermission.REPORTS_SHOW_ACCOUNT_INFORMATION)
.hasPermission();
}
boolean showReferencesInformation = permissionService.permission()
.admin(AdminMemberPermission.REFERENCES_VIEW)
.member(MemberPermission.REFERENCES_VIEW)
.operator(OperatorPermission.REFERENCES_VIEW)
.hasPermission();
boolean showInvoicesInformation = showAccountInformation && permissionService.permission()
.admin(AdminMemberPermission.INVOICES_VIEW)
.member(MemberPermission.INVOICES_VIEW)
.operator(OperatorPermission.INVOICES_VIEW)
.hasPermission();
vo.setShowAccountInformation(showAccountInformation);
vo.setShowInvoicesInformation(showInvoicesInformation);
vo.setShowReferencesInformation(showReferencesInformation);
vo.setShowAdsInformation(showAdsInformation);
vo.setShowNonActiveAdsInformation(showNonActiveAdsInformation);
// Since active
vo.setSinceActive(member.getActivationDate());
// Number of brokered members
boolean isBroker = member.getGroup().getNature() == Nature.BROKER;
if (isBroker) {
final BrokeringQuery query = new BrokeringQuery();
query.setBroker(member);
query.setStatus(BrokeringQuery.Status.ACTIVE);
query.setPageForCount();
vo.setNumberBrokeredMembers(PageHelper.getTotalCount(brokeringService.search(query)));
}
// References
if (showReferencesInformation) {
vo.setReceivedReferencesByLevel(referenceService.countReferencesByLevel(Reference.Nature.GENERAL, member, true));
vo.setGivenReferencesByLevel(referenceService.countReferencesByLevel(Reference.Nature.GENERAL, member, false));
}
// Ads
if (vo.isShowAdsInformation()) {
vo.setAdsByStatus(adService.getNumberOfAds(null, member));
}
final List<MemberAccount> accounts = (List<MemberAccount>) accountService.getAccounts(member);
// Get invoice information
if (showInvoicesInformation) {
// Incoming invoices
final InvoiceSummaryDTO incomingInvoicesDTO = new InvoiceSummaryDTO();
incomingInvoicesDTO.setOwner(member);
incomingInvoicesDTO.setDirection(InvoiceQuery.Direction.INCOMING);
incomingInvoicesDTO.setStatus(Invoice.Status.OPEN);
vo.setIncomingInvoices(invoiceService.getSummary(incomingInvoicesDTO));
// Outgoing invoices
final InvoiceSummaryDTO summaryDTO = new InvoiceSummaryDTO();
summaryDTO.setOwner(member);
summaryDTO.setDirection(InvoiceQuery.Direction.OUTGOING);
summaryDTO.setStatus(Invoice.Status.OPEN);
vo.setOutgoingInvoices(invoiceService.getSummary(summaryDTO));
}
// 30 days ago
final Calendar days30 = DateHelper.truncate(Calendar.getInstance());
days30.add(Calendar.DATE, -30);
// Account activities; as rate info is NOT subject to permissions, always do the loop
for (final MemberAccount account : accounts) {
boolean hasRateInfo = false;
final GetTransactionsDTO allTime = new GetTransactionsDTO(account);
// final GetTransactionsDTO last30Days = new GetTransactionsDTO(account, Period.begginingAt(days30));
// Build an account activities VO
final AccountActivitiesVO activities = new AccountActivitiesVO();
// Get the account status
AccountStatus accountStatus = accountService.getRatedStatus(account, null);
activities.setAccountStatus(accountStatus);
// as AccountStatus contains rate info, no need to get it separately
hasRateInfo = rateService.isAnyRateEnabled(account, null);
activities.setHasRateInfo(hasRateInfo);
// get the conversion result
if (hasRateInfo) {
// get the relevant transfer type for conversions
final Collection<TransferType> currencyConversionTTs = transferTypeService.getConversionTTs(account.getType().getCurrency());
final Collection<TransferType> accountConversionTTs = transferTypeService.getConversionTTs(account.getType());
TransferType conversionTT = null;
// there must be only 1 TT available on the account. if more than one, we don't know which to choose so show nothing.
if (accountConversionTTs.size() == 1) {
final Object[] ttArray = accountConversionTTs.toArray();
conversionTT = (TransferType) ttArray[0];
} else if (accountConversionTTs.size() == 0 && currencyConversionTTs.size() == 1) {
// OR in case there is none on the account, we will take the only one available on the currency.
final Object[] ttArray = currencyConversionTTs.toArray();
conversionTT = (TransferType) ttArray[0];
}
// if no balance or no TT, there's nothing to convert.
final BigDecimal balance = accountStatus.getBalance();
if (balance.compareTo(BigDecimal.ZERO) > 0 && conversionTT != null) {
final ConversionSimulationDTO dto = new ConversionSimulationDTO();
dto.setTransferType(conversionTT);
dto.setAccount(account);
dto.setAmount(balance);
dto.setUseActualRates(true);
dto.setDate(Calendar.getInstance());
final TransactionFeePreviewForRatesDTO result = paymentService.simulateConversion(dto);
activities.setTotalFeePercentage(result.getRatesAsFeePercentage());
}
}
// rest of the activities info is subject to permissions
if (showAccountInformation) {
// Check if user has permission to view information of that account
if (account.getMember().equals(loggedElement) || canViewAccountInformation(loggedElement, account)) {
activities.setShowAccountInfo(true);
GetTransactionsDTO txAllTime = new GetTransactionsDTO(account);
txAllTime.setRootOnly(true);
GetTransactionsDTO tx30Days = new GetTransactionsDTO(account, Period.begginingAt(days30));
tx30Days.setRootOnly(true);
activities.setCreditsAllTime(accountService.getCredits(txAllTime));
activities.setDebitsAllTime(accountService.getDebits(txAllTime));
activities.setCreditsLast30Days(accountService.getCredits(tx30Days));
activities.setDebitsLast30Days(accountService.getDebits(tx30Days));
// Get the broker commission
if (isBroker) {
activities.setBrokerCommission(accountService.getBrokerCommissions(allTime));
}
// Calculate the total of remaining loans
final LoanQuery loanQuery = new LoanQuery();
loanQuery.setMember(member);
loanQuery.setStatus(Loan.Status.OPEN);
loanQuery.setAccountType(account.getType());
int remainingLoans = 0;
BigDecimal remainingLoanAmount = BigDecimal.ZERO;
final List<Loan> loans = loanService.search(loanQuery);
for (final Loan loan : loans) {
remainingLoans++;
remainingLoanAmount = remainingLoanAmount.add(loan.getRemainingAmount());
}
activities.setRemainingLoans(new TransactionSummaryVO(remainingLoans, remainingLoanAmount));
}
}
// Store this one, but only if there is info
if (activities.isShowAccountInfo() || activities.isHasRateInfo()) {
vo.addAccountActivities(account.getType().getName(), activities);
}
}
return vo;
}
/**
*
* @param member
* @return true if the member has set at least one notification by sms
*/
private boolean hasNotificationsBySms(final Member member) {
Collection<NotificationPreference> preferences = preferenceService.load(member);
if (CollectionUtils.isEmpty(preferences)) {
return false;
}
for (NotificationPreference preference : preferences) {
if (preference.isSms()) {
return true;
}
}
return false;
}
private MemberSmsStatus performGetSmsStatus(Member member) {
// First, acquire a pessimistic lock
LockHandler lockHandler = lockHandlerFactory.getLockHandler();
lockHandler.lockSmsStatus(member);
// Try to load the sms status. If none found, a new one will be returned
member = fetchService.fetch(member, Element.Relationships.GROUP);
final Calendar today = Calendar.getInstance();
final Period currentMonth = TimePeriod.ONE_MONTH.currentPeriod(today);
MemberSmsStatus status;
try {
// Try loading the member status
status = memberSmsStatusDao.load(member);
// If got to this line, the status exists
boolean changed = false;
if (today.after(status.getFreeSmsExpiration())) {
// The free sms period has expired. Reset.
status.setFreeSmsSent(0);
status.setFreeSmsExpiration(currentMonth.getEnd());
changed = true;
}
final Calendar paidSmsExpiration = status.getPaidSmsExpiration();
if (paidSmsExpiration != null && today.after(paidSmsExpiration)) {
// The paid sms messages have expired. Reset.
status.setPaidSmsLeft(0);
status.setPaidSmsExpiration(null);
changed = true;
}
if (changed) {
// Update the record if it has changed
status = memberSmsStatusDao.update(status);
}
} catch (final EntityNotFoundException e) {
// The status does not exist. Create a new one.
MemberGroup group = member.getMemberGroup();
status = new MemberSmsStatus();
status.setMember(member);
status.setFreeSmsExpiration(currentMonth.getEnd());
status.setAllowChargingSms(group.isDefaultAllowChargingSms());
status.setAcceptFreeMailing(group.isDefaultAcceptFreeMailing());
status.setAcceptPaidMailing(group.isDefaultAcceptPaidMailing());
ensureAllowChargingSms(status, hasNotificationsBySms(member));
status = memberSmsStatusDao.insert(status);
} finally {
lockHandler.release();
}
return status;
}
}