Beispiel #1
0
def get_view():
    """Obtains a sending view from DocuSign. The user will then be redirected to the view url

    Uses the information stored in the session to request the view.
    Query parameter: send = 0 or 1. See https://goo.gl/aLNjJH
    RETURNS {err, redirect_url}
    """

    err = False  # No problems so far!
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    if not embedded_tagging_key in session:
        return {
            "err":
            "Embedded signing information missing from session! Please re-send."
        }

    embedding_info = session[embedded_tagging_key]
    # Obtain the "sender's view"
    # See https://docs.docusign.com/esign/restapi/Envelopes/EnvelopeViews/createSender/

    return_url = ds_recipe_lib.get_base_url(2) + return_uri
    data = {"returnUrl": return_url}
    send = request.args.get('send')

    # append "/envelopes/{envelopeId}/views/sender" to the baseUrl and use in the request
    url = auth["base_url"] + '/envelopes/{}/views/sender?send={}'.format(
        embedding_info["envelopeId"], send)
    ds_headers = {
        'Accept': 'application/json',
        auth["auth_header_key"]: auth["auth_header_value"],
        trace_key: trace_value
    }

    try:
        r = requests.post(url, headers=ds_headers, json=data)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling EnvelopeViews:createSender: " + str(e)}

    status = r.status_code
    if (status != 201):
        return ({
            'err':
            "Error calling DocuSign EnvelopeViews:createSender<br/>Status is: "
            + str(status) + ". Response: <pre><code>" + r.text +
            "</code></pre>"
        })

    data = r.json()
    redirect_url = data['url']
    # Update the send parameter in the url
    # An example url:
    # https://demo.docusign.net/Member/StartInSession.aspx?StartConsole=1&t=2fABCXYZ6197&DocuEnvelope=2dABCXYZ&send=1
    # We search for send=0|1 and replace it per our incoming "send" parameter
    send_re = re.compile("(\&send=[01])")
    redirect_url = send_re.sub("&send={}".format(request.args.get('send')),
                               redirect_url)
    return {"err": err, "redirect_url": redirect_url}
def get_doc():
    """Get a document from DocuSign

    query parameters: url, fn
    Returns {err, pdf, filename}
    """
    err = False # No problems so far!
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    uri = request.args.get("url")
    fn = request.args.get("fn")

    if not uri:
        return {"err": "query parameter url is missing!"}

    # Retrieve file
    # append the uri parameter to the baseUrl and use in the request
    url = auth["base_url"] + uri
    ds_headers = {'Accept': 'Accept: application/pdf', auth["auth_header_key"]: auth["auth_header_value"],
                  trace_key: trace_value}

    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling EnvelopeViews:createRecipient: " + str(e)}

    status = r.status_code
    if (status != 200):
        return ({'err': "Error retrieving document.<br/>Status is: " +
                        str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"})

    # Success!
    return {"err": err, "pdf": r.content, "filename": fn}
def logs_list():
    """Returns log_entries for all current logs that were previously downloaded

    {"err": an error or false
     "entries": Array of log_entry
     log_entry: {file_name: the filename of the entry
                url: for retrieving the file
                head: first 1500 bytes of the entry, base64 encoded}
    }
    Strategy: parse the log files on the clients.
    """
    global auth
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}
    entries = []
    log_path = get_log_path()
    log_path_url = ds_recipe_lib.get_base_url(
        1) + "/" + log_storage_uri + "/" + account_id_to_dir(
            auth["account_id"]) + "/"

    # Walk the dir
    for i in os.listdir(log_path):
        if i.endswith(".txt"):
            entries.append(
                api_log_item(os.path.join(log_path, i), i, log_path_url))
    return {"err": False, "entries": entries}
def get_view():
    """Obtains a view from DocuSign. The user will then be redirected to the view url

    Uses the information stored in the session to request the view.
    RETURNS {err, redirect_url}
    """

    err = False  # No problems so far!
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    if not embedded_signing_key in session:
        return {
            "err":
            "Embedded signing information missing from session! Please re-send."
        }

    embedding_info = session[embedded_signing_key]
    # Obtain the "recipient's view" (In this case, its the signer's view)
    # See https://docs.docusign.com/esign/restapi/Envelopes/EnvelopeViews/createRecipient/

    return_url = ds_recipe_lib.get_base_url(2) + return_uri
    data = {
        "authenticationMethod":
        "Password",  # How was this recipient authenticated. Pick from list of values
        "clientUserId": embedding_info["clientUserId"],
        "email": embedding_info["email"],
        "userName": embedding_info["name"],
        "returnUrl": return_url
    }

    # append "/envelopes/{envelopeId}/views/recipient" to the baseUrl and use in the request
    url = auth["base_url"] + '/envelopes/{}/views/recipient'.format(
        embedding_info["envelopeId"])
    ds_headers = {
        'Accept': 'application/json',
        auth["auth_header_key"]: auth["auth_header_value"],
        trace_key: trace_value
    }

    try:
        r = requests.post(url, headers=ds_headers, json=data)
    except requests.exceptions.RequestException as e:
        return {
            'err': "Error calling EnvelopeViews:createRecipient: " + str(e)
        }

    status = r.status_code
    if (status != 201):
        return ({
            'err':
            "Error calling DocuSign EnvelopeViews:createRecipient<br/>Status is: "
            + str(status) + ". Response: <pre><code>" + r.text +
            "</code></pre>"
        })

    data = r.json()
    redirect_url = data['url']
    return {"err": err, "redirect_url": redirect_url}
def start():
    """Sends EnvelopeRecipients: list method

    Returns r: {
        err: False, or an error message
        intro: html introduction to the page
        url: the url used for the request
        response: the response body
        }
    """

    # Ready...

    # STEP 1 - Fetch Authentication information from session
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    if not 'latest_envelope_id' in session:
        return {
            "err":
            "Problem, no envelope ID is available. Please send an envelope with a different recipe, then retry the Envelope Recipient Status recipe."
        }
    envelope_id = session['latest_envelope_id']

    #
    # STEP 2 - Create and send the request
    #
    # See the docs, https://docs.docusign.com/esign/restapi/Envelopes/EnvelopeRecipients/list

    # create the url from the baseUrl
    url = auth[
        "base_url"] + "/envelopes/{}/recipients/?include_tabs=true".format(
            envelope_id)
    ds_headers = {
        'Accept': 'application/json',
        auth["auth_header_key"]: auth["auth_header_value"],
        trace_key: trace_value
    }

    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling EnvelopeRecipients:list: " + str(e)}

    status = r.status_code
    if (status != 200):
        return ({
            'err':
            "Error calling DocuSign EnvelopeRecipients:list<br/>Status is: " +
            str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"
        })

    response = r.json()
    return {
        "err": False,
        "url": url,
        "intro": intro,
        "response": json.dumps(response, indent=4, sort_keys=True)
    }
def get_status(envelope_id):
    """Fetch the envelope status from DocuSign

    See https://docs.docusign.com/esign/restapi/Envelopes/Envelopes/get/
    Returns {false or the result of the call}
    """

    # Sample data returned from the Envelopes: Get method
    # {
    #     "status": "completed",
    #     "documentsUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/documents",
    #     "recipientsUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/recipients",
    #     "envelopeUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d",
    #     "emailSubject": "Please sign the NDA package",
    #     "envelopeId": "ed400d38-7765-4ce5-9f50-8652a8c4486d",
    #     "customFieldsUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/custom_fields",
    #     "autoNavigation": "true",
    #     "envelopeIdStamping": "true",
    #     "notificationUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/notification",
    #     "enableWetSign": "true",
    #     "allowMarkup": "false",
    #     "createdDateTime": "2016-06-28T15:57:07.1800000Z",
    #     "lastModifiedDateTime": "2016-06-28T15:57:07.1800000Z",
    #     "deliveredDateTime": "2016-06-28T15:57:33.6270000Z",
    #     "initialSentDateTime": "2016-06-28T15:57:07.7430000Z",
    #     "sentDateTime": "2016-06-28T15:57:33.6270000Z",
    #     "completedDateTime": "2016-06-28T15:57:33.6270000Z",
    #     "statusChangedDateTime": "2016-06-28T15:57:33.6270000Z",
    #     "documentsCombinedUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/documents/combined",
    #     "certificateUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/documents/certificate",
    #     "templatesUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/templates",
    #     "brandId": "3774f432-9d31-40e6-bc6b-6ae30cce334c",
    #     "purgeState": "unpurged",
    #     "is21CFRPart11": "false",
    #     "isSignatureProviderEnvelope": "false"
    # }

    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    # append "/envelopes/{envelopeId}" to the baseUrl and use in the request
    url = auth["base_url"] + '/envelopes/{}'.format(envelope_id) + "?cache_buster={}".format(time.time())
    ds_headers = {'Accept': 'application/json', auth["auth_header_key"]: auth["auth_header_value"],
                  trace_key: trace_value}

    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return False

    status = r.status_code
    if (status != 200):
        return False

    result = r.json()
    result["err"] = False
    return result
def start():
    """Sends Envelopes: listStatusChanges method

    Returns r: {
        err: False, or an error message
        intro: html introduction to the page
        url: the url used for the request
        response: the response body
        }
    """

    # Ready...

    # STEP 1 - Fetch Authentication information from session
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    #
    # STEP 2 - Create and send the request
    #
    
    # See the docs, https://docs.docusign.com/esign/restapi/Envelopes/Envelopes/listStatusChanges/
    # We need to set one or more of the following parameters: from_date, envelopeIds and/or transactionIds.
    # We will set from_date to be yesterday.
    #
    # If you're using this method to poll for changes, see "Polling for Current Status" section of 
    # page https://docs.docusign.com/esign/guide/usage/status_and_events.html for a strategy that won't
    # violate the platform's polling policy.
    
    # construct the body of the request
    yesterday = datetime.date.today() - datetime.timedelta(days=1)
    yesterday_s = yesterday.strftime ("%Y-%m-%d") # '2016-07-25'
        
    # create the url from the baseUrl
    url = auth["base_url"] + "/envelopes?from_date={}".format(yesterday_s)
    ds_headers = {'Accept': 'application/json', auth["auth_header_key"]: auth["auth_header_value"],
                  trace_key: trace_value}

    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling Envelopes:listStatusChanges: " + str(e)}
        
    status = r.status_code
    if (status != 200): 
        return ({'err': "Error calling DocuSign Envelopes:listStatusChanges<br/>Status is: " +
            str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"})

    response = r.json()
    return {
        "err": False,
        "url": url,
        "intro": intro,
        "response": json.dumps(response, indent=4, sort_keys=True)
    }
def start():
    """Sends EnvelopeRecipients: list method

    Returns r: {
        err: False, or an error message
        intro: html introduction to the page
        url: the url used for the request
        response: the response body
        }
    """

    # Ready...

    # STEP 1 - Fetch Authentication information from session
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}
        
    if not 'latest_envelope_id' in session:
        return {"err": "Problem, no envelope ID is available. Please send an envelope with a different recipe, then retry the Envelope Recipient Status recipe."}
    envelope_id = session['latest_envelope_id']

    #
    # STEP 2 - Create and send the request
    #
    # See the docs, https://docs.docusign.com/esign/restapi/Envelopes/EnvelopeRecipients/list
            
    # create the url from the baseUrl
    url = auth["base_url"] + "/envelopes/{}/recipients/?include_tabs=true".format(envelope_id)
    ds_headers = {'Accept': 'application/json', auth["auth_header_key"]: auth["auth_header_value"],
                  trace_key: trace_value}

    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling EnvelopeRecipients:list: " + str(e)}
        
    status = r.status_code
    if (status != 200): 
        return ({'err': "Error calling DocuSign EnvelopeRecipients:list<br/>Status is: " +
            str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"})

    response = r.json()
    return {
        "err": False,
        "url": url,
        "intro": intro,
        "response": json.dumps(response, indent=4, sort_keys=True)
    }
def get_view():
    """Obtains a sending view from DocuSign. The user will then be redirected to the view url

    Uses the information stored in the session to request the view.
    Query parameter: send = 0 or 1. See https://goo.gl/aLNjJH
    RETURNS {err, redirect_url}
    """    

    err = False # No problems so far!
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    if not embedded_tagging_key in session:
        return {"err": "Embedded signing information missing from session! Please re-send."}

    embedding_info = session[embedded_tagging_key]
    # Obtain the "sender's view" 
    # See https://docs.docusign.com/esign/restapi/Envelopes/EnvelopeViews/createSender/

    return_url = ds_recipe_lib.get_base_url(2) + return_uri
    data = {"returnUrl": return_url}
    send = request.args.get('send')

    # append "/envelopes/{envelopeId}/views/sender" to the baseUrl and use in the request
    url = auth["base_url"] + '/envelopes/{}/views/sender?send={}'.format(
        embedding_info["envelopeId"], send)
    ds_headers = {'Accept': 'application/json', auth["auth_header_key"]: auth["auth_header_value"],
                  trace_key: trace_value}

    try:
        r = requests.post(url, headers=ds_headers, json=data)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling EnvelopeViews:createSender: " + str(e)}

    status = r.status_code
    if (status != 201):
        return ({'err': "Error calling DocuSign EnvelopeViews:createSender<br/>Status is: " +
                        str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"})

    data = r.json()
    redirect_url = data['url']
    # Update the send parameter in the url
    # An example url:
    # https://demo.docusign.net/Member/StartInSession.aspx?StartConsole=1&t=2fABCXYZ6197&DocuEnvelope=2dABCXYZ&send=1
    # We search for send=0|1 and replace it per our incoming "send" parameter
    send_re = re.compile("(\&send=[01])")
    redirect_url = send_re.sub("&send={}".format(request.args.get('send')), redirect_url)
    return {"err": err, "redirect_url": redirect_url}
def get_view():
    """Obtains a view from DocuSign. The user will then be redirected to the view url

    Uses the information stored in the session to request the view.
    RETURNS {err, redirect_url}
    """

    err = False # No problems so far!
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    if not embedded_signing_key in session:
        return {"err": "Embedded signing information missing from session! Please re-send."}

    embedding_info = session[embedded_signing_key]
    # Obtain the "recipient's view" (In this case, its the signer's view)
    # See https://docs.docusign.com/esign/restapi/Envelopes/EnvelopeViews/createRecipient/

    return_url = ds_recipe_lib.get_base_url(2) + return_uri
    data = {"authenticationMethod": "Password", # How was this recipient authenticated. Pick from list of values
            "clientUserId": embedding_info["clientUserId"],
            "email": embedding_info["email"],
            "userName": embedding_info["name"],
            "returnUrl": return_url
            }

    # append "/envelopes/{envelopeId}/views/recipient" to the baseUrl and use in the request
    url = auth["base_url"] + '/envelopes/{}/views/recipient'.format(embedding_info["envelopeId"])
    ds_headers = {'Accept': 'application/json', auth["auth_header_key"]: auth["auth_header_value"],
                  trace_key: trace_value}

    try:
        r = requests.post(url, headers=ds_headers, json=data)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling EnvelopeViews:createRecipient: " + str(e)}

    status = r.status_code
    if (status != 201):
        return ({'err': "Error calling DocuSign EnvelopeViews:createRecipient<br/>Status is: " +
                        str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"})

    data = r.json()
    redirect_url = data['url']
    return {"err": err, "redirect_url": redirect_url}
def get_doc():
    """Get a document from DocuSign

    query parameters: url, fn
    Returns {err, pdf, filename}
    """
    err = False  # No problems so far!
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    uri = request.args.get("url")
    fn = request.args.get("fn")

    if not uri:
        return {"err": "query parameter url is missing!"}

    # Retrieve file
    # append the uri parameter to the baseUrl and use in the request
    url = auth["base_url"] + uri
    ds_headers = {
        'Accept': 'Accept: application/pdf',
        auth["auth_header_key"]: auth["auth_header_value"],
        trace_key: trace_value
    }

    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return {
            'err': "Error calling EnvelopeViews:createRecipient: " + str(e)
        }

    status = r.status_code
    if (status != 200):
        return ({
            'err':
            "Error retrieving document.<br/>Status is: " + str(status) +
            ". Response: <pre><code>" + r.text + "</code></pre>"
        })

    # Success!
    return {"err": err, "pdf": r.content, "filename": fn}
def get_logging_status():
    """Returns the logging status of the account

    Side-effect: initializes logging if it isn't already active

    Returns:
    logging_status = {
        err: False or a problem string.
        err_code: False or codes eg 'GENERIC', 'PLEASE_AUTHENTICATE', 
        status: string description of the status
        logging: True / False
        remaining_entries: integer from the platform,
        max_entries: integer from the platform
        }
    """

    global auth
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    logging = logging_updateSettings(
    )  # returns {err, max_entries, remaining_entries, err_code}
    if logging['err']:
        return {"err": logging["err"]}

    # No API error...
    if logging["logging"]:
        logging_activated = "Logging is activated. "
    else:
        logging_activated = "Logging is <b>not</b> activated! "
    status = logging_activated + "{} logging spaces are available out of {} total.".format(
        logging["remaining_entries"], logging["max_entries"])
    return {
        'err': False,
        'status': status,
        'logging': logging["logging"],
        'remaining_entries': logging["remaining_entries"],
        'max_entries': logging["max_entries"]
    }
def logs_download():
    """Download (and then delete) the logs from DocuSign

    The logs are stored in files/log/<account_id>/log_<timestamp>_<orig_name>
    <orig_name> is the original name of the file from the platform. Eg:
        00_OK_GetAccountSharedAccess.txt
        01_OK_GetFolderList.txt
        02_OK_ExecuteLoggedApiBusinessLogic.txt
        03_Created_RequestRecipientToken.txt
        04_OK_GetEnvelope.txt
        05_OK_GetEnvelope.txt
        06_OK_SendEnvelope.txt

    Returns {err: False or a problem string, entries: log_entries, err_code }
        returns an array of just the new log_entries
    """
    global auth
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}
    r = logging_do_download()  # returns {err, new_entries}
    return r
Beispiel #14
0
def send():
    """Creates the envelope as a draft

    Returns r: {
        err: False, or an error message
        html: html output, to be displayed
        envelope_id:
        }
    """

    # Ready...
    # Possibly create some fake people
    ds_signer1_email = ds_recipe_lib.get_signer_email(ds_signer1_email_orig)
    ds_signer1_name = ds_recipe_lib.get_signer_name(ds_signer1_name_orig)
    ds_cc1_email = ds_recipe_lib.get_signer_email(ds_cc1_email_orig)
    ds_cc1_name = ds_recipe_lib.get_signer_name(ds_cc1_name_orig)

    # STEP 1 - Fetch Authentication information from session
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    #
    # STEP 2 - Create the draft envelope
    #

    # construct the body of the request
    file_contents = open(doc_document_path, "rb").read()

    # Please use the most accurate and relevant subject line.
    subject = "Please sign the NDA package"
    # File contents are provided here
    # The documents array can include multiple documents, of differing types.
    # All documents are converted to pdf prior to signing.
    # The fileExtension field defaults to "pdf".
    documents = [{
        "documentId": "1",
        "name": doc_document_name,
        "fileExtension": os.path.splitext(doc_document_path)[1][1:],
        "documentBase64": base64.b64encode(file_contents)
    }]

    # The signing fields
    #
    # Invisible (white) Anchor field names for the NDA.pdf document:
    #   * signer1sig
    #   * signer1name
    #   * signer1company
    #   * signer1date
    #
    fields = {
        "signHereTabs": [{
            "anchorString": "signer1sig",  # Anchored for doc 1
            "anchorXOffset": "0",
            "anchorYOffset": "0",
            "anchorUnits": "mms",
            "recipientId": "1",
            "name": "Please sign here",
            "optional": "false",
            "scaleValue": 1,
            "tabLabel": "signer1sig"
        }],
        "fullNameTabs": [{
            "anchorString": "signer1name",  # Anchored for doc 1
            "anchorYOffset": "-6",
            "fontSize": "Size12",
            "recipientId": "1",
            "tabLabel": "Full Name",
            "name": "Full Name"
        }]
    }

    signers = [{
        "email": ds_signer1_email,
        "name": ds_signer1_name,
        "recipientId": "1",
        "routingOrder": "1",
        "tabs": fields
    }]

    ccs = [{
        "email": ds_cc1_email,
        "name": ds_cc1_name,
        "recipientId": "2",
        "routingOrder": "2"
    }]

    data = {
        "emailSubject": subject,
        "documents": documents,
        "recipients": {
            "signers": signers,
            "carbonCopies": ccs
        },
        "status":
        "created"  ### "created" status means we'll get a draft envelope
    }

    eventNotification = ds_webhook.get_eventNotification_object()
    if eventNotification:
        data["eventNotification"] = eventNotification

    # append "/envelopes" to the baseUrl and use in the request
    url = auth["base_url"] + "/envelopes"
    ds_headers = {
        'Accept': 'application/json',
        auth["auth_header_key"]: auth["auth_header_value"],
        trace_key: trace_value
    }

    try:
        r = requests.post(url, headers=ds_headers, json=data)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling Envelopes:create: " + str(e)}

    status = r.status_code
    if (status != 201):
        return ({
            'err':
            "Error calling DocuSign Envelopes:create<br/>Status is: " +
            str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"
        })

    data = r.json()
    envelope_id = data['envelopeId']
    session['latest_envelope_id'] = envelope_id  # Save for other recipe's use

    # Save the information that we will need for the embedded tagging
    # in our "database" (for this example, we're using the session)
    session[embedded_tagging_key] = {"envelopeId": envelope_id}

    # Instructions for tagging and sending the envelope
    html = (
        "<h2>A draft envelope was created, ready to be tagged and sent!</h2>" +
        "<p>Envelope ID: " + envelope_id + "</p>" + "<p>Signer: " +
        ds_signer1_name + "</p>" + "<p>CC: " + ds_cc1_name + "</p>")
    html += (
        "<h2>Next step:</h2>" + "<form action='get_view'>" +
        "<p><select name='send'>" +
        "<option value='0'>Start with the prepare page</option>" +
        "<option value='1' selected='selected'>Start with the tagging page</option>"
        + "</select></p>" +
        "<button type='submit' class='btn btn-primary'>Tag and Send the envelope</button>"
        + "</form>")

    return {
        "err": False,
        "envelope_id": envelope_id,
        "ds_signer1_email": ds_signer1_email,
        "ds_signer1_name": ds_signer1_name,
        "ds_signer1_qr": ds_signer1_email,
        "ds_cc1_email": ds_cc1_email,
        "ds_cc1_name": ds_cc1_name,
        "html": html
    }
def get_status(envelope_id):
    """Fetch the envelope status from DocuSign

    See https://docs.docusign.com/esign/restapi/Envelopes/Envelopes/get/
    Returns {false or the result of the call}
    """

    # Sample data returned from the Envelopes: Get method
    # {
    #     "status": "completed",
    #     "documentsUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/documents",
    #     "recipientsUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/recipients",
    #     "envelopeUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d",
    #     "emailSubject": "Please sign the NDA package",
    #     "envelopeId": "ed400d38-7765-4ce5-9f50-8652a8c4486d",
    #     "customFieldsUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/custom_fields",
    #     "autoNavigation": "true",
    #     "envelopeIdStamping": "true",
    #     "notificationUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/notification",
    #     "enableWetSign": "true",
    #     "allowMarkup": "false",
    #     "createdDateTime": "2016-06-28T15:57:07.1800000Z",
    #     "lastModifiedDateTime": "2016-06-28T15:57:07.1800000Z",
    #     "deliveredDateTime": "2016-06-28T15:57:33.6270000Z",
    #     "initialSentDateTime": "2016-06-28T15:57:07.7430000Z",
    #     "sentDateTime": "2016-06-28T15:57:33.6270000Z",
    #     "completedDateTime": "2016-06-28T15:57:33.6270000Z",
    #     "statusChangedDateTime": "2016-06-28T15:57:33.6270000Z",
    #     "documentsCombinedUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/documents/combined",
    #     "certificateUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/documents/certificate",
    #     "templatesUri": "/envelopes/ed400d38-7765-4ce5-9f50-8652a8c4486d/templates",
    #     "brandId": "3774f432-9d31-40e6-bc6b-6ae30cce334c",
    #     "purgeState": "unpurged",
    #     "is21CFRPart11": "false",
    #     "isSignatureProviderEnvelope": "false"
    # }

    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    # append "/envelopes/{envelopeId}" to the baseUrl and use in the request
    url = auth["base_url"] + '/envelopes/{}'.format(
        envelope_id) + "?cache_buster={}".format(time.time())
    ds_headers = {
        'Accept': 'application/json',
        auth["auth_header_key"]: auth["auth_header_value"],
        trace_key: trace_value
    }

    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return False

    status = r.status_code
    if (status != 200):
        return False

    result = r.json()
    result["err"] = False
    return result
def send():
    """Sends the envelope

    Returns r: {
        err: False, or an error message
        html: html output, to be displayed
        envelope_id:
        }
    """

    # Ready...
    # Possibly create some fake people
    ds_signer1_email = ds_recipe_lib.get_signer_email(ds_signer1_email_orig)
    ds_signer1_name = ds_recipe_lib.get_signer_name(ds_signer1_name_orig)
    ds_cc1_email = ds_recipe_lib.get_signer_email(ds_cc1_email_orig)
    ds_cc1_name = ds_recipe_lib.get_signer_name(ds_cc1_name_orig)
    ds_cc2_email = ds_recipe_lib.get_signer_email(ds_cc2_email_orig)
    ds_cc2_name = ds_recipe_lib.get_signer_name(ds_cc2_name_orig)

    # STEP 1 - Fetch Authentication information from session
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    #
    # STEP 2 - Create and send envelope
    #
    # construct the body of the request
    file_contents = open(doc_document_path, "rb").read()

    # Please use the most accurate and relevant subject line.
    subject = "Please sign the NDA package"
    # File contents are provided here
    # The documents array can include multiple documents, of differing types.
    # All documents are converted to pdf prior to signing.
    # The fileExtension field defaults to "pdf".
    documents = [{"documentId": "1",
            "name": doc_document_name,
            "fileExtension": os.path.splitext(doc_document_path)[1][1:],
            "documentBase64": base64.b64encode(file_contents)}
        ]

    # The signing fields
    #
    # Invisible (white) Anchor field names for the NDA.pdf document:
    #   * signer1sig
    #   * signer1name
    #   * signer1company
    #   * signer1date
    #
    fields = {
    "signHereTabs": [{
        "anchorString": "signer1sig", # Anchored for doc 1
        "anchorXOffset": "0",
        "anchorYOffset": "0",
        "anchorUnits": "mms",
        "recipientId": "1",
        "name": "Please sign here",
        "optional": "false",
        "scaleValue": 1,
        "tabLabel": "signer1sig"}],
    "fullNameTabs": [{
        "anchorString": "signer1name", # Anchored for doc 1
        "anchorYOffset": "-6",
        "fontSize": "Size12",
        "recipientId": "1",
        "tabLabel": "Full Name",
        "name": "Full Name"}],
    "textTabs": [{
        "anchorString": "signer1company", # Anchored for doc 1
        "anchorYOffset": "-8",
        "fontSize": "Size12",
        "recipientId": "1",
        "tabLabel": "Company",
        "name": "Company",
        "required": "false"}],
    "signerAttachmentTabs": [{
        "anchorString": "signer1company", # Anchored for doc 1
        "anchorYOffset": "110",
        "fontSize": "Size12",
        "recipientId": "1",
        "tabLabel": "Optional attachment",
        "name": "NDA_attachment",
        "optional": "true"}],
    "dateSignedTabs": [{
        "anchorString": "signer1date", # Anchored for doc 1
        "anchorYOffset": "-6",
        "fontSize": "Size12",
        "recipientId": "1",
        "name": "Date Signed",
        "tabLabel": "date_signed"}]
    }

    signers = [{"email": ds_signer1_email,
                "name": ds_signer1_name,
                "clientUserId": ds_signer1_clientUserId, # this signer is an embedded signer
                "recipientId": "1",
                "routingOrder": "1",
                "tabs": fields}]

    ccs = [{"email": ds_cc1_email,
            "name": ds_cc1_name,
            "recipientId": "2",
            "routingOrder": "2"},
           {"email": ds_cc2_email,
            "name": ds_cc2_name,
            "recipientId": "3",
            "routingOrder": "3"}]

    data = {
        "emailSubject": subject,
        "documents": documents,
        "recipients": {"signers": signers, "carbonCopies": ccs},
        "status": "sent"
    }

    eventNotification = ds_webhook.get_eventNotification_object()
    if eventNotification:
        data["eventNotification"] = eventNotification

    # append "/envelopes" to the baseUrl and use in the request
    url = auth["base_url"] + "/envelopes"
    ds_headers = {'Accept': 'application/json', auth["auth_header_key"]: auth["auth_header_value"],
                  trace_key: trace_value}

    try:
        r = requests.post(url, headers=ds_headers, json=data)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling Envelopes:create: " + str(e)}

    status = r.status_code
    if (status != 201):
        return ({'err': "Error calling DocuSign Envelopes:create<br/>Status is: " +
            str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"})

    data = r.json()
    envelope_id = data['envelopeId']
    session['latest_envelope_id'] = envelope_id # Save for other recipe's use

    # Save the information that we will need for the embedded signing
    # in our "database" (for this example, we're using the session)
    session[embedded_signing_key] = {
        "email": ds_signer1_email,
        "name": ds_signer1_name,
        "clientUserId": ds_signer1_clientUserId,
        "envelopeId": envelope_id}

    # Instructions for signing the email
    webhook_instructions = ds_webhook.webhook_instructions(envelope_id)
    html =  ("<h2>Envelope created, ready to be signed!</h2>" +
            "<p>Envelope ID: " + envelope_id + "</p>" +
            "<p>Signer: " + ds_signer1_name + "</p>" +
            "<p>CC: " + ds_cc1_name + ", " + ds_cc2_name + "</p>")
    if webhook_instructions:
        html += (
            "<h2>Next steps:</h2>" +
            webhook_instructions +
            "<h3>2. Sign the envelope</h3>" +
            "<form action='get_view'>" +
            "<button type='submit' class='btn btn-primary'>" + sign_button_text + "</button>" +
            "</form>")
    else:
        html += (
            "<h2>Next step:</h2>" +

            "<form action='get_view'>" +
            "<button type='submit' class='btn btn-primary'>" + sign_button_text + "</button>" +
            "</form>")

    return {
        "err": False,
        "envelope_id": envelope_id,
        "ds_signer1_email": ds_signer1_email,
        "ds_signer1_name": ds_signer1_name,
        "ds_signer1_clientUserId": ds_signer1_clientUserId,
        "ds_signer1_qr": ds_signer1_email,
        "ds_cc1_email": ds_cc1_email,
        "ds_cc1_name": ds_cc1_name,
        "html": html
    }
def send():
    """Sends the envelope from a template

    Parameters:
        template_name
        company_name

    Returns r: {
        err: False, or an error message
        html: html output, to be displayed
        envelope_id:
        }
    """

    # Ready...
    # Possibly create some fake people
    ds_signer1_email = ds_recipe_lib.get_signer_email(ds_signer1_email_orig)
    ds_signer1_name = ds_recipe_lib.get_signer_name(ds_signer1_name_orig)
    ds_cc1_email = ds_recipe_lib.get_signer_email(ds_cc1_email_orig)
    ds_cc1_name = ds_recipe_lib.get_signer_name(ds_cc1_name_orig)

    # STEP 1 - Fetch Authentication information from session
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    #
    # STEP 2 - lookup the template
    #
    template_name = request.form.get('template_name')
    company_name = request.form.get('company_name')
    if not template_name:
        return {"err": "Please fill in a template name"}
    if not company_name:
        return {"err": "Please fill in a company name"}

    # Templates: list. See https://docs.docusign.com/esign/restapi/Templates/Templates/list/
    url = auth["base_url"] + "/templates?" + "search_text={}".format(urllib.quote(template_name))
    ds_headers = {'Accept': 'application/json', auth["auth_header_key"]: auth["auth_header_value"],
                  trace_key: trace_value}
    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling Templates:list: " + str(e)}

    status = r.status_code
    if (status != 200):
        return ({'err': "Error calling DocuSign Templates:list<br/>Status is: " +
                        str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"})

    data = r.json()
    if data["resultSetSize"] == "0":
        return {"err": "No Templates with title {} were found.".format(template_name)}

    # Use the first template_id in the results
    template_id = data["envelopeTemplates"][0]["templateId"]

    # When we create the envelope, we want to set the text tag with the company name value.
    # To set a value, we need the tab's "tabLabel". If it were an agreed value with the person
    # who created the tab, that'd be fine. For the purpose of this example, we'll be more
    # flexible: we'll get the details on the template, and then assume that the first text tab
    # is the company tab. You wouldn't want to do this in production since someone might add
    # an additional text tab to the template, which would break the integration.

    # Use the Templates: get method to retrieve full info about the template.
    # See https://docs.docusign.com/esign/restapi/Templates/Templates/get/
    url = auth["base_url"] + "/templates/{}".format(urllib.quote(template_id))
    ds_headers = {'Accept': 'application/json', auth["auth_header_key"]: auth["auth_header_value"],
                  trace_key: trace_value}
    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling Templates:list: " + str(e)}

    status = r.status_code
    if (status != 200):
        return ({'err': "Error calling DocuSign Templates:list<br/>Status is: " +
                        str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"})

    data = r.json()
    company_tabLabel = data["recipients"]["signers"][0]["tabs"]["textTabs"][0]["tabLabel"]

    #
    # STEP 3 - Create and send envelope
    #
    # Since we're using a template, this request is relatively small
    # The signer and cc role names must be in agreement with the template's settings
    template_role_signer_1 = {
        "roleName": signer1_role,
        "email": ds_signer1_email,
        "name": ds_signer1_name,
        "tabs": {
            "textTabs": [
                {"tabLabel": company_tabLabel, "value": company_name}
            ]
        }
    }
    template_role_cc = {
        "roleName": cc_role,
        "email": ds_cc1_email,
        "name": ds_cc1_name
    }
    data = {
        "templateId": template_id,
        "templateRoles": [template_role_signer_1, template_role_cc],
        "status": "sent"
    }
    eventNotification = ds_webhook.get_eventNotification_object()
    if eventNotification:
        data["eventNotification"] = eventNotification

    # append "/envelopes" to the baseUrl and use in the request
    url = auth["base_url"] + "/envelopes"
    ds_headers = {'Accept': 'application/json', auth["auth_header_key"]: auth["auth_header_value"],
                  trace_key: trace_value}
    try:
        r = requests.post(url, headers=ds_headers, json=data)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling Envelopes:create: " + str(e)}

    status = r.status_code
    if (status != 201):
        return ({'err': "Error calling DocuSign Envelopes:create<br/>Status is: " +
            str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"})

    data = r.json()
    envelope_id = data['envelopeId']
    session['latest_envelope_id'] = envelope_id # Save for other recipe's use

    # Instructions for reading the email
    webhook_instructions = ds_webhook.webhook_instructions(envelope_id)
    html =  ("<h2>Envelope created, Signature request sent!</h2>" +
            "<p>Envelope ID: " + envelope_id + "</p>" +
            "<p>Signer: " + ds_signer1_name + "</p>" +
            "<p>CC: " + ds_cc1_name + "</p>")
    if webhook_instructions:
        html += (
            "<h2>Next steps:</h2>" +
            webhook_instructions +
            "<h3>2. Sign the envelope</h3>")
    else:
        html += "<h2>Next step:</h2>"

    ds_signer1_email_access = ds_recipe_lib.get_temp_email_access(ds_signer1_email)
    if (ds_signer1_email_access):
        # A temp account was used for the email
        html += "<p>Respond to the request via your mobile phone by using the QR code: </p>" + \
                "<p>" + ds_recipe_lib.get_temp_email_access_qrcode(ds_signer1_email_access) + "</p>" + \
                "<p> or via <a target='_blank' href='" + ds_signer1_email_access + "'>your web browser.</a></p>"
        #html += ("<p>View and respond to the request by opening " +
        #        "<a target='_blank' href='http://mailinator.com'>mailinator.com</a></p>" +
        #        "<p>Then enter mailbox id " + ds_recipe_lib.get_temp_email_access_id(ds_signer1_email) + "</p>")
    else:
        # A regular email account was used
        html += "<p>Respond to the request via your mobile phone or other mail tool.</p>" + \
                "<p>The email was sent to " + ds_signer1_name + " &lt;" + ds_signer1_email + "&gt;</p>"

    return {
        "err": False,
        "envelope_id": envelope_id,
        "ds_signer1_email": ds_signer1_email,
        "ds_signer1_name": ds_signer1_name,
        "ds_signer1_access": ds_signer1_email_access,
        "ds_signer1_qr": ds_signer1_email,
        "ds_cc1_email": ds_cc1_email,
        "ds_cc1_name": ds_cc1_name,
        "html": html
    }
Beispiel #18
0
def send():
    """Sends the envelope

    Returns r: {
        err: False, or an error message
        html: html output, to be displayed
        envelope_id:
        }
    """

    # Ready...
    # Possibly create some fake people
    ds_signer1_email = ds_recipe_lib.get_signer_email(ds_signer1_email_orig)
    ds_signer1_name = ds_recipe_lib.get_signer_name(ds_signer1_name_orig)
    ds_cc1_email = ds_recipe_lib.get_signer_email(ds_cc1_email_orig)
    ds_cc1_name = ds_recipe_lib.get_signer_name(ds_cc1_name_orig)

    # STEP 1 - Fetch Authentication information from session
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    #
    # STEP 2 - Create and send envelope
    #

    # construct the body of the request
    file_contents = open(doc_document_path, "rb").read()

    # Please use the most accurate and relevant subject line.
    subject = "Please sign the NDA package"
    # File contents are provided here
    # The documents array can include multiple documents, of differing types.
    # All documents are converted to pdf prior to signing.
    # The fileExtension field defaults to "pdf".
    documents = [{"documentId": "1",
            "name": doc_document_name,
            "fileExtension": os.path.splitext(doc_document_path)[1][1:],
            "documentBase64": base64.b64encode(file_contents)}
        ]

    # The signing fields
    #
    # Invisible (white) Anchor field names for the NDA.pdf document:
    #   * signer1sig
    #   * signer1name
    #   * signer1company
    #   * signer1date
    #
    fields = {
    "signHereTabs": [{
        "anchorString": "signer1sig", # Anchored for doc 1
        "anchorXOffset": "0",
        "anchorYOffset": "0",
        "anchorUnits": "mms",
        "recipientId": "1",
        "name": "Please sign here",
        "optional": "false",
        "scaleValue": 1,
        "tabLabel": "signer1sig"}],
    "fullNameTabs": [{
        "anchorString": "signer1name", # Anchored for doc 1
        "anchorYOffset": "-6",
        "fontSize": "Size12",
        "recipientId": "1",
        "tabLabel": "Full Name",
        "name": "Full Name"}],
    "textTabs": [{
        "anchorString": "signer1company", # Anchored for doc 1
        "anchorYOffset": "-8",
        "fontSize": "Size12",
        "recipientId": "1",
        "tabLabel": "Company",
        "name": "Company",
        "required": "true"}],
    "dateSignedTabs": [{
        "anchorString": "signer1date", # Anchored for doc 1
        "anchorYOffset": "-6",
        "fontSize": "Size12",
        "recipientId": "1",
        "name": "Date Signed",
        "tabLabel": "date_signed"}]
    }

    signers = [{"email": ds_signer1_email,
                "name": ds_signer1_name,
                "recipientId": "1",
                "routingOrder": "1",
                "tabs": fields}]

    ccs = [{"email": ds_cc1_email,
                "name": ds_cc1_name,
                "recipientId": "2",
                "routingOrder": "2"}]

    data = {"emailSubject": subject,
        "documents": documents,
        "recipients": {"signers": signers, "carbonCopies": ccs},
        "status": "sent"
    }

    eventNotification = ds_webhook.get_eventNotification_object()
    if eventNotification:
        data["eventNotification"] = eventNotification

    # append "/envelopes" to the baseUrl and use in the request
    url = auth["base_url"] + "/envelopes"
    ds_headers = {'Accept': 'application/json', auth["auth_header_key"]: auth["auth_header_value"],
                  trace_key: trace_value}

    try:
        r = requests.post(url, headers=ds_headers, json=data)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling Envelopes:create: " + str(e)}

    status = r.status_code
    if (status != 201):
        return ({'err': "Error calling DocuSign Envelopes:create<br/>Status is: " +
            str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"})

    data = r.json()
    envelope_id = data['envelopeId']
    session['latest_envelope_id'] = envelope_id # Save for other recipe's use

    # Instructions for reading the email
    webhook_instructions = ds_webhook.webhook_instructions(envelope_id)
    html =  ("<h2>Envelope created, Signature request sent!</h2>" +
            "<p>Envelope ID: " + envelope_id + "</p>" +
            "<p>Signer: " + ds_signer1_name + "</p>" +
            "<p>CC: " + ds_cc1_name + "</p>")
    if webhook_instructions:
        html += (
            "<h2>Next steps:</h2>" +
            webhook_instructions +
            "<h3>2. Sign the envelope</h3>")
    else:
        html += "<h2>Next step:</h2>"

    ds_signer1_email_access = ds_recipe_lib.get_temp_email_access(ds_signer1_email)
    if (ds_signer1_email_access):
        # A temp account was used for the email
        html += "<p>Respond to the request via your mobile phone by using the QR code: </p>" + \
                "<p>" + ds_recipe_lib.get_temp_email_access_qrcode(ds_signer1_email_access) + "</p>" + \
                "<p> or via <a target='_blank' href='" + ds_signer1_email_access + "'>your web browser.</a></p>"
        #html += ("<p>View and respond to the request by opening " +
        #        "<a target='_blank' href='http://mailinator.com'>mailinator.com</a></p>" +
        #        "<p>Then enter mailbox id " + ds_recipe_lib.get_temp_email_access_id(ds_signer1_email) + "</p>")
    else:
        # A regular email account was used
        html += "<p>Respond to the request via your mobile phone or other mail tool.</p>" + \
                "<p>The email was sent to " + ds_signer1_name + " &lt;" + ds_signer1_email + "&gt;</p>"

    return {
        "err": False,
        "envelope_id": envelope_id,
        "ds_signer1_email": ds_signer1_email,
        "ds_signer1_name": ds_signer1_name,
        "ds_signer1_access": ds_signer1_email_access,
        "ds_signer1_qr": ds_signer1_email,
        "ds_cc1_email": ds_cc1_email,
        "ds_cc1_name": ds_cc1_name,
        "html": html
    }
Beispiel #19
0
def start():
    """Sends Envelopes: listStatusChanges method

    Returns r: {
        err: False, or an error message
        intro: html introduction to the page
        url: the url used for the request
        response: the response body
        }
    """

    # Ready...

    # STEP 1 - Fetch Authentication information from session
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    #
    # STEP 2 - Create and send the request
    #

    # See the docs, https://docs.docusign.com/esign/restapi/Envelopes/Envelopes/listStatusChanges/
    # We need to set one or more of the following parameters: from_date, envelopeIds and/or transactionIds.
    # We will set from_date to be yesterday.
    #
    # If you're using this method to poll for changes, see "Polling for Current Status" section of
    # page https://docs.docusign.com/esign/guide/usage/status_and_events.html for a strategy that won't
    # violate the platform's polling policy.

    # construct the body of the request
    yesterday = datetime.date.today() - datetime.timedelta(days=1)
    yesterday_s = yesterday.strftime("%Y-%m-%d")  # '2016-07-25'

    # create the url from the baseUrl
    url = auth["base_url"] + "/envelopes?from_date={}".format(yesterday_s)
    ds_headers = {
        'Accept': 'application/json',
        auth["auth_header_key"]: auth["auth_header_value"],
        trace_key: trace_value
    }

    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling Envelopes:listStatusChanges: " + str(e)}

    status = r.status_code
    if (status != 200):
        return ({
            'err':
            "Error calling DocuSign Envelopes:listStatusChanges<br/>Status is: "
            + str(status) + ". Response: <pre><code>" + r.text +
            "</code></pre>"
        })

    response = r.json()
    return {
        "err": False,
        "url": url,
        "intro": intro,
        "response": json.dumps(response, indent=4, sort_keys=True)
    }
def send():
    """Sends the envelope from a template

    Parameters:
        template_name
        company_name

    Returns r: {
        err: False, or an error message
        html: html output, to be displayed
        envelope_id:
        }
    """

    # Ready...
    # Possibly create some fake people
    ds_signer1_email = ds_recipe_lib.get_signer_email(ds_signer1_email_orig)
    ds_signer1_name = ds_recipe_lib.get_signer_name(ds_signer1_name_orig)
    ds_cc1_email = ds_recipe_lib.get_signer_email(ds_cc1_email_orig)
    ds_cc1_name = ds_recipe_lib.get_signer_name(ds_cc1_name_orig)

    # STEP 1 - Fetch Authentication information from session
    auth = ds_authentication.get_auth()
    if auth["err"]:
        return {"err": auth["err"], "err_code": auth["err_code"]}

    #
    # STEP 2 - lookup the template
    #
    template_name = request.form.get('template_name')
    company_name = request.form.get('company_name')
    if not template_name:
        return {"err": "Please fill in a template name"}
    if not company_name:
        return {"err": "Please fill in a company name"}

    # Templates: list. See https://docs.docusign.com/esign/restapi/Templates/Templates/list/
    url = auth["base_url"] + "/templates?" + "search_text={}".format(
        urllib.quote(template_name))
    ds_headers = {
        'Accept': 'application/json',
        auth["auth_header_key"]: auth["auth_header_value"],
        trace_key: trace_value
    }
    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling Templates:list: " + str(e)}

    status = r.status_code
    if (status != 200):
        return ({
            'err':
            "Error calling DocuSign Templates:list<br/>Status is: " +
            str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"
        })

    data = r.json()
    if data["resultSetSize"] == "0":
        return {
            "err":
            "No Templates with title {} were found.".format(template_name)
        }

    # Use the first template_id in the results
    template_id = data["envelopeTemplates"][0]["templateId"]

    # When we create the envelope, we want to set the text tag with the company name value.
    # To set a value, we need the tab's "tabLabel". If it were an agreed value with the person
    # who created the tab, that'd be fine. For the purpose of this example, we'll be more
    # flexible: we'll get the details on the template, and then assume that the first text tab
    # is the company tab. You wouldn't want to do this in production since someone might add
    # an additional text tab to the template, which would break the integration.

    # Use the Templates: get method to retrieve full info about the template.
    # See https://docs.docusign.com/esign/restapi/Templates/Templates/get/
    url = auth["base_url"] + "/templates/{}".format(urllib.quote(template_id))
    ds_headers = {
        'Accept': 'application/json',
        auth["auth_header_key"]: auth["auth_header_value"],
        trace_key: trace_value
    }
    try:
        r = requests.get(url, headers=ds_headers)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling Templates:list: " + str(e)}

    status = r.status_code
    if (status != 200):
        return ({
            'err':
            "Error calling DocuSign Templates:list<br/>Status is: " +
            str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"
        })

    data = r.json()
    company_tabLabel = data["recipients"]["signers"][0]["tabs"]["textTabs"][0][
        "tabLabel"]

    #
    # STEP 3 - Create and send envelope
    #
    # Since we're using a template, this request is relatively small
    # The signer and cc role names must be in agreement with the template's settings
    template_role_signer_1 = {
        "roleName": signer1_role,
        "email": ds_signer1_email,
        "name": ds_signer1_name,
        "tabs": {
            "textTabs": [{
                "tabLabel": company_tabLabel,
                "value": company_name
            }]
        }
    }
    template_role_cc = {
        "roleName": cc_role,
        "email": ds_cc1_email,
        "name": ds_cc1_name
    }
    data = {
        "templateId": template_id,
        "templateRoles": [template_role_signer_1, template_role_cc],
        "status": "sent"
    }
    eventNotification = ds_webhook.get_eventNotification_object()
    if eventNotification:
        data["eventNotification"] = eventNotification

    # append "/envelopes" to the baseUrl and use in the request
    url = auth["base_url"] + "/envelopes"
    ds_headers = {
        'Accept': 'application/json',
        auth["auth_header_key"]: auth["auth_header_value"],
        trace_key: trace_value
    }
    try:
        r = requests.post(url, headers=ds_headers, json=data)
    except requests.exceptions.RequestException as e:
        return {'err': "Error calling Envelopes:create: " + str(e)}

    status = r.status_code
    if (status != 201):
        return ({
            'err':
            "Error calling DocuSign Envelopes:create<br/>Status is: " +
            str(status) + ". Response: <pre><code>" + r.text + "</code></pre>"
        })

    data = r.json()
    envelope_id = data['envelopeId']
    session['latest_envelope_id'] = envelope_id  # Save for other recipe's use

    # Instructions for reading the email
    webhook_instructions = ds_webhook.webhook_instructions(envelope_id)
    html = ("<h2>Envelope created, Signature request sent!</h2>" +
            "<p>Envelope ID: " + envelope_id + "</p>" + "<p>Signer: " +
            ds_signer1_name + "</p>" + "<p>CC: " + ds_cc1_name + "</p>")
    if webhook_instructions:
        html += ("<h2>Next steps:</h2>" + webhook_instructions +
                 "<h3>2. Sign the envelope</h3>")
    else:
        html += "<h2>Next step:</h2>"

    ds_signer1_email_access = ds_recipe_lib.get_temp_email_access(
        ds_signer1_email)
    if (ds_signer1_email_access):
        # A temp account was used for the email
        html += "<p>Respond to the request via your mobile phone by using the QR code: </p>" + \
                "<p>" + ds_recipe_lib.get_temp_email_access_qrcode(ds_signer1_email_access) + "</p>" + \
                "<p> or via <a target='_blank' href='" + ds_signer1_email_access + "'>your web browser.</a></p>"
        #html += ("<p>View and respond to the request by opening " +
        #        "<a target='_blank' href='http://mailinator.com'>mailinator.com</a></p>" +
        #        "<p>Then enter mailbox id " + ds_recipe_lib.get_temp_email_access_id(ds_signer1_email) + "</p>")
    else:
        # A regular email account was used
        html += "<p>Respond to the request via your mobile phone or other mail tool.</p>" + \
                "<p>The email was sent to " + ds_signer1_name + " &lt;" + ds_signer1_email + "&gt;</p>"

    return {
        "err": False,
        "envelope_id": envelope_id,
        "ds_signer1_email": ds_signer1_email,
        "ds_signer1_name": ds_signer1_name,
        "ds_signer1_access": ds_signer1_email_access,
        "ds_signer1_qr": ds_signer1_email,
        "ds_cc1_email": ds_cc1_email,
        "ds_cc1_name": ds_cc1_name,
        "html": html
    }