diff --git a/README.md b/README.md index 361e143..6330ad3 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,25 @@ lead = client.sync_lead( ) ``` +## Sync Multiple Leads + +This fucntion updates multiple lead records from Marketo. If a lead without a matching email isn't found in the database, a new one is created. The request returns a list of results detailing creation/update/failure for each lead. + +```python +result = client.sync_multiple_leads(leads = ( + ('user@gmail.com', ( + ('City', 'string', 'Toronto'), + ('Country', 'string', 'Canada'), + ('Title', 'string', 'Web Developer'), + ) + ), + ('another.user@gmail.com', ( + ('Phone', 'string', '5551234567'), + ) + ) +)) +``` + ## Request Campaign This function triggers a Marketo campaign request (typically used to activate a campaign after a user has filled out a form). This requires the numeric ID of both a campaign and the lead that is to be associated with the campaign. Returns True on success. @@ -111,4 +130,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/marketo/__init__.py b/marketo/__init__.py index 287da5e..9c42a62 100644 --- a/marketo/__init__.py +++ b/marketo/__init__.py @@ -7,7 +7,7 @@ import requests import auth -from marketo.wrapper import get_lead, get_lead_activity, request_campaign, sync_lead +from marketo.wrapper import get_lead, get_lead_activity, request_campaign, sync_lead, sync_multiple_leads class Client: @@ -108,3 +108,17 @@ def sync_lead(self, email=None, attributes=None): return sync_lead.unwrap(response) else: raise Exception(response.text) + + def sync_multiple_leads(self, leads=None, create_duplicates=False): + + if not leads or not isinstance(leads, tuple): + raise ValueError('Must supply leads as a non-empty tuple.') + + body = sync_multiple_leads.wrap(leads, create_duplicates) + + response = self.request(body) + + if response.status_code == 200: + return sync_multiple_leads.unwrap(response) + else: + raise Exception(response.text) diff --git a/marketo/wrapper/result_record.py b/marketo/wrapper/result_record.py new file mode 100644 index 0000000..3234fb4 --- /dev/null +++ b/marketo/wrapper/result_record.py @@ -0,0 +1,20 @@ + +class ResultRecord: + def __init__(self): + self.leadId = '' + self.status = '' + self.error = '' + + def __str__(self): + return "Lead %s - Result: %s (error: %s)" % (self.leadId, self.status, self.error) + + def __repr__(self): + return self.__str__() + +def unwrap(xml): + result = ResultRecord() + result.leadId = xml.find('leadId').text + result.status = xml.find('status').text + result.error = xml.find('error').text + + return result diff --git a/marketo/wrapper/sync_multiple_leads.py b/marketo/wrapper/sync_multiple_leads.py new file mode 100644 index 0000000..3a8b682 --- /dev/null +++ b/marketo/wrapper/sync_multiple_leads.py @@ -0,0 +1,33 @@ +import xml.etree.ElementTree as ET +import lead_record, sync_lead, result_record + +def wrap(leads=None, create_duplicates=False): + + ret = ( + '' + + '' + ) + + for lead in leads: + wrapped_lead = sync_lead.wrap(email=lead[0], attributes=lead[1]) + ret += wrapped_lead[wrapped_lead.index(''):wrapped_lead.index('' + + '' + ('false' if create_duplicates else 'true') + '' + + '' + ) + + return ret + +def unwrap(response): + root = ET.fromstring(response.text) + resultList = root.find('.//result') + + unwrappedList = [] + + for result in resultList.findall('.//syncStatus'): + unwrappedList.append(result_record.unwrap(result)) + + return unwrappedList