0

我正在尝试使用 simple_salesforce Python 包将在 Python 中生成的 pdf 作为附件上传到 salesforce 对象。我尝试了几种不同的方法来实现这一点,但到目前为止还没有运气。这是代码

import base64
import json
from simple_salesforce import Salesforce

instance = ''
sessionId = sf.session_id

def pdf_encode(pdf_filename):
    body = open(pdf_filename, 'rb') #open binary file in read mode 
    body = body.read() 
    body = base64.encodebytes(body)

body = pdf_encode('PDF_Report.pdf')


response = requests.post('https://%s.salesforce.com/services/data/v29.0/sobjects/Attachment/' % instance,
    headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer %s' % sessionId },
    data = json.dumps({
        'ParentId': parent_id,
        'Name': 'test.txt',
        'body': body
    })
)

我得到这个错误。

TypeError: Object of type bytes is not JSON serializable

我也尝试过使用

body = base64.encodebytes(body).decode('ascii')

在我的代码中,但我也无法让它工作。我得到错误

UnicodeError: encoding with 'idna' codec failed (UnicodeError: label empty or too long)

关于如何使用 simple_salesforce 将 Python 3 中的 PDF 作为附件上传到 Salesforce 的任何建议?

4

1 回答 1

2

我正在研究这个并找到了一些上传文件的资源。我使用它为自己创建了一个。

以下是您可用于 Python 并将文件上传到 Salesforce 的代码。

import requests
import base64
import json


params = {
    "grant_type": "password",
    "client_id": "Your_Client_Id",
    "client_secret": "Your_Client_Secret",
    "username": "YOUR_EMAIL@procureanalytics.com.pcsandbox", # The email you use to login
    "password": "YOUR_PASSWORD+YOUR_SECURITY_TOKEN" # Concat your password and your security token
}
r = requests.post("https://test.salesforce.com/services/oauth2/token", params=params)
# if you connect to a Sandbox, use test.salesforce.com instead
access_token = r.json().get("access_token")
instance_url = r.json().get("instance_url")
print("Access Token:", access_token)
print("Instance URL", instance_url)

#######################################################################################
# Helper function
#######################################################################################
def sf_api_call(action, parameters = {}, method = 'get', data = {}):
    """
    Helper function to make calls to Salesforce REST API.
    Parameters: action (the URL), URL params, method (get, post or patch), data for POST/PATCH.
    """
    headers = {
        'Content-type': 'application/json',
        'Accept-Encoding': 'gzip',
        'Authorization': 'Bearer %s' % access_token
    }
    if method == 'get':
        r = requests.request(method, instance_url+action, headers=headers, params=parameters, timeout=30)
    elif method in ['post', 'patch']:
        r = requests.request(method, instance_url+action, headers=headers, json=data, params=parameters, timeout=10)
    else:
        # other methods not implemented in this example
        raise ValueError('Method should be get or post or patch.')
    print('Debug: API %s call: %s' % (method, r.url) )
    if r.status_code < 300:
        if method=='patch':
            return None
        else:
            return r.json()
    else:
        raise Exception('API error when calling %s : %s' % (r.url, r.content))
        
# Test connection
print(json.dumps(sf_api_call('/services/data/v40.0/query/', {
    'q': 'SELECT Account.Name, Name, CloseDate from Opportunity where IsClosed = False order by CloseDate ASC LIMIT 1'
}), indent=2))

#######################################################################################
# File Upload from directory
#######################################################################################
# 1) Create a ContentVersion
path = "Folder_name\Sample_pdf.pdf"
with open(path, "rb") as f:
    encoded_string = base64.b64encode(f.read()).decode("utf-8")

ContentVersion = sf_api_call('/services/data/v40.0/sobjects/ContentVersion', method="post", data={
    'Title': 'Sample_pdf file',
    'PathOnClient': path,
    'VersionData': encoded_string,
})
ContentVersion_id = ContentVersion.get('id')

# 2) Get the ContentDocument id
ContentVersion = sf_api_call('/services/data/v40.0/sobjects/ContentVersion/%s' % ContentVersion_id)
ContentDocument_id = ContentVersion.get('ContentDocumentId')


# 3) Create a ContentDocumentLink
Id = "Abcd123" # This Id can be anything: Account_Id or Lead_Id or Opportunity_Id
ContentDocumentLink = sf_api_call('/services/data/v40.0/sobjects/ContentDocumentLink', method = 'post', data={
        'ContentDocumentId': ContentDocument_id,
        'LinkedEntityId': Id,
        'ShareType': 'V'
    })

如何使用

步骤1:

在此处输入您的电子邮件地址和密码。请注意,此处的密码是“您的密码”和您的“安全令牌”的字符串。

# Import libraries
import requests
import base64
import json

params = {
    "grant_type": "password",
    "client_id": "Your_Client_Id",
    "client_secret": "Your_Client_Secret",
    "username": "YOUR_EMAIL@procureanalytics.com.pcsandbox", # The email you use to login
    "password": "YOUR_PASSWORD+YOUR_SECURITY_TOKEN" # Concat your password and your security token
}
r = requests.post("https://test.salesforce.com/services/oauth2/token", params=params)
# if you connect to a Sandbox, use test.salesforce.com instead
access_token = r.json().get("access_token")
instance_url = r.json().get("instance_url")
print("Access Token:", access_token)
print("Instance URL", instance_url)

您可以通过Account >> Settings >> Reset My Security Token在 Salesforce 上获取您的安全令牌。您将收到一封来自 Salesforce 的电子邮件,其中包含您的安全令牌。

第2步:

为 request.post 选择适当的链接
对于沙盒环境:

r = requests.post("https://test.salesforce.com/services/oauth2/token", params=params)

对于生产环境:

r = requests.post("https://login.salesforce.com/services/oauth2/token", params=params)

初始连接准备就绪后,第二个单元格上的输出应如下所示:

Access Token: !2864b793dbce2ad32c1ba7d71009ec84.b793dbce2ad32c1ba7d71009ec84
Instance URL https://your_company_name--pcsandbox.my.salesforce.com

第 3 步:

在“从目录上传文件”单元格(单元格 #5)下,指定您的文件路径。就我而言,这是

# 1) Create a ContentVersion
path = "Folder_name\Sample_pdf.pdf"
with open(path, "rb") as f:
    encoded_string = base64.b64encode(f.read()).decode("utf-8")

第4步:

在同一单元格下,提及您要上传文件的 ID。下面的示例代码正在为 ID 为Abcd123的帐户上传 Accounts 对象上的文件

# 3) Create a ContentDocumentLink
Id = "Abcd123" # This Id can be anything: Account_Id or Lead_Id or Opportunity_Id
ContentDocumentLink = sf_api_call('/services/data/v40.0/sobjects/ContentDocumentLink', method = 'post', data={
        'ContentDocumentId': ContentDocument_id,
        'LinkedEntityId': Id,
        'ShareType': 'V'
    })
于 2021-05-13T16:56:27.577 回答