class SforceBaseClient(object): _sforce = None _sessionId = None _location = None _product = 'Python Toolkit' _version = (0, 1, 3) _objectNamespace = None _strictResultTyping = False _allowFieldTruncationHeader = None _assignmentRuleHeader = None _callOptions = None _assignmentRuleHeader = None _emailHeader = None _localeOptions = None _loginScopeHeader = None _mruHeader = None _packageVersionHeader = None _queryOptions = None _sessionHeader = None _userTerritoryDeleteHeader = None def __init__(self, wsdl=None, cacheDuration = 0, suds_client=None, **kwargs): ''' Connect to Salesforce 'wsdl' : Location of WSDL 'cacheDuration' : Duration of HTTP GET cache in seconds, or 0 for no cache 'proxy' : Dict of pair of 'protocol' and 'location' e.g. {'http': 'my.insecure.proxy.example.com:80'} 'username' : Username for HTTP auth when using a proxy ONLY 'password' : Password for HTTP auth when using a proxy ONLY ''' if suds_client is None: # Suds can only accept WSDL locations with a protocol prepended if '://' not in wsdl: # TODO windows users??? # check if file exists, else let bubble up to suds as is # definitely don't want to assume http or https if os.path.isfile(wsdl): wsdl = 'file://' + os.path.abspath(wsdl) if cacheDuration > 0: cache = FileCache() cache.setduration(seconds = cacheDuration) else: cache = None self._sforce = Client(wsdl, cache = cache) # Set HTTP headers headers = {'User-Agent': 'Salesforce/' + self._product + '/' + '.'.join(str(x) for x in self._version)} # This HTTP header will not work until Suds gunzips/inflates the content # 'Accept-Encoding': 'gzip, deflate' self._sforce.set_options(headers = headers) if kwargs.has_key('proxy'): # urllib2 cannot handle HTTPS proxies yet (see bottom of README) if kwargs['proxy'].has_key('https'): raise NotImplementedError('Connecting to a proxy over HTTPS not yet implemented due to a \ limitation in the underlying urllib2 proxy implementation. However, traffic from a proxy to \ Salesforce will use HTTPS.') self._sforce.set_options(proxy = kwargs['proxy']) if kwargs.has_key('username'): self._sforce.set_options(username = kwargs['username']) if kwargs.has_key('password'): self._sforce.set_options(password = kwargs['password']) else: self._sforce = suds_client def clone(self): return type(self)(suds_client=self._sforce.clone()) # Toolkit-specific methods def generateHeader(self, sObjectType): ''' Generate a SOAP header as defined in: http://www.salesforce.com/us/developer/docs/api/Content/soap_headers.htm ''' try: return self._sforce.factory.create(sObjectType) except: print 'There is not a SOAP header of type %s' % sObjectType def generateObject(self, sObjectType): ''' Generate a Salesforce object, such as a Lead or Contact ''' obj = self._sforce.factory.create('ens:sObject') obj.type = sObjectType return obj def _handleResultTyping(self, result): ''' If any of the following calls return a single result, and self._strictResultTyping is true, return the single result, rather than [(SaveResult) {...}]: convertLead() create() delete() emptyRecycleBin() invalidateSessions() merge() process() retrieve() undelete() update() upsert() describeSObjects() sendEmail() ''' if self._strictResultTyping == False and len(result) == 1: return result[0] else: return result def _marshallSObjects(self, sObjects, tag = 'sObjects'): ''' Marshall generic sObjects into a list of SAX elements This code is going away ASAP tag param is for nested objects (e.g. MergeRequest) where key: object must be in <key/>, not <sObjects/> ''' if not isinstance(sObjects, (tuple, list)): sObjects = (sObjects, ) if sObjects[0].type in ['LeadConvert', 'SingleEmailMessage', 'MassEmailMessage']: nsPrefix = 'tns:' else: nsPrefix = 'ens:' li = [] for obj in sObjects: el = Element(tag) el.set('xsi:type', nsPrefix + obj.type) for k, v in obj: if k == 'type': continue # This is here to avoid 'duplicate values' error when setting a field in fieldsToNull # Even a tag like <FieldName/> will trigger it if v == None: # not going to win any awards for variable-naming scheme here tmp = Element(k) tmp.set('xsi:nil', 'true') el.append(tmp) elif isinstance(v, (list, tuple)): for value in v: el.append(Element(k).setText(value)) elif isinstance(v, suds.sudsobject.Object): el.append(self._marshallSObjects(v, k)) else: el.append(Element(k).setText(v)) li.append(el) return li def _setEndpoint(self, location): ''' Set the endpoint after when Salesforce returns the URL after successful login() ''' # suds 0.3.7+ supports multiple wsdl services, but breaks setlocation :( # see https://fedorahosted.org/suds/ticket/261 try: self._sforce.set_options(location = location) except: self._sforce.wsdl.service.setlocation(location) self._location = location def _setHeaders(self, call = None): ''' Attach particular SOAP headers to the request depending on the method call made ''' # All calls, including utility calls, set the session header headers = {'SessionHeader': self._sessionHeader} if call in ('convertLead', 'create', 'merge', 'process', 'undelete', 'update', 'upsert'): if self._allowFieldTruncationHeader is not None: headers['AllowFieldTruncationHeader'] = self._allowFieldTruncationHeader if call in ('create', 'merge', 'update', 'upsert'): if self._assignmentRuleHeader is not None: headers['AssignmentRuleHeader'] = self._assignmentRuleHeader # CallOptions will only ever be set by the SforcePartnerClient if self._callOptions is not None: if call in ('create', 'merge', 'queryAll', 'query', 'queryMore', 'retrieve', 'search', 'update', 'upsert', 'convertLead', 'login', 'delete', 'describeGlobal', 'describeLayout', 'describeTabs', 'describeSObject', 'describeSObjects', 'getDeleted', 'getUpdated', 'process', 'undelete', 'getServerTimestamp', 'getUserInfo', 'setPassword', 'resetPassword'): headers['CallOptions'] = self._callOptions if call in ('create', 'delete', 'resetPassword', 'update', 'upsert'): if self._emailHeader is not None: headers['EmailHeader'] = self._emailHeader if call in ('describeSObject', 'describeSObjects'): if self._localeOptions is not None: headers['LocaleOptions'] = self._localeOptions if call == 'login': if self._loginScopeHeader is not None: headers['LoginScopeHeader'] = self._loginScopeHeader if call in ('create', 'merge', 'query', 'retrieve', 'update', 'upsert'): if self._mruHeader is not None: headers['MruHeader'] = self._mruHeader if call in ('convertLead', 'create', 'delete', 'describeGlobal', 'describeLayout', 'describeSObject', 'describeSObjects', 'describeTabs', 'merge', 'process', 'query', 'retrieve', 'search', 'undelete', 'update', 'upsert'): if self._packageVersionHeader is not None: headers['PackageVersionHeader'] = self._packageVersionHeader if call in ('query', 'queryAll', 'queryMore', 'retrieve'): if self._queryOptions is not None: headers['QueryOptions'] = self._queryOptions if call == 'delete': if self._userTerritoryDeleteHeader is not None: headers['UserTerritoryDeleteHeader'] = self._userTerritoryDeleteHeader self._sforce.set_options(soapheaders = headers) def setStrictResultTyping(self, strictResultTyping): ''' Set whether single results from any of the following calls return the result wrapped in a list, or simply the single result object: convertLead() create() delete() emptyRecycleBin() invalidateSessions() merge() process() retrieve() undelete() update() upsert() describeSObjects() sendEmail() ''' self._strictResultTyping = strictResultTyping def getSessionId(self): return self._sessionId def getLocation(self): return self._location def getConnection(self): return self._sforce def getLastRequest(self): return str(self._sforce.last_sent()) def getLastResponse(self): return str(self._sforce.last_received()) # Core calls def convertLead(self, leadConverts): ''' Converts a Lead into an Account, Contact, or (optionally) an Opportunity. ''' self._setHeaders('convertLead') return self._handleResultTyping(self._sforce.service.convertLead(leadConverts)) def create(self, sObjects): self._setHeaders('create') return self._handleResultTyping(self._sforce.service.create(sObjects)) def delete(self, ids): ''' Deletes one or more objects ''' self._setHeaders('delete') return self._handleResultTyping(self._sforce.service.delete(ids)) def emptyRecycleBin(self, ids): ''' Permanently deletes one or more objects ''' self._setHeaders('emptyRecycleBin') return self._handleResultTyping(self._sforce.service.emptyRecycleBin(ids)) def getDeleted(self, sObjectType, startDate, endDate): ''' Retrieves the list of individual objects that have been deleted within the given timespan for the specified object. ''' self._setHeaders('getDeleted') return self._sforce.service.getDeleted(sObjectType, startDate, endDate) def getUpdated(self, sObjectType, startDate, endDate): ''' Retrieves the list of individual objects that have been updated (added or changed) within the given timespan for the specified object. ''' self._setHeaders('getUpdated') return self._sforce.service.getUpdated(sObjectType, startDate, endDate) def invalidateSessions(self, sessionIds): ''' Invalidate a Salesforce session This should be used with extreme caution, for the following (undocumented) reason: All API connections for a given user share a single session ID This will call logout() WHICH LOGS OUT THAT USER FROM EVERY CONCURRENT SESSION return invalidateSessionsResult ''' self._setHeaders('invalidateSessions') return self._handleResultTyping(self._sforce.service.invalidateSessions(sessionIds)) def login(self, username, password, token): ''' Login to Salesforce.com and starts a client session. Unlike other toolkits, token is a separate parameter, because Salesforce doesn't explicitly tell you to append it when it gives you a login error. Folks that are new to the API may not know this. 'username' : Username 'password' : Password 'token' : Token return LoginResult ''' self._setHeaders('login') result = self._sforce.service.login(username, password + token) # set session header header = self.generateHeader('SessionHeader') header.sessionId = result['sessionId'] self.setSessionHeader(header) self._sessionId = result['sessionId'] # change URL to point from test.salesforce.com to something like cs2-api.salesforce.com self._setEndpoint(result['serverUrl']) # na0.salesforce.com (a.k.a. ssl.salesforce.com) requires ISO-8859-1 instead of UTF-8 if 'ssl.salesforce.com' in result['serverUrl'] or 'na0.salesforce.com' in result['serverUrl']: # currently, UTF-8 is hard-coded in Suds, can't implement this yet pass return result def logout(self): ''' Logout from Salesforce.com This should be used with extreme caution, for the following (undocumented) reason: All API connections for a given user share a single session ID Calling logout() LOGS OUT THAT USER FROM EVERY CONCURRENT SESSION return LogoutResult ''' self._setHeaders('logout') return self._sforce.service.logout() def merge(self, mergeRequests): self._setHeaders('merge') return self._handleResultTyping(self._sforce.service.merge(mergeRequests)) def process(self, processRequests): self._setHeaders('process') return self._handleResultTyping(self._sforce.service.process(processRequests)) def query(self, queryString): ''' Executes a query against the specified object and returns data that matches the specified criteria. ''' self._setHeaders('query') return self._sforce.service.query(queryString) def queryAll(self, queryString): ''' Retrieves data from specified objects, whether or not they have been deleted. ''' self._setHeaders('queryAll') return self._sforce.service.queryAll(queryString) def queryMore(self, queryLocator): ''' Retrieves the next batch of objects from a query. ''' self._setHeaders('queryMore') return self._sforce.service.queryMore(queryLocator) def retrieve(self, fieldList, sObjectType, ids): ''' Retrieves one or more objects based on the specified object IDs. ''' self._setHeaders('retrieve') return self._handleResultTyping(self._sforce.service.retrieve(fieldList, sObjectType, ids)) def search(self, searchString): ''' Executes a text search in your organization's data. ''' self._setHeaders('search') return self._sforce.service.search(searchString) def undelete(self, ids): ''' Undeletes one or more objects ''' self._setHeaders('undelete') return self._handleResultTyping(self._sforce.service.undelete(ids)) def update(self, sObjects): self._setHeaders('update') return self._handleResultTyping(self._sforce.service.update(sObjects)) def upsert(self, externalIdFieldName, sObjects): self._setHeaders('upsert') return self._handleResultTyping(self._sforce.service.upsert(externalIdFieldName, sObjects)) # Describe calls def describeGlobal(self): ''' Retrieves a list of available objects in your organization ''' self._setHeaders('describeGlobal') return self._sforce.service.describeGlobal() def describeLayout(self, sObjectType, recordTypeIds = None): ''' Use describeLayout to retrieve information about the layout (presentation of data to users) for a given object type. The describeLayout call returns metadata about a given page layout, including layouts for edit and display-only views and record type mappings. Note that field-level security and layout editability affects which fields appear in a layout. ''' self._setHeaders('describeLayout') return self._sforce.service.describeLayout(sObjectType, recordTypeIds) def describeSObject(self, sObjectsType): ''' Describes metadata (field list and object properties) for the specified object. ''' self._setHeaders('describeSObject') return self._sforce.service.describeSObject(sObjectsType) def describeSObjects(self, sObjectTypes): ''' An array-based version of describeSObject; describes metadata (field list and object properties) for the specified object or array of objects. ''' self._setHeaders('describeSObjects') return self._handleResultTyping(self._sforce.service.describeSObjects(sObjectTypes)) # describeSoftphoneLayout not implemented # From the docs: "Use this call to obtain information about the layout of a SoftPhone. # Use only in the context of Salesforce CRM Call Center; do not call directly from client programs." def describeTabs(self): ''' The describeTabs call returns information about the standard apps and custom apps, if any, available for the user who sends the call, including the list of tabs defined for each app. ''' self._setHeaders('describeTabs') return self._sforce.service.describeTabs() # Utility calls def getServerTimestamp(self): ''' Retrieves the current system timestamp (GMT) from the Web service. ''' self._setHeaders('getServerTimestamp') return self._sforce.service.getServerTimestamp() def getUserInfo(self): self._setHeaders('getUserInfo') return self._sforce.service.getUserInfo() def resetPassword(self, userId): ''' Changes a user's password to a system-generated value. ''' self._setHeaders('resetPassword') return self._sforce.service.resetPassword(userId) def sendEmail(self, emails): self._setHeaders('sendEmail') return self._handleResultTyping(self._sforce.service.sendEmail(emails)) def setPassword(self, userId, password): ''' Sets the specified user's password to the specified value. ''' self._setHeaders('setPassword') return self._sforce.service.setPassword(userId, password) # SOAP header-related calls def setAllowFieldTruncationHeader(self, header): self._allowFieldTruncationHeader = header def setAssignmentRuleHeader(self, header): self._assignmentRuleHeader = header # setCallOptions() is only implemented in SforcePartnerClient # http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_header_calloptions.htm def setEmailHeader(self, header): self._emailHeader = header def setLocaleOptions(self, header): self._localeOptions = header def setLoginScopeHeader(self, header): self._loginScopeHeader = header def setMruHeader(self, header): self._mruHeader = header def setPackageVersionHeader(self, header): self._packageVersionHeader = header def setQueryOptions(self, header): self._queryOptions = header def setSessionHeader(self, header): self._sessionHeader = header def setUserTerritoryDeleteHeader(self, header): self._userTerritoryDeleteHeader = header
class SforceBaseClient(object): _sforce = None _sessionId = None _location = None _product = 'Python Toolkit' _version = (0, 1, 3) _objectNamespace = None _strictResultTyping = False _allowFieldTruncationHeader = None _assignmentRuleHeader = None _callOptions = None _assignmentRuleHeader = None _emailHeader = None _localeOptions = None _loginScopeHeader = None _mruHeader = None _packageVersionHeader = None _queryOptions = None _sessionHeader = None _userTerritoryDeleteHeader = None def __init__(self, wsdl=None, cacheDuration=0, suds_client=None, **kwargs): ''' Connect to Salesforce 'wsdl' : Location of WSDL 'cacheDuration' : Duration of HTTP GET cache in seconds, or 0 for no cache 'proxy' : Dict of pair of 'protocol' and 'location' e.g. {'http': 'my.insecure.proxy.example.com:80'} 'username' : Username for HTTP auth when using a proxy ONLY 'password' : Password for HTTP auth when using a proxy ONLY ''' if suds_client is None: # Suds can only accept WSDL locations with a protocol prepended if '://' not in wsdl: # TODO windows users??? # check if file exists, else let bubble up to suds as is # definitely don't want to assume http or https if os.path.isfile(wsdl): wsdl = 'file://' + os.path.abspath(wsdl) if cacheDuration > 0: cache = FileCache() cache.setduration(seconds=cacheDuration) else: cache = None self._sforce = Client(wsdl, cache=cache) # Set HTTP headers headers = { 'User-Agent': 'Salesforce/' + self._product + '/' + '.'.join(str(x) for x in self._version) } # This HTTP header will not work until Suds gunzips/inflates the content # 'Accept-Encoding': 'gzip, deflate' self._sforce.set_options(headers=headers) if kwargs.has_key('proxy'): # urllib2 cannot handle HTTPS proxies yet (see bottom of README) if kwargs['proxy'].has_key('https'): raise NotImplementedError( 'Connecting to a proxy over HTTPS not yet implemented due to a \ limitation in the underlying urllib2 proxy implementation. However, traffic from a proxy to \ Salesforce will use HTTPS.') self._sforce.set_options(proxy=kwargs['proxy']) if kwargs.has_key('username'): self._sforce.set_options(username=kwargs['username']) if kwargs.has_key('password'): self._sforce.set_options(password=kwargs['password']) else: self._sforce = suds_client def clone(self): return type(self)(suds_client=self._sforce.clone()) # Toolkit-specific methods def generateHeader(self, sObjectType): ''' Generate a SOAP header as defined in: http://www.salesforce.com/us/developer/docs/api/Content/soap_headers.htm ''' try: return self._sforce.factory.create(sObjectType) except: print 'There is not a SOAP header of type %s' % sObjectType def generateObject(self, sObjectType): ''' Generate a Salesforce object, such as a Lead or Contact ''' obj = self._sforce.factory.create('ens:sObject') obj.type = sObjectType return obj def _handleResultTyping(self, result): ''' If any of the following calls return a single result, and self._strictResultTyping is true, return the single result, rather than [(SaveResult) {...}]: convertLead() create() delete() emptyRecycleBin() invalidateSessions() merge() process() retrieve() undelete() update() upsert() describeSObjects() sendEmail() ''' if self._strictResultTyping == False and len(result) == 1: return result[0] else: return result def _marshallSObjects(self, sObjects, tag='sObjects'): ''' Marshall generic sObjects into a list of SAX elements This code is going away ASAP tag param is for nested objects (e.g. MergeRequest) where key: object must be in <key/>, not <sObjects/> ''' if not isinstance(sObjects, (tuple, list)): sObjects = (sObjects, ) if sObjects[0].type in [ 'LeadConvert', 'SingleEmailMessage', 'MassEmailMessage' ]: nsPrefix = 'tns:' else: nsPrefix = 'ens:' li = [] for obj in sObjects: el = Element(tag) el.set('xsi:type', nsPrefix + obj.type) for k, v in obj: if k == 'type': continue # This is here to avoid 'duplicate values' error when setting a field in fieldsToNull # Even a tag like <FieldName/> will trigger it if v == None: # not going to win any awards for variable-naming scheme here tmp = Element(k) tmp.set('xsi:nil', 'true') el.append(tmp) elif isinstance(v, (list, tuple)): for value in v: el.append(Element(k).setText(value)) elif isinstance(v, suds.sudsobject.Object): el.append(self._marshallSObjects(v, k)) else: el.append(Element(k).setText(v)) li.append(el) return li def _setEndpoint(self, location): ''' Set the endpoint after when Salesforce returns the URL after successful login() ''' # suds 0.3.7+ supports multiple wsdl services, but breaks setlocation :( # see https://fedorahosted.org/suds/ticket/261 try: self._sforce.set_options(location=location) except: self._sforce.wsdl.service.setlocation(location) self._location = location def _setHeaders(self, call=None): ''' Attach particular SOAP headers to the request depending on the method call made ''' # All calls, including utility calls, set the session header headers = {'SessionHeader': self._sessionHeader} if call in ('convertLead', 'create', 'merge', 'process', 'undelete', 'update', 'upsert'): if self._allowFieldTruncationHeader is not None: headers[ 'AllowFieldTruncationHeader'] = self._allowFieldTruncationHeader if call in ('create', 'merge', 'update', 'upsert'): if self._assignmentRuleHeader is not None: headers['AssignmentRuleHeader'] = self._assignmentRuleHeader # CallOptions will only ever be set by the SforcePartnerClient if self._callOptions is not None: if call in ('create', 'merge', 'queryAll', 'query', 'queryMore', 'retrieve', 'search', 'update', 'upsert', 'convertLead', 'login', 'delete', 'describeGlobal', 'describeLayout', 'describeTabs', 'describeSObject', 'describeSObjects', 'getDeleted', 'getUpdated', 'process', 'undelete', 'getServerTimestamp', 'getUserInfo', 'setPassword', 'resetPassword'): headers['CallOptions'] = self._callOptions if call in ('create', 'delete', 'resetPassword', 'update', 'upsert'): if self._emailHeader is not None: headers['EmailHeader'] = self._emailHeader if call in ('describeSObject', 'describeSObjects'): if self._localeOptions is not None: headers['LocaleOptions'] = self._localeOptions if call == 'login': if self._loginScopeHeader is not None: headers['LoginScopeHeader'] = self._loginScopeHeader if call in ('create', 'merge', 'query', 'retrieve', 'update', 'upsert'): if self._mruHeader is not None: headers['MruHeader'] = self._mruHeader if call in ('convertLead', 'create', 'delete', 'describeGlobal', 'describeLayout', 'describeSObject', 'describeSObjects', 'describeTabs', 'merge', 'process', 'query', 'retrieve', 'search', 'undelete', 'update', 'upsert'): if self._packageVersionHeader is not None: headers['PackageVersionHeader'] = self._packageVersionHeader if call in ('query', 'queryAll', 'queryMore', 'retrieve'): if self._queryOptions is not None: headers['QueryOptions'] = self._queryOptions if call == 'delete': if self._userTerritoryDeleteHeader is not None: headers[ 'UserTerritoryDeleteHeader'] = self._userTerritoryDeleteHeader self._sforce.set_options(soapheaders=headers) def setStrictResultTyping(self, strictResultTyping): ''' Set whether single results from any of the following calls return the result wrapped in a list, or simply the single result object: convertLead() create() delete() emptyRecycleBin() invalidateSessions() merge() process() retrieve() undelete() update() upsert() describeSObjects() sendEmail() ''' self._strictResultTyping = strictResultTyping def getSessionId(self): return self._sessionId def getLocation(self): return self._location def getConnection(self): return self._sforce def getLastRequest(self): return str(self._sforce.last_sent()) def getLastResponse(self): return str(self._sforce.last_received()) # Core calls def convertLead(self, leadConverts): ''' Converts a Lead into an Account, Contact, or (optionally) an Opportunity. ''' self._setHeaders('convertLead') return self._handleResultTyping( self._sforce.service.convertLead(leadConverts)) def create(self, sObjects): self._setHeaders('create') return self._handleResultTyping(self._sforce.service.create(sObjects)) def delete(self, ids): ''' Deletes one or more objects ''' self._setHeaders('delete') return self._handleResultTyping(self._sforce.service.delete(ids)) def emptyRecycleBin(self, ids): ''' Permanently deletes one or more objects ''' self._setHeaders('emptyRecycleBin') return self._handleResultTyping( self._sforce.service.emptyRecycleBin(ids)) def getDeleted(self, sObjectType, startDate, endDate): ''' Retrieves the list of individual objects that have been deleted within the given timespan for the specified object. ''' self._setHeaders('getDeleted') return self._sforce.service.getDeleted(sObjectType, startDate, endDate) def getUpdated(self, sObjectType, startDate, endDate): ''' Retrieves the list of individual objects that have been updated (added or changed) within the given timespan for the specified object. ''' self._setHeaders('getUpdated') return self._sforce.service.getUpdated(sObjectType, startDate, endDate) def invalidateSessions(self, sessionIds): ''' Invalidate a Salesforce session This should be used with extreme caution, for the following (undocumented) reason: All API connections for a given user share a single session ID This will call logout() WHICH LOGS OUT THAT USER FROM EVERY CONCURRENT SESSION return invalidateSessionsResult ''' self._setHeaders('invalidateSessions') return self._handleResultTyping( self._sforce.service.invalidateSessions(sessionIds)) def login(self, username, password, token): ''' Login to Salesforce.com and starts a client session. Unlike other toolkits, token is a separate parameter, because Salesforce doesn't explicitly tell you to append it when it gives you a login error. Folks that are new to the API may not know this. 'username' : Username 'password' : Password 'token' : Token return LoginResult ''' self._setHeaders('login') result = self._sforce.service.login(username, password + token) # set session header header = self.generateHeader('SessionHeader') header.sessionId = result['sessionId'] self.setSessionHeader(header) self._sessionId = result['sessionId'] # change URL to point from test.salesforce.com to something like cs2-api.salesforce.com self._setEndpoint(result['serverUrl']) # na0.salesforce.com (a.k.a. ssl.salesforce.com) requires ISO-8859-1 instead of UTF-8 if 'ssl.salesforce.com' in result[ 'serverUrl'] or 'na0.salesforce.com' in result['serverUrl']: # currently, UTF-8 is hard-coded in Suds, can't implement this yet pass return result def logout(self): ''' Logout from Salesforce.com This should be used with extreme caution, for the following (undocumented) reason: All API connections for a given user share a single session ID Calling logout() LOGS OUT THAT USER FROM EVERY CONCURRENT SESSION return LogoutResult ''' self._setHeaders('logout') return self._sforce.service.logout() def merge(self, mergeRequests): self._setHeaders('merge') return self._handleResultTyping( self._sforce.service.merge(mergeRequests)) def process(self, processRequests): self._setHeaders('process') return self._handleResultTyping( self._sforce.service.process(processRequests)) def query(self, queryString): ''' Executes a query against the specified object and returns data that matches the specified criteria. ''' self._setHeaders('query') return self._sforce.service.query(queryString) def queryAll(self, queryString): ''' Retrieves data from specified objects, whether or not they have been deleted. ''' self._setHeaders('queryAll') return self._sforce.service.queryAll(queryString) def queryMore(self, queryLocator): ''' Retrieves the next batch of objects from a query. ''' self._setHeaders('queryMore') return self._sforce.service.queryMore(queryLocator) def retrieve(self, fieldList, sObjectType, ids): ''' Retrieves one or more objects based on the specified object IDs. ''' self._setHeaders('retrieve') return self._handleResultTyping( self._sforce.service.retrieve(fieldList, sObjectType, ids)) def search(self, searchString): ''' Executes a text search in your organization's data. ''' self._setHeaders('search') return self._sforce.service.search(searchString) def undelete(self, ids): ''' Undeletes one or more objects ''' self._setHeaders('undelete') return self._handleResultTyping(self._sforce.service.undelete(ids)) def update(self, sObjects): self._setHeaders('update') return self._handleResultTyping(self._sforce.service.update(sObjects)) def upsert(self, externalIdFieldName, sObjects): self._setHeaders('upsert') return self._handleResultTyping( self._sforce.service.upsert(externalIdFieldName, sObjects)) # Describe calls def describeGlobal(self): ''' Retrieves a list of available objects in your organization ''' self._setHeaders('describeGlobal') return self._sforce.service.describeGlobal() def describeLayout(self, sObjectType, recordTypeIds=None): ''' Use describeLayout to retrieve information about the layout (presentation of data to users) for a given object type. The describeLayout call returns metadata about a given page layout, including layouts for edit and display-only views and record type mappings. Note that field-level security and layout editability affects which fields appear in a layout. ''' self._setHeaders('describeLayout') return self._sforce.service.describeLayout(sObjectType, recordTypeIds) def describeSObject(self, sObjectsType): ''' Describes metadata (field list and object properties) for the specified object. ''' self._setHeaders('describeSObject') return self._sforce.service.describeSObject(sObjectsType) def describeSObjects(self, sObjectTypes): ''' An array-based version of describeSObject; describes metadata (field list and object properties) for the specified object or array of objects. ''' self._setHeaders('describeSObjects') return self._handleResultTyping( self._sforce.service.describeSObjects(sObjectTypes)) # describeSoftphoneLayout not implemented # From the docs: "Use this call to obtain information about the layout of a SoftPhone. # Use only in the context of Salesforce CRM Call Center; do not call directly from client programs." def describeTabs(self): ''' The describeTabs call returns information about the standard apps and custom apps, if any, available for the user who sends the call, including the list of tabs defined for each app. ''' self._setHeaders('describeTabs') return self._sforce.service.describeTabs() # Utility calls def getServerTimestamp(self): ''' Retrieves the current system timestamp (GMT) from the Web service. ''' self._setHeaders('getServerTimestamp') return self._sforce.service.getServerTimestamp() def getUserInfo(self): self._setHeaders('getUserInfo') return self._sforce.service.getUserInfo() def resetPassword(self, userId): ''' Changes a user's password to a system-generated value. ''' self._setHeaders('resetPassword') return self._sforce.service.resetPassword(userId) def sendEmail(self, emails): self._setHeaders('sendEmail') return self._handleResultTyping(self._sforce.service.sendEmail(emails)) def setPassword(self, userId, password): ''' Sets the specified user's password to the specified value. ''' self._setHeaders('setPassword') return self._sforce.service.setPassword(userId, password) # SOAP header-related calls def setAllowFieldTruncationHeader(self, header): self._allowFieldTruncationHeader = header def setAssignmentRuleHeader(self, header): self._assignmentRuleHeader = header # setCallOptions() is only implemented in SforcePartnerClient # http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_header_calloptions.htm def setEmailHeader(self, header): self._emailHeader = header def setLocaleOptions(self, header): self._localeOptions = header def setLoginScopeHeader(self, header): self._loginScopeHeader = header def setMruHeader(self, header): self._mruHeader = header def setPackageVersionHeader(self, header): self._packageVersionHeader = header def setQueryOptions(self, header): self._queryOptions = header def setSessionHeader(self, header): self._sessionHeader = header def setUserTerritoryDeleteHeader(self, header): self._userTerritoryDeleteHeader = header