diff --git a/app/eSignature/examples/eg011_embedded_sending.py b/app/eSignature/examples/eg011_embedded_sending.py index ea5ef59..9e438eb 100644 --- a/app/eSignature/examples/eg011_embedded_sending.py +++ b/app/eSignature/examples/eg011_embedded_sending.py @@ -1,7 +1,10 @@ -from docusign_esign import EnvelopesApi, ReturnUrlRequest +import base64 +from os import path + +from docusign_esign import EnvelopesApi, ReturnUrlRequest, EnvelopesApi, EnvelopeDefinition, \ + Document, Signer, CarbonCopy, SignHere, Tabs, Recipients from flask import url_for, session, request -from .eg002_signing_via_email import Eg002SigningViaEmailController from ...consts import pattern, demo_docs_path from ...docusign import create_api_client @@ -24,7 +27,7 @@ def get_args(): "signer_name": signer_name, "cc_email": cc_email, "cc_name": cc_name, - "status": "sent", + "status": "created", } args = { "starting_view": starting_view, @@ -36,36 +39,196 @@ def get_args(): } return args - @staticmethod - def worker(args,doc_docx_path,doc_pdf_path): + @classmethod + def worker(cls, args, doc_docx_path, doc_pdf_path): """ This function does the work of creating the envelope in draft mode and returning a URL for the sender"s view """ # Step 2. Create the envelope with "created" (draft) status - args["envelope_args"]["status"] = "created" - # Using worker from example 002 - results = Eg002SigningViaEmailController.worker(args, doc_docx_path, doc_pdf_path) - envelope_id = results["envelope_id"] + envelope = cls.create_envelope(args, doc_docx_path, doc_pdf_path) + envelope_id = envelope.envelope_id # Step 3. Create the sender view + sender_view_url = cls.create_sender_view(args, envelope_id) + + return {"envelope_id": envelope_id, "redirect_url": sender_view_url} + + @classmethod + #ds-snippet-start:eSign11Step3 + def create_sender_view(cls, args, envelope_id): view_request = ReturnUrlRequest(return_url=args["ds_return_url"]) # Exceptions will be caught by the calling function - #ds-snippet-start:eSign11Step3 api_client = create_api_client(base_path=args["base_path"], access_token=args["access_token"]) envelope_api = EnvelopesApi(api_client) - results = envelope_api.create_sender_view( + sender_view = envelope_api.create_sender_view( account_id=args["account_id"], envelope_id=envelope_id, return_url_request=view_request ) # Switch to Recipient and Documents view if requested by the user - url = results.url + url = sender_view.url if args["starting_view"] == "recipient": url = url.replace("send=1", "send=0") - #ds-snippet-end:eSign13Step3 - return {"envelope_id": envelope_id, "redirect_url": url} + return url + #ds-snippet-end:eSign11Step3 + + @classmethod + #ds-snippet-start:eSign11Step2 + def create_envelope(cls, args, doc_docx_path, doc_pdf_path): + envelope_args = args["envelope_args"] + # Create the envelope request object + envelope_definition = cls.make_envelope(envelope_args, doc_docx_path, doc_pdf_path) + api_client = create_api_client(base_path=args["base_path"], access_token=args["access_token"]) + # Call Envelopes::create API method + # Exceptions will be caught by the calling function + envelopes_api = EnvelopesApi(api_client) + return envelopes_api.create_envelope(account_id=args["account_id"], envelope_definition=envelope_definition) + + @classmethod + def make_envelope(cls, args, doc_docx_path, doc_pdf_path): + """ + Creates envelope + Document 1: An HTML document. + Document 2: A Word .docx document. + Document 3: A PDF document. + DocuSign will convert all of the documents to the PDF format. + The recipients" field tags are placed using anchor strings. + """ + + # document 1 (html) has sign here anchor tag **signature_1** + # document 2 (docx) has sign here anchor tag /sn1/ + # document 3 (pdf) has sign here anchor tag /sn1/ + # + # The envelope has two recipients. + # recipient 1 - signer + # recipient 2 - cc + # The envelope will be sent first to the signer. + # After it is signed, a copy is sent to the cc person. + + # create the envelope definition + env = EnvelopeDefinition( + email_subject="Please sign this document set" + ) + doc1_b64 = base64.b64encode(bytes(cls.create_document1(args), "utf-8")).decode("ascii") + # read files 2 and 3 from a local directory + # The reads could raise an exception if the file is not available! + with open(path.join(demo_docs_path, doc_docx_path), "rb") as file: + doc2_docx_bytes = file.read() + doc2_b64 = base64.b64encode(doc2_docx_bytes).decode("ascii") + with open(path.join(demo_docs_path, doc_pdf_path), "rb") as file: + doc3_pdf_bytes = file.read() + doc3_b64 = base64.b64encode(doc3_pdf_bytes).decode("ascii") + + # Create the document models + document1 = Document( # create the DocuSign document object + document_base64=doc1_b64, + name="Order acknowledgement", # can be different from actual file name + file_extension="html", # many different document types are accepted + document_id="1" # a label used to reference the doc + ) + document2 = Document( # create the DocuSign document object + document_base64=doc2_b64, + name="Battle Plan", # can be different from actual file name + file_extension="docx", # many different document types are accepted + document_id="2" # a label used to reference the doc + ) + document3 = Document( # create the DocuSign document object + document_base64=doc3_b64, + name="Lorem Ipsum", # can be different from actual file name + file_extension="pdf", # many different document types are accepted + document_id="3" # a label used to reference the doc + ) + # The order in the docs array determines the order in the envelope + env.documents = [document1, document2, document3] + + # Create the signer recipient model + signer1 = Signer( + email=args["signer_email"], + name=args["signer_name"], + recipient_id="1", + routing_order="1" + ) + # routingOrder (lower means earlier) determines the order of deliveries + # to the recipients. Parallel routing order is supported by using the + # same integer as the order for two or more recipients. + + # create a cc recipient to receive a copy of the documents + cc1 = CarbonCopy( + email=args["cc_email"], + name=args["cc_name"], + recipient_id="2", + routing_order="2" + ) + + # Create signHere fields (also known as tabs) on the documents, + # We"re using anchor (autoPlace) positioning + # + # The DocuSign platform searches throughout your envelope"s + # documents for matching anchor strings. So the + # signHere2 tab will be used in both document 2 and 3 since they + # use the same anchor string for their "signer 1" tabs. + sign_here1 = SignHere( + anchor_string="**signature_1**", + anchor_units="pixels", + anchor_y_offset="10", + anchor_x_offset="20" + ) + + sign_here2 = SignHere( + anchor_string="/sn1/", + anchor_units="pixels", + anchor_y_offset="10", + anchor_x_offset="20" + ) + + # Add the tabs model (including the sign_here tabs) to the signer + # The Tabs object wants arrays of the different field/tab types + signer1.tabs = Tabs(sign_here_tabs=[sign_here1, sign_here2]) + + # Add the recipients to the envelope object + recipients = Recipients(signers=[signer1], carbon_copies=[cc1]) + env.recipients = recipients + + # Request that the envelope be sent by setting |status| to "sent". + # To request that the envelope be created as a draft, set to "created" + env.status = args["status"] + + return env + + @classmethod + def create_document1(cls, args): + """ Creates document 1 -- an html document""" + + return f""" + + +
+ + + +Email: {args["signer_email"]}
+Copy to: {args["cc_name"]}, {args["cc_email"]}
++ Candy bonbon pastry jujubes lollipop wafer biscuit biscuit. Topping brownie sesame snaps sweet roll pie. + Croissant danish biscuit soufflé caramels jujubes jelly. Dragée danish caramels lemon drops dragée. + Gummi bears cupcake biscuit tiramisu sugar plum pastry. Dragée gummies applicake pudding liquorice. + Donut jujubes oat cake jelly-o. + Dessert bear claw chocolate cake gummies lollipop sugar plum ice cream gummies cheesecake. +
+ +