Skip to content

Commit a059a6a

Browse files
author
Olena Harkusha
committed
Add using conditional recipients example
1 parent ad604e6 commit a059a6a

8 files changed

Lines changed: 645 additions & 149 deletions

File tree

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,15 @@ This repo is a Python 3 application that demonstrates:
114114
[Create Bulk Send Request](https://developers.docusign.com/esign-rest-api/reference/BulkEnvelopes/BulkSend/createBulkSendRequest).
115115
Firstly, creates a bulk send recipients list, and then creates an envelope.
116116
After that, initiates bulk envelope sending.
117-
1. **Pause a signature workflow**
117+
1. **Pausing a signature workflow**
118118
[Source.](./app/eSignature/examples/eg032_pause_signature_workflow/controller.py)
119119
This code example demonstrates how to create an envelope where the workflow is paused before the envelope is sent to a second recipient.
120-
1. **Unpause a signature workflow**
120+
1. **Unpausing a signature workflow**
121121
[Source.](./app/eSignature/examples/eg033_unpause_signature_workflow/controller.py)
122122
This code example demonstrates how to resume an envelope workflow that has been paused.
123+
1. **Using conditional recipients**
124+
[Source.](./app/eSignature/examples/eg034_use_conditional_recipients/controller.py)
125+
This code example demonstrates how to create an envelope where the workflow is routed to different recipients based on the value of a transaction.
123126

124127

125128
## Rooms API

app/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
app.register_blueprint(examples.eg031)
7575
app.register_blueprint(examples.eg032)
7676
app.register_blueprint(examples.eg033)
77+
app.register_blueprint(examples.eg034)
7778

7879
if "DYNO" in os.environ: # On Heroku?
7980
import logging

app/eSignature/examples/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@
3131
from .eg031_bulk_send import eg031
3232
from .eg032_pause_signature_workflow import eg032
3333
from .eg033_unpause_signature_workflow import eg033
34+
from .eg034_use_conditional_recipients import eg034
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .views import eg034
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
import base64
2+
from os import path
3+
4+
from docusign_esign import (
5+
Checkbox, EnvelopesApi, EnvelopeDefinition, Document, Signer, SignHere,
6+
Tabs, Recipients
7+
)
8+
from docusign_esign.models import (
9+
ConditionalRecipientRule, ConditionalRecipientRuleCondition,
10+
ConditionalRecipientRuleFilter, RecipientGroup,
11+
RecipientOption, RecipientRouting, RecipientRules, Workflow, WorkflowStep
12+
)
13+
from flask import session, request
14+
15+
from ....consts import demo_docs_path, pattern
16+
from ....docusign import create_api_client
17+
from ....ds_config import DS_CONFIG
18+
19+
20+
class Eg034Controller:
21+
@staticmethod
22+
def get_args():
23+
"""Get request and session arguments"""
24+
25+
# Strip anything other than characters listed
26+
signer1_email = pattern.sub("", request.form.get("signer1_email"))
27+
signer1_name = pattern.sub("", request.form.get("signer1_name"))
28+
signer_2a_email = pattern.sub("", request.form.get("signer_2a_email"))
29+
signer_2a_name = pattern.sub("", request.form.get("signer_2a_name"))
30+
signer_2b_email = pattern.sub("", request.form.get("signer_2b_email"))
31+
signer_2b_name = pattern.sub("", request.form.get("signer_2b_name"))
32+
envelope_args = {
33+
"signer1_email": signer1_email,
34+
"signer1_name": signer1_name,
35+
"signer_2a_email": signer_2a_email,
36+
"signer_2a_name": signer_2a_name,
37+
"signer_2b_email": signer_2b_email,
38+
"signer_2b_name": signer_2b_name,
39+
"status": "Sent",
40+
}
41+
args = {
42+
"account_id": session["ds_account_id"],
43+
"base_path": session["ds_base_path"],
44+
"access_token": session["ds_access_token"],
45+
"envelope_args": envelope_args
46+
}
47+
return args
48+
49+
@classmethod
50+
def worker(cls, args):
51+
"""
52+
1. Create the envelope request object
53+
2. Send the envelope
54+
"""
55+
56+
envelope_args = args["envelope_args"]
57+
# 1. Create the envelope request object
58+
envelope_definition = cls.make_envelope(envelope_args)
59+
api_client = create_api_client(
60+
base_path=args["base_path"], access_token=args["access_token"]
61+
)
62+
# 2. call Envelopes::create API method
63+
# Exceptions will be caught by the calling function
64+
envelopes_api = EnvelopesApi(api_client)
65+
results = envelopes_api.create_envelope(
66+
account_id=args["account_id"],
67+
envelope_definition=envelope_definition
68+
)
69+
70+
return {"envelope_id": results.envelope_id}
71+
72+
@classmethod
73+
def make_envelope(cls, args):
74+
"""
75+
Creates envelope
76+
Document: A txt document.
77+
DocuSign will convert document to the PDF format.
78+
"""
79+
80+
# The envelope has two recipients.
81+
# recipient 1 - signer1
82+
# recipient 2 - signer2
83+
# The envelope will be sent first to the signer1.
84+
# After it is signed, a signature workflow will be paused.
85+
# After resuming (unpause) the signature workflow will send to the second recipient.
86+
87+
# create the envelope definition
88+
env = EnvelopeDefinition(email_subject="ApproveIfChecked")
89+
90+
# read file from a local directory
91+
# The reads could raise an exception if the file is not available!
92+
with open(path.join(demo_docs_path, DS_CONFIG["doc_txt"]),
93+
"rb") as file:
94+
doc_docx_bytes = file.read()
95+
doc_b64 = base64.b64encode(doc_docx_bytes).decode("ascii")
96+
97+
# Create the document model.
98+
document = Document( # create the DocuSign document object
99+
document_base64=doc_b64,
100+
name="Welcome", # can be different from actual file name
101+
file_extension="txt", # many different document types are accepted
102+
document_id="1" # a label used to reference the doc
103+
)
104+
105+
# The order in the docs array determines the order in the envelope.
106+
env.documents = [document, ]
107+
108+
# Create the signer model
109+
# routingOrder (lower means earlier) determines the order of deliveries
110+
# to the recipients.
111+
signer1 = Signer(
112+
email=args["signer1_email"],
113+
name=args["signer1_name"],
114+
recipient_id="1",
115+
routing_order="1",
116+
role_name="Purchaser"
117+
)
118+
# signer2 = Signer(
119+
# email="gravecapa@gmail.com",
120+
# name="Alpaca",
121+
# recipient_id="2",
122+
# routing_order="2",
123+
# role_name="Approver"
124+
# )
125+
126+
# Create signHere fields (also known as tabs) on the documents.
127+
sign_here1 = SignHere(
128+
document_id="1",
129+
page_number="1",
130+
name="SignHere",
131+
tab_label="PurchaserSignature",
132+
x_position="200",
133+
y_position="200"
134+
)
135+
sign_here2 = SignHere(
136+
document_id="1",
137+
page_number="1",
138+
name="SignHere",
139+
recipient_id="2",
140+
tab_label="ApproverSignature",
141+
x_position="300",
142+
y_position="200"
143+
)
144+
145+
checkbox = Checkbox(
146+
document_id="1",
147+
page_number="1",
148+
name="ClickToApprove",
149+
selected="false",
150+
tab_label="ApproveWhenChecked",
151+
x_position="50",
152+
y_position="50"
153+
)
154+
#
155+
# Add the tabs model (including the sign_here tabs) to the signer
156+
# The Tabs object wants arrays of the different field/tab types
157+
signer1.tabs = Tabs(
158+
sign_here_tabs=[sign_here1, ],
159+
checkbox_tabs=[checkbox, ]
160+
)
161+
# signer2.tabs = Tabs(sign_here_tabs=[sign_here2, ])
162+
163+
# Add the recipients to the envelope object
164+
env_recipients = Recipients(signers=[signer1, ])
165+
# recipients = Recipients(signers=[signer1, signer2])
166+
env.recipients = env_recipients
167+
168+
# !!!!!!!! Create RecipientRouting model.
169+
signer_2a = RecipientOption(
170+
email=args["signer_2a_email"],
171+
name=args["signer_2a_name"],
172+
role_name="Signer when not checked",
173+
recipient_label="signer2a"
174+
)
175+
176+
signer_2b = RecipientOption(
177+
email=args["signer_2b_email"],
178+
name=args["signer_2b_name"],
179+
role_name="Signer when checked",
180+
recipient_label="signer2b"
181+
)
182+
recipients = [signer_2a, signer_2b]
183+
recipient_group = RecipientGroup(
184+
group_name="Approver",
185+
group_message="Members of this group approve a workflow",
186+
recipients=recipients
187+
)
188+
189+
filter1 = ConditionalRecipientRuleFilter(
190+
scope="tabs",
191+
recipient_id="1",
192+
tab_id="ApprovalTab",
193+
operator="equals",
194+
value="false",
195+
tab_label="ApproveWhenChecked"
196+
)
197+
filter2 = ConditionalRecipientRuleFilter(
198+
scope="tabs",
199+
recipient_id="1",
200+
tab_id="ApprovalTab",
201+
operator="equals",
202+
value="true",
203+
tab_label="ApproveWhenChecked"
204+
)
205+
206+
condition1 = ConditionalRecipientRuleCondition(
207+
filters=[filter1, ],
208+
order="1",
209+
recipient_label="signer2a"
210+
)
211+
condition2 = ConditionalRecipientRuleCondition(
212+
filters=[filter2, ],
213+
order="2",
214+
recipient_label="signer2b"
215+
)
216+
conditions = [condition1, condition2]
217+
conditional_recipient = ConditionalRecipientRule(
218+
conditions=conditions,
219+
recipient_group=recipient_group,
220+
recipient_id="2",
221+
order="0",
222+
223+
)
224+
rules = RecipientRules(conditional_recipients=[conditional_recipient, ])
225+
recipient_routing = RecipientRouting(rules=rules)
226+
227+
# Create a workflow model.
228+
# Signature workflow will be paused after it is signed by the signer1.
229+
workflow_step = WorkflowStep(
230+
action="pause_before",
231+
trigger_on_item="routing_order",
232+
item_id="2",
233+
status="pending",
234+
recipient_routing=recipient_routing
235+
)
236+
237+
workflow = Workflow(workflow_steps=[workflow_step, ])
238+
# Add the workflow to the envelope object
239+
env.workflow = workflow
240+
241+
# Request that the envelope be sent by setting |status| to "sent".
242+
# To request that the envelope be created as a draft, set to "created"
243+
env.status = args["status"]
244+
return env
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
""" Example 034: Creating an envelope where the workflow is routed
2+
to different recipients based on the value of a transaction """
3+
4+
from os import path
5+
6+
from docusign_esign.client.api_exception import ApiException
7+
from flask import render_template, session, Blueprint
8+
9+
from .controller import Eg034Controller
10+
from ....docusign import authenticate
11+
from ....ds_config import DS_CONFIG
12+
from ....error_handlers import process_error
13+
14+
eg = "eg034" # reference (and url) for this example
15+
eg034 = Blueprint("eg034", __name__)
16+
17+
18+
@eg034.route("/eg034", methods=["POST"])
19+
@authenticate(eg=eg)
20+
def use_conditional_recipients():
21+
"""
22+
1. Get required arguments
23+
2. Call the worker method
24+
3. Render success response with envelopeId
25+
"""
26+
27+
# 1. Get required arguments
28+
args = Eg034Controller.get_args()
29+
try:
30+
# 1. Call the worker method
31+
results = Eg034Controller.worker(args)
32+
except ApiException as err:
33+
return process_error(err)
34+
35+
# 2. Render success response with envelopeId
36+
return render_template(
37+
"example_done.html",
38+
envelope_ok=True,
39+
title="Use conditional recipients",
40+
h1="Use conditional recipients",
41+
message=f"Envelope ID {results['envelope_id']} with the conditional"
42+
f" routing criteria has been created and sent to the first recipient!<br/>"
43+
)
44+
45+
46+
@eg034.route("/eg034", methods=["GET"])
47+
@authenticate(eg=eg)
48+
def get_view():
49+
"""responds with the form for the example"""
50+
51+
return render_template(
52+
"eg034_use_conditional_recipients.html",
53+
title="Using conditional recipients",
54+
source_file=path.basename(path.dirname(__file__)) + "/controller.py",
55+
source_url=DS_CONFIG["github_example_url"] + path.basename(path.dirname(__file__)) + "/controller.py",
56+
documentation=DS_CONFIG["documentation"] + eg,
57+
show_doc=DS_CONFIG["documentation"],
58+
signer1_name=DS_CONFIG["signer_name"],
59+
signer1_email=DS_CONFIG["signer_email"]
60+
)

0 commit comments

Comments
 (0)