/**
* =============================================================================
*
* ORCID (R) Open Source
* http://orcid.org
*
* Copyright (c) 2012-2014 ORCID, Inc.
* Licensed under an MIT-Style License (MIT)
* http://orcid.org/open-source-license
*
* This copyright and license information (including a link to the full license)
* shall be included in its entirety in all copies or substantial portion of
* the software.
*
* =============================================================================
*/
package org.orcid.core.manager.impl;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.orcid.core.manager.EmailManager;
import org.orcid.core.manager.SalesForceManager;
import org.orcid.core.manager.SourceManager;
import org.orcid.core.manager.read_only.impl.ManagerReadOnlyBaseImpl;
import org.orcid.core.salesforce.cache.MemberDetailsCacheKey;
import org.orcid.core.salesforce.dao.SalesForceDao;
import org.orcid.core.salesforce.model.Consortium;
import org.orcid.core.salesforce.model.Contact;
import org.orcid.core.salesforce.model.ContactRole;
import org.orcid.core.salesforce.model.ContactRoleType;
import org.orcid.core.salesforce.model.Member;
import org.orcid.core.salesforce.model.MemberDetails;
import org.orcid.core.salesforce.model.Opportunity;
import org.orcid.core.salesforce.model.SlugUtils;
import org.orcid.core.salesforce.model.SubMember;
import org.orcid.jaxb.model.record_v2.Email;
import org.orcid.persistence.dao.SalesForceConnectionDao;
import org.orcid.persistence.jpa.entities.SalesForceConnectionEntity;
import org.orcid.utils.DateUtils;
import org.orcid.utils.ReleaseNameUtils;
import net.sf.ehcache.constructs.blocking.SelfPopulatingCache;
/**
*
* @author Will Simpson
*
*/
public class SalesForceManagerImpl extends ManagerReadOnlyBaseImpl implements SalesForceManager {
private static final String OPPORTUNITY_CLOSED_LOST = "Closed Lost";
private static final String OPPORTUNITY_TYPE = "New";
private static final String OPPORTUNITY_INITIAL_STAGE_NAME = "Invoice Paid";
private static final String OPPORTUNITY_NAME = "Opportunity from registry";
@Resource(name = "salesForceMembersListCache")
private SelfPopulatingCache salesForceMembersListCache;
@Resource(name = "salesForceMemberDetailsCache")
private SelfPopulatingCache salesForceMemberDetailsCache;
@Resource(name = "salesForceConsortiaListCache")
private SelfPopulatingCache salesForceConsortiaListCache;
@Resource(name = "salesForceConsortiumCache")
private SelfPopulatingCache salesForceConsortiumCache;
@Resource(name = "salesForceContactsCache")
private SelfPopulatingCache salesForceContactsCache;
@Resource
private SalesForceDao salesForceDao;
@Resource
private SalesForceConnectionDao salesForceConnectionDao;
@Resource
private EmailManager emailManager;
@Resource
private SourceManager sourceManager;
private String releaseName = ReleaseNameUtils.getReleaseName();
private String premiumConsortiumMemberTypeId;
private String consortiumMemberRecordTypeId;
@SuppressWarnings("unchecked")
@Override
public List<Member> retrieveMembers() {
return (List<Member>) salesForceMembersListCache.get(releaseName).getObjectValue();
}
@SuppressWarnings("unchecked")
@Override
public List<Member> retrieveConsortia() {
return (List<Member>) salesForceConsortiaListCache.get(releaseName).getObjectValue();
}
@Override
public Consortium retrieveConsortium(String consortiumId) {
return (Consortium) salesForceConsortiumCache.get(consortiumId).getObjectValue();
}
@Override
public MemberDetails retrieveDetailsBySlug(String memberSlug) {
String memberId = SlugUtils.extractIdFromSlug(memberSlug);
return retrieveDetails(memberId);
}
@Override
public MemberDetails retrieveDetails(String memberId) {
List<Member> members = retrieveMembers();
Optional<Member> match = members.stream().filter(e -> {
String id = e.getId();
String legacyId = id.substring(0, 15);
return memberId.equalsIgnoreCase(id) || memberId.equals(legacyId);
}).findFirst();
if (match.isPresent()) {
Member salesForceMember = match.get();
MemberDetails details = (MemberDetails) salesForceMemberDetailsCache
.get(new MemberDetailsCacheKey(memberId, salesForceMember.getConsortiumLeadId(), releaseName)).getObjectValue();
details.setMember(salesForceMember);
details.setSubMembers(findSubMembers(memberId));
return details;
}
throw new IllegalArgumentException("No member details found for " + memberId);
}
@SuppressWarnings("unchecked")
@Override
public List<Contact> retrieveContactsByAccountId(String accountId) {
return (List<Contact>) salesForceContactsCache.get(accountId).getObjectValue();
}
@Override
public void addOrcidsToContacts(List<Contact> contacts) {
List<String> emails = contacts.stream().map(c -> c.getEmail()).collect(Collectors.toList());
Map<String, String> emailsToOrcids = emailManager.findIdsByEmails(emails);
contacts.stream().forEach(c -> {
c.setOrcid(emailsToOrcids.get(c.getEmail()));
});
}
@Override
public void enableAccess(String accountId, List<Contact> contactsList) {
contactsList.forEach(c -> {
String orcid = c.getOrcid();
if (orcid == null) {
return;
}
SalesForceConnectionEntity connection = salesForceConnectionDao.findByOrcidAndAccountId(orcid, accountId);
if (connection == null) {
connection = new SalesForceConnectionEntity();
connection.setOrcid(orcid);
connection.setSalesForceAccountId(accountId);
connection.setEmail(c.getEmail());
salesForceConnectionDao.persist(connection);
}
});
}
@Override
public String retriveAccountIdByOrcid(String orcid) {
SalesForceConnectionEntity connection = salesForceConnectionDao.findByOrcid(orcid);
return connection != null ? connection.getSalesForceAccountId() : null;
}
@Override
public String createMember(Member member) {
Opportunity opportunity = new Opportunity();
Optional<Member> firstExistingMember = salesForceDao.retrieveMembersByWebsite(member.getWebsiteUrl().toString()).stream().findFirst();
String accountId = null;
if (firstExistingMember.isPresent()) {
accountId = firstExistingMember.get().getId();
} else {
accountId = salesForceDao.createMember(member);
}
opportunity.setTargetAccountId(accountId);
opportunity.setConsortiumLeadId(retriveAccountIdByOrcid(sourceManager.retrieveRealUserOrcid()));
opportunity.setType(OPPORTUNITY_TYPE);
opportunity.setMemberType(getPremiumConsortiumMemberTypeId());
opportunity.setStageName(OPPORTUNITY_INITIAL_STAGE_NAME);
opportunity.setCloseDate(calculateCloseDate());
opportunity.setMembershipStartDate(calculateMembershipStartDate());
opportunity.setMembershipEndDate(calculateMembershipEndDate());
opportunity.setRecordTypeId(getConsortiumMemberRecordTypeId());
opportunity.setName(OPPORTUNITY_NAME);
createOpportunity(opportunity);
evictAll();
return accountId;
}
private String calculateCloseDate() {
return DateUtils.convertToXMLGregorianCalendarNoTimeZoneNoMillis(new Date()).toXMLFormat();
}
private String calculateMembershipStartDate() {
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
return String.format("%s-01-01", year);
}
private String calculateMembershipEndDate() {
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
return String.format("%s-12-31", year);
}
private String getPremiumConsortiumMemberTypeId() {
if (premiumConsortiumMemberTypeId == null) {
premiumConsortiumMemberTypeId = salesForceDao.retrievePremiumConsortiumMemberTypeId();
}
return premiumConsortiumMemberTypeId;
}
private String getConsortiumMemberRecordTypeId() {
if (consortiumMemberRecordTypeId == null) {
consortiumMemberRecordTypeId = salesForceDao.retrieveConsortiumMemberRecordTypeId();
}
return consortiumMemberRecordTypeId;
}
@Override
public void updateMember(Member member) {
salesForceDao.updateMember(member);
salesForceMembersListCache.removeAll();
}
@Override
public String createOpportunity(Opportunity opportunity) {
String accountId = salesForceDao.createOpportunity(opportunity);
salesForceMembersListCache.removeAll();
return accountId;
}
@Override
public void flagOpportunityAsClosed(String opportunityId) {
String accountId = retriveAccountIdByOrcid(sourceManager.retrieveRealUserOrcid());
MemberDetails memberDetails = retrieveDetails(accountId);
boolean authorized = memberDetails.getSubMembers().stream().anyMatch(s -> opportunityId.equals(s.getOpportunity().getId()));
if (authorized) {
Opportunity opportunity = new Opportunity();
opportunity.setId(opportunityId);
opportunity.setStageName(OPPORTUNITY_CLOSED_LOST);
salesForceDao.updateOpportunity(opportunity);
}
// Need to make more granular!
evictAll();
}
@Override
public void createContact(Contact contact) {
String accountId = retriveAccountIdByOrcid(sourceManager.retrieveRealUserOrcid());
contact.setAccountId(accountId);
if (StringUtils.isBlank(contact.getEmail())) {
String contactOrcid = contact.getOrcid();
Email primaryEmail = emailManager.getEmails(contactOrcid, getLastModified(contactOrcid)).getEmails().stream().filter(e -> e.isPrimary()).findFirst().get();
contact.setEmail(primaryEmail.getEmail());
}
List<Contact> existingContacts = salesForceDao.retrieveAllContactsByAccountId(accountId);
Optional<Contact> existingContact = existingContacts.stream().filter(c -> contact.getOrcid().equals(c.getOrcid())).findFirst();
String contactId = existingContact.isPresent() ? existingContact.get().getId() : salesForceDao.createContact(contact);
ContactRole contactRole = new ContactRole();
contactRole.setContactId(contactId);
contactRole.setRoleType(ContactRoleType.OTHER_CONTACT);
contactRole.setAccountId(contact.getAccountId());
salesForceDao.createContactRole(contactRole);
// Need to make more granular!
evictAll();
}
@Override
public void removeContact(Contact contact) {
String accountId = retriveAccountIdByOrcid(sourceManager.retrieveRealUserOrcid());
List<ContactRole> contactRoles = salesForceDao.retrieveContactRolesByContactIdAndAccountId(contact.getId(), accountId);
contactRoles.forEach(r -> salesForceDao.removeContactRole(r.getId()));
// Need to make more granular!
evictAll();
}
@Override
public void removeContactRole(Contact contact) {
String accountId = retriveAccountIdByOrcid(sourceManager.retrieveRealUserOrcid());
List<ContactRole> contactRoles = salesForceDao.retrieveContactRolesByContactIdAndAccountId(contact.getId(), accountId);
contactRoles.stream().filter(r -> r.getId().equals(contact.getRole().getId())).findFirst().ifPresent(r -> salesForceDao.removeContactRole(r.getId()));
// Need to make more granular!
evictAll();
}
@Override
public void updateContact(Contact contact) {
String accountId = retriveAccountIdByOrcid(sourceManager.retrieveRealUserOrcid());
List<ContactRole> roles = salesForceDao.retrieveContactRolesByContactIdAndAccountId(contact.getId(), accountId);
salesForceDao.removeContactRole(contact.getRole().getId());
if (roles.stream().noneMatch(r -> contact.getRole().equals(r.getRoleType()))) {
ContactRole contactRole = new ContactRole();
contactRole.setAccountId(accountId);
contactRole.setContactId(contact.getId());
contactRole.setRoleType(contact.getRole().getRoleType());
String contactRoleId = salesForceDao.createContactRole(contactRole);
contact.getRole().setId(contactRoleId);
}
// Need to make more granular!
evictAll();
}
@Override
public void evictAll() {
salesForceMembersListCache.removeAll();
salesForceMemberDetailsCache.removeAll();
salesForceConsortiaListCache.removeAll();
salesForceConsortiumCache.removeAll();
salesForceContactsCache.removeAll();
premiumConsortiumMemberTypeId = null;
consortiumMemberRecordTypeId = null;
}
private List<SubMember> findSubMembers(String memberId) {
Consortium consortium = retrieveConsortium(memberId);
if (consortium != null) {
List<SubMember> subMembers = consortium.getOpportunities().stream().map(o -> {
SubMember subMember = new SubMember();
subMember.setOpportunity(o);
subMember.setSlug(SlugUtils.createSlug(o.getTargetAccountId(), o.getAccountName()));
return subMember;
}).collect(Collectors.toList());
return subMembers;
}
return Collections.emptyList();
}
}