I have been successfully using the Salesforce REST API for a while, but have encountered some functionality that is only available via the SOAP API. One such function is the convertLead() function. I believe that I should be able to use the Salesforce Access Token (a/k/a Session ID) to call the SOAP API but I don't see a good library to use for this function as well as a few others that I'm interested in.
Salesforce provides a sample SOAP request here: https://developer.salesforce.com/page/Enterprise_Convert_Lead
I have attempted to write some the convertLead() function but running into some errors, and since I'm new to SOAP as well as the lxml library, I'm not sure how to diagnose.
Here is the class that I've written to generate the XML:
from lxml import etree
class SalesforceLeadConverter(object):
def __init__(self, session_id, lead_id, **kwargs):
self.session_id = session_id
self.lead_id = lead_id
def build_xml(self):
root = etree.Element(
"{soapenv}Envelope",
soapenv='<a rel="nofollow" class="external free" href="http://schemas.xmlsoap.org/soap/envelope/">http://schemas.xmlsoap.org/soap/envelope/</a>',
urn="urn:enterprise.soap.sforce.com"
)
soapenv = etree.SubElement(root, "{soapenv}Header")
urn = etree.SubElement(soapenv, "{urn}SessionHeader")
session_id = etree.SubElement(urn, "{urn}sessionId").text=self.session_id
soapenv2 = etree.SubElement(root, "{soapenv}Body")
urn2 = etree.SubElement(soapenv2, "{urn}convertLead")
lead_converts = etree.SubElement(urn2, "{urn}leadConverts")
lead_id = etree.SubElement(lead_converts, "{urn}leadId").text=self.lead_id
print(etree.tostring(root, pretty_print=True))
return root
This is designed so that I can pass in a value for lead_id and session_id (access token) and generate some XML, like so:
>>> from integrations.salesforce.soap import SalesforceLeadConverter
>>> slc = SalesforceLeadConverter(session_id="1q2w3e4r...", lead_id="00Qj000000PMV3h")
>>> xml = slc.build_xml()
Which generates the following output:
<ns0:Envelope xmlns:ns0="soapenv" urn="urn:enterprise.soap.sforce.com">
<ns0:Header>
<ns1:SessionHeader xmlns:ns1="urn">
<ns1:sessionId>1q2w3e4r...</ns1:sessionId>
</ns1:SessionHeader>
</ns0:Header>
<ns0:Body>
<ns2:convertLead xmlns:ns2="urn">
<ns2:leadConverts>
<ns2:leadId>00Qj000000PMV3h</ns2:leadId>
</ns2:leadConverts>
</ns2:convertLead>
</ns0:Body>
</ns0:Envelope>
Finally, I pass the XML data to the Salesforce SOAP API endpoint using requests; I set 'SOAPAction' to any value (in this case 'x') because of another thread I found that recommended setting this to some random text value.
>>> headers = {'Content-Type':'application/xml', 'SOAPAction':'x'}
>>> requests.post('https://na1.salesforce.com/services/Soap/c/10.0', data=xml, headers=headers)
I'm getting the following error:
TypeError: data must be a memoryview, buffer or byte string
Full error output is here: https://gist.github.com/joefusaro/f3297c253beb6bba93e075d8b8da9822