Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,11 @@ python:
- '3.4'
- '3.5'

env:
- DJANGO_VERSION=1.4.3
- DJANGO_VERSION=1.8
- DJANGO_VERSION=1.10

install:
- pip install -r requirements.txt
- pip install -r requirements_test.txt
- pip install Django==$DJANGO_VERSION

script: nosetests --with-coverage
script: nosetests --with-coverage --nologcapture

after_success: coveralls

Expand Down
41 changes: 3 additions & 38 deletions membersuite_api_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,49 +95,14 @@ def construct_concierge_header(self, url):

return concierge_request_header

def query_orgs(self, parameters=None, since_when=None):
"""
Constructs request to MemberSuite to query organization objects
based on parameters provided.

parameters: A dictionary of key-value pairs (field name: value)
"""
concierge_request_header = self.construct_concierge_header(
url="http://membersuite.com/contracts/"
"IConciergeAPIService/ExecuteMSQL")

query = "SELECT Objects() FROM Organization "
if parameters:
query += "WHERE"
for key in parameters:
query += " %s = '%s' AND" % (key, parameters[key])
query = query[:-4]

if since_when:
query += " AND LastModifiedDate > '{since_when} 00:00:00'"\
.format(since_when=since_when.isoformat())
elif since_when:
query += "WHERE LastModifiedDate > '{since_when} 00:00:00'".format(
since_when=since_when.isoformat())

result = self.client.service.ExecuteMSQL(
_soapheaders=[concierge_request_header],
msqlStatement=query,
startRecord=0
)
if result["body"]["ExecuteMSQLResult"]["ResultValue"]["ObjectSearchResult"]["Objects"]:
return(result["body"]["ExecuteMSQLResult"]["ResultValue"]
["ObjectSearchResult"]["Objects"]["MemberSuiteObject"])
else:
return None

def runSQL(self, query, start_record=0):
def runSQL(self, query, start_record=0, limit_to=400):
concierge_request_header = self.construct_concierge_header(
url="http://membersuite.com/contracts/"
"IConciergeAPIService/ExecuteMSQL")
result = self.client.service.ExecuteMSQL(
_soapheaders=[concierge_request_header],
msqlStatement=query,
startRecord=start_record
startRecord=start_record,
maximumNumberOfRecordsToReturn=limit_to,
)
return result
Empty file.
49 changes: 49 additions & 0 deletions membersuite_api_client/memberships/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
class Membership(object):

def __init__(self, membership):
""" Create a Membership model from MemberSuite Member object
"""
self.id = membership["ID"]
self.owner = membership["Owner"]
self.membership_directory_opt_out = \
membership["MembershipDirectoryOptOut"]
self.receives_member_benefits = membership["ReceivesMemberBenefits"]
self.current_dues_amount = membership["CurrentDuesAmount"]
self.expiration_date = membership["ExpirationDate"]
self.type = membership["Type"]
self.product = membership["Product"]
self.last_modified_date = membership["LastModifiedDate"]

self.status = membership["Status"]
self.join_date = membership["JoinDate"]
self.termination_date = membership["TerminationDate"]
self.renewal_date = membership["RenewalDate"]


class MembershipProduct(object):

def __init__(self, membership_type):
""" Create a MembershipType model from MembershipDuesProduct object
"""
self.id = membership_type["ID"]
self.name = membership_type["Name"]

STATUSES = {
'6faf90e4-0069-cf2c-650f-0b3c15a7d3aa': 'Expired',
'6faf90e4-0069-cd19-6a43-0b3c15a7c287': 'New Member',
'6faf90e4-0069-c450-a9c8-0b3c6a781755': 'Pending',
'6faf90e4-0069-c7d5-2e88-0b3c15a7cf8a': 'Reinstated',
'6faf90e4-0069-c2ef-6d51-0b3c15a7cb7f': 'Renewed',
'6faf90e4-0069-cebb-b501-0b3c15a7d742': 'Terminated',
}

TYPES = {
'6faf90e4-006a-c1e7-1ac8-0b3c2f7cb3bc': 'Business',
'6faf90e4-006a-c2ae-40f5-0b3c5c99549d': 'International Institution',
'6faf90e4-006a-c242-d6ab-0b3c5c994f57': 'North American Institution',
'6faf90e4-006a-c6b0-10c0-0b3c2f7cc1c5': 'Other',
'6faf90e4-006a-c71f-2f32-0b3c2f7cbbee': 'Campus',
'6faf90e4-006a-c85d-2efa-0b3c2f7ca9cc': 'HEASC Membership',
'6faf90e4-006a-c9c7-5aa2-0b3bc8775e74': 'New Member',
'6faf90e4-006a-c904-255d-0b3bc8774c95': 'Regained Membership',
}
148 changes: 148 additions & 0 deletions membersuite_api_client/memberships/services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
"""
The service for connecting to MemberSuite for MembershipService

http://api.docs.membersuite.com/#References/Objects/Membership.htm

"""

from .models import Membership, MembershipProduct
from ..utils import convert_ms_object
from zeep.exceptions import TransportError


class MembershipService(object):

def __init__(self, client):
"""
Accepts a ConciergeClient to connect with MemberSuite
"""
self.client = client

def get_memberships_for_org(self, account_num):
"""
Retrieve all memberships associated with an organization
"""
if not self.client.session_id:
self.client.request_session()

query = "SELECT Objects() FROM Membership " \
"WHERE Owner = '%s'" % account_num
result = self.client.runSQL(query)
msql_result = result["body"]["ExecuteMSQLResult"]
obj_result = msql_result["ResultValue"]["ObjectSearchResult"]
if obj_result['Objects']:
objects = obj_result['Objects']['MemberSuiteObject']
if not msql_result["Errors"] and len(objects):
return self.package_memberships(objects)
return None

def get_all_memberships(self, since_when=None, results=None,
start_record=0, limit_to=200,
depth=1, max_depth=None):
"""
Retrieve all memberships updated since "since_when"

Loop over queries of size limit_to until either a non-full queryset
is returned, or max_depth is reached (used in tests). Then the
recursion collapses to return a single concatenated list.
"""
if not self.client.session_id:
self.client.request_session()

query = "SELECT Objects() FROM Membership"
if since_when:
query += " WHERE LastModifiedDate > '{since_when} 00:00:00'" \
" ORDER BY LocalID"\
.format(since_when=since_when.isoformat())
else:
query += " ORDER BY LocalID"

try:
result = self.client.runSQL(
query=query,
start_record=start_record,
limit_to=limit_to,
)

except TransportError:
# API Intermittently fails and kicks a 504,
# this is a way to retry if that happens.
result = self.get_all_memberships(
since_when=since_when,
results=results,
start_record=start_record,
limit_to=limit_to,
depth=depth,
max_depth=max_depth,
)

msql_result = result['body']["ExecuteMSQLResult"]
if (not msql_result['Errors'] and msql_result["ResultValue"]
["ObjectSearchResult"]["Objects"]):
new_results = self.package_memberships(msql_result
["ResultValue"]
["ObjectSearchResult"]
["Objects"]
["MemberSuiteObject"]
) + (results or [])

# Check if the queryset was completely full. If so, there may be
# More results we need to query
if len(new_results) >= limit_to and depth < max_depth:
new_results = self.get_all_memberships(
since_when=since_when,
results=new_results,
start_record=start_record + limit_to,
limit_to=limit_to,
depth=depth+1,
max_depth=max_depth
)
return new_results
else:
return results

def get_all_membership_products(self):
"""
Retrieves membership product objects
"""
if not self.client.session_id:
self.client.request_session()

query = "SELECT Objects() FROM MembershipDuesProduct"
result = self.client.runSQL(query)
msql_result = result['body']['ExecuteMSQLResult']
if not msql_result['Errors']:
return self.package_membership_products(msql_result)
else:
return None

def package_memberships(self, object_list):
"""
Loops through MS objects returned from queries to turn them into
Membership objects and pack them into a list for later use.
"""
membership_list = []
for obj in object_list:
if type(obj) != str:
sane_obj = convert_ms_object(
obj['Fields']['KeyValueOfstringanyType'])
membership = Membership(sane_obj)
membership_list.append(membership)

return membership_list

def package_membership_products(self, msql_result):
"""
Loops through MS objects returned from queries to turn them into
MembershipProduct objects and pack them into a list for later use.
"""
obj_result = msql_result['ResultValue']['ObjectSearchResult']
objects = obj_result['Objects']['MemberSuiteObject']
product_list = []
for obj in objects:
sane_obj = convert_ms_object(
obj['Fields']['KeyValueOfstringanyType']
)
product = MembershipProduct(sane_obj)
product_list.append(product)
return product_list
Empty file.
49 changes: 49 additions & 0 deletions membersuite_api_client/organizations/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
class Organization(object):

def __init__(self, org):
"""Create an Organization model from MemberSuite Organization object
"""
self.account_num = org["ID"]
self.membersuite_id = org["LocalID"]
self.org_name = org["Name"]
self.picklist_name = org["SortName"] or ''

address = org["Mailing_Address"]
if address:
self.street1 = address["Line1"] or ''
self.street2 = address["Line2"] or ''
self.city = address["City"] or ''
self.state = address["State"] or ''
self.country = address["Country"]
self.postal_code = address["PostalCode"] or ''
self.latitude = address["GeocodeLat"] or ''
self.longitude = address["GeocodeLong"] or ''

self.website = org["WebSite"] or ''
self.exclude_from_website = False
self.is_defunct = (org["Status"] == 'Defunct')

self.org_type = org["Type"]

self.stars_participant_status = (
'STARS participant' if org["STARSCharterParticipant__c"] else ''
)

self.primary_email = org['EmailAddress'] or ''


class OrganizationType(object):

def __init__(self, org_type):
"""Create an OrganizationType model
from MemberSuite OrganizationType object
"""
self.id = org_type["ID"]
self.Name = org_type["Name"]

STATUSES = {
'6faf90e4-01f3-c54c-f01a-0b3bc87640ab': 'Active',
'6faf90e4-01f3-c0f1-4593-0b3c3ca7ff6c': 'Deceased',
'6faf90e4-01f3-c7ad-174c-0b3c52b7f497': 'Defunct',
'6faf90e4-01f3-cd50-ffed-0b3c3ca7f4fd': 'Retired',
}
Loading