1+ /**
2+ * @file
3+ * Example 017: Set template tab (field) values and an envelope custom field value
4+ * @author DocuSign
5+ */
6+
7+ const path = require ( 'path' )
8+ , docusign = require ( 'docusign-esign' )
9+ , validator = require ( 'validator' )
10+ , dsConfig = require ( '../../ds_configuration.js' ) . config
11+ ;
12+
13+ const eg017SetTemplateTabValues = exports
14+ , eg = 'eg017' // This example reference.
15+ , mustAuthenticate = '/ds/mustAuthenticate'
16+ , minimumBufferMin = 3
17+ ;
18+
19+
20+ /**
21+ * Send envelope with a template
22+ * @param {object } req Request obj
23+ * @param {object } res Response obj
24+ */
25+ eg017SetTemplateTabValues . createController = async ( req , res ) => {
26+ // Step 1. Check the token
27+ // At this point we should have a good token. But we
28+ // double-check here to enable a better UX to the user.
29+ let tokenOK = req . dsAuthCodeGrant . checkToken ( minimumBufferMin ) ;
30+ if ( ! tokenOK ) {
31+ req . flash ( 'info' , 'Sorry, you need to re-authenticate.' ) ;
32+ // We could store the parameters of the requested operation
33+ // so it could be restarted automatically.
34+ // But since it should be rare to have a token issue here,
35+ // we'll make the user re-enter the form data after
36+ // authentication.
37+ req . dsAuthCodeGrant . setEg ( req , eg ) ;
38+ res . redirect ( mustAuthenticate ) ;
39+ }
40+
41+ if ( ! req . session . templateId ) {
42+ res . render ( 'pages/examples/eg017SetTemplateTabValues' , {
43+ csrfToken : req . csrfToken ( ) ,
44+ title : "Send envelope using a template" ,
45+ templateOk : req . session . templateId ,
46+ sourceFile : path . basename ( __filename ) ,
47+ sourceUrl : dsConfig . githubExampleUrl + path . basename ( __filename ) ,
48+ documentation : dsConfig . documentation + eg ,
49+ showDoc : dsConfig . documentation
50+ } ) ;
51+ }
52+
53+ // Step 2. Call the worker method
54+ let body = req . body
55+ // Additional data validation might also be appropriate
56+ , signerEmail = validator . escape ( body . signerEmail )
57+ , signerName = validator . escape ( body . signerName )
58+ , ccEmail = validator . escape ( body . ccEmail )
59+ , ccName = validator . escape ( body . ccName )
60+ , envelopeArgs = {
61+ templateId : req . session . templateId ,
62+ signerEmail : signerEmail ,
63+ signerName : signerName ,
64+ signerClientId : 1000 ,
65+ ccEmail : ccEmail ,
66+ ccName : ccName ,
67+ dsReturnUrl : dsConfig . appUrl + '/ds-return'
68+ }
69+ , args = {
70+ accessToken : req . user . accessToken ,
71+ basePath : req . session . basePath ,
72+ accountId : req . session . accountId ,
73+ envelopeArgs : envelopeArgs
74+ }
75+ , results = null
76+ ;
77+
78+ try {
79+ results = await eg017SetTemplateTabValues . worker ( args )
80+ }
81+ catch ( error ) {
82+ let errorBody = error && error . response && error . response . body
83+ // we can pull the DocuSign error code and message from the response body
84+ , errorCode = errorBody && errorBody . errorCode
85+ , errorMessage = errorBody && errorBody . message
86+ ;
87+ // In production, may want to provide customized error messages and
88+ // remediation advice to the user.
89+ res . render ( 'pages/error' , { err : error , errorCode : errorCode , errorMessage : errorMessage } ) ;
90+ }
91+ if ( results ) {
92+ req . session . envelopeId = results . envelopeId ; // Save for use by other examples
93+ // which need an envelopeId
94+ // Redirect the user to the Signing Ceremony
95+ // Don't use an iFrame!
96+ // State can be stored/recovered using the framework's session or a
97+ // query parameter on the returnUrl (see the makeRecipientViewRequest method)
98+ res . redirect ( results . redirectUrl ) ;
99+ }
100+ }
101+
102+ /**
103+ * This function does the work of creating the envelope
104+ * @param {object } args
105+ */
106+ // ***DS.worker.start ***DS.snippet.1.start
107+ eg017SetTemplateTabValues . worker = async ( args ) => {
108+ // 1. Create envelope definition
109+ let envelopeArgs = args . envelopeArgs
110+ , envelopeDefinition = makeEnvelope ( envelopeArgs ) ;
111+
112+ // 2. Create the envelope
113+ let dsApiClient = new docusign . ApiClient ( ) ;
114+ dsApiClient . setBasePath ( args . basePath ) ;
115+ dsApiClient . addDefaultHeader ( 'Authorization' , 'Bearer ' + args . accessToken ) ;
116+ let envelopesApi = new docusign . EnvelopesApi ( dsApiClient )
117+ , results = await envelopesApi . createEnvelope (
118+ args . accountId , { envelopeDefinition : envelopeDefinition } )
119+ , envelopeId = results . envelopeId
120+ ;
121+
122+ // 3. create the recipient view, the Signing Ceremony
123+ let viewRequest = docusign . RecipientViewRequest . constructFromObject ( {
124+ returnUrl : envelopeArgs . dsReturnUrl ,
125+ authenticationMethod : 'none' ,
126+ email : envelopeArgs . signerEmail ,
127+ userName : envelopeArgs . signerName ,
128+ clientUserId : envelopeArgs . signerClientId } ) ;
129+
130+ // 4. Call the CreateRecipientView API
131+ // Exceptions will be caught by the calling function
132+ results = await envelopesApi . createRecipientView ( args . accountId , envelopeId ,
133+ { recipientViewRequest : viewRequest } ) ;
134+
135+ return ( { envelopeId : envelopeId , redirectUrl : results . url } )
136+ }
137+ // ***DS.worker.end ***DS.snippet.1.end
138+
139+ // ***DS.snippet.2.start
140+ /**
141+ * Creates envelope from the template
142+ * @function
143+ * @param {Object } args
144+ * @returns {Envelope } An envelope definition
145+ * @private
146+ */
147+ function makeEnvelope ( args ) {
148+ // The envelope has two recipients.
149+ // recipient 1 - signer
150+ // recipient 2 - cc
151+ // This method sets values for many of the template's tabs.
152+ // It also adds a new tab, and adds a custom metadata field
153+
154+ // create the envelope definition with the template id
155+ let envelopeDefinition = docusign . EnvelopeDefinition . constructFromObject ( {
156+ templateId : args . templateId , status : 'sent'
157+ } ) ;
158+
159+ // Set the values for the fields in the template
160+ // List item
161+ let list1 = docusign . List . constructFromObject ( {
162+ value : "green" , documentId : "1" , pageNumber : "1" , tabLabel : "list" } ) ;
163+
164+ // Checkboxes
165+ let check1 = docusign . Checkbox . constructFromObject ( {
166+ tabLabel : 'ckAuthorization' , selected : "true" } )
167+ , check3 = docusign . Checkbox . constructFromObject ( {
168+ tabLabel : 'ckAgreement' , selected : "true" } ) ;
169+ // The NOde.js SDK has a bug so it cannot create a Number tab at this time.
170+ //number1 = docusign.Number.constructFromObject({
171+ // tabLabel: "numbersOnly", value: '54321' });
172+ let radioGroup = docusign . RadioGroup . constructFromObject ( {
173+ groupName : "radio1" ,
174+ // You only need to provide the radio entry for the entry you're selecting
175+ radios :
176+ [ docusign . Radio . constructFromObject ( { value : "white" , selected : "true" } ) ]
177+ } ) ;
178+ let text = docusign . Text . constructFromObject ( {
179+ tabLabel : "text" , value : "Jabberwocky!" } ) ;
180+
181+ // We can also add a new tab (field) to the ones already in the template:
182+ let textExtra = docusign . Text . constructFromObject ( {
183+ document_id : "1" , page_number : "1" ,
184+ x_position : "280" , y_position : "172" ,
185+ font : "helvetica" , font_size : "size14" , tab_label : "added text field" ,
186+ height : "23" , width : "84" , required : "false" ,
187+ bold : 'true' , value : args . signerName ,
188+ locked : 'false' , tab_id : 'name' } ) ;
189+
190+ // Pull together the existing and new tabs in a Tabs object:
191+ let tabs = docusign . Tabs . constructFromObject ( {
192+ checkboxTabs : [ check1 , check3 ] , // numberTabs: [number1],
193+ radioGroupTabs : [ radioGroup ] , textTabs : [ text , textExtra ] ,
194+ listTabs : [ list1 ]
195+ } ) ;
196+ // Create the template role elements to connect the signer and cc recipients
197+ // to the template
198+ let signer = docusign . TemplateRole . constructFromObject ( {
199+ email : args . signerEmail , name : args . signerName ,
200+ roleName : 'signer' ,
201+ clientUserId : args . signerClientId , // change the signer to be embedded
202+ tabs : tabs // Set tab values
203+ } ) ;
204+ // Create a cc template role.
205+ let cc = docusign . TemplateRole . constructFromObject ( {
206+ email : args . ccEmail , name : args . ccName ,
207+ roleName : 'cc'
208+ } ) ;
209+ // Add the TemplateRole objects to the envelope object
210+ envelopeDefinition . templateRoles = [ signer , cc ] ;
211+ // Create an envelope custom field to save the our application's
212+ // data about the envelope
213+ let customField = docusign . TextCustomField . constructFromObject ( {
214+ name : 'app metadata item' ,
215+ required : 'false' ,
216+ show : 'true' , // Yes, include in the CoC
217+ value : '1234567' } )
218+ , customFields = docusign . CustomFields . constructFromObject ( {
219+ textCustomFields : [ customField ] } ) ;
220+ envelopeDefinition . customFields = customFields ;
221+
222+ return envelopeDefinition ;
223+ }
224+ // ***DS.snippet.2.end
225+
226+ /**
227+ * Form page for this application
228+ */
229+ eg017SetTemplateTabValues . getController = ( req , res ) => {
230+ // Check that the authentication token is ok with a long buffer time.
231+ // If needed, now is the best time to ask the user to authenticate
232+ // since they have not yet entered any information into the form.
233+ let tokenOK = req . dsAuthCodeGrant . checkToken ( ) ;
234+ if ( tokenOK ) {
235+ res . render ( 'pages/examples/eg017SetTemplateTabValues' , {
236+ csrfToken : req . csrfToken ( ) ,
237+ title : "Set template tab values" ,
238+ templateOk : req . session . templateId ,
239+ sourceFile : path . basename ( __filename ) ,
240+ sourceUrl : dsConfig . githubExampleUrl + path . basename ( __filename ) ,
241+ documentation : dsConfig . documentation + eg ,
242+ showDoc : dsConfig . documentation
243+ } ) ;
244+ } else {
245+ // Save the current operation so it will be resumed after authentication
246+ req . dsAuthCodeGrant . setEg ( req , eg ) ;
247+ res . redirect ( mustAuthenticate ) ;
248+ }
249+ }
0 commit comments