0
votes

I'm trying to send an envelope from a template in a webhook listener. I'm using node.js with .mjs files. When I send the envelope via the docusign dashboard it has the tabs - full name, SSN, phone number, address. But when the API sends the envelope, it has those words but no fields next to them. This is a problem because we need that info and there's nowhere for the signer to input it. What could be causing the tabs to not appear when the envelope is sent from the api?

Here's the code to create an envelope and use a template (based off docs):

import docusign from 'docusign-esign';

export function makeEnvelope(args){

  // Create the envelope definition
    let env = new docusign.EnvelopeDefinition();
    env.templateId = args.templateId;

  // Create template role elements to connect the signer and cc recipients
  // to the template
  // We're setting the parameters via the object creation
    let signer1 = docusign.TemplateRole.constructFromObject({
        email: args.signerEmail,
        name: args.signerName,
        roleName: 'signer'});

  // Create a cc template role.
  // We're setting the parameters via setters
    let cc1 = new docusign.TemplateRole();
    cc1.email = args.ccEmail;
    cc1.name = args.ccName;
    cc1.roleName = 'cc';

  // Add the TemplateRole objects to the envelope object
    env.templateRoles = [signer1, cc1];
    env.status = 'sent'; // We want the envelope to be sent

    return env;
}

export async function useTemplate(args) {


    let dsApiClient = new docusign.ApiClient();
    dsApiClient.setBasePath(args.basePath);
    dsApiClient.addDefaultHeader('Authorization', 'Bearer ' + args.accessToken);
    let envelopesApi = new docusign.EnvelopesApi(dsApiClient);
  
  // Make the envelope request body
    let envelope = makeEnvelope(args.envelopeArgs);

  // Call Envelopes::create API method
  // Exceptions will be caught by the calling function
    let results = await envelopesApi.createEnvelope(
      args.accountId, {envelopeDefinition: envelope});

    return results;
};

Here's the code for the webhook listener where I call useTemplate (please excuse the commented out code and the console logs - I'm still in the midst of figuring it all out):

import express from 'express';
import { useTemplate } from '../request/docusign/docusign-methods.mjs';
import opportunities from '../request/prosperworks/opportunities.mjs';
import people from '../request/prosperworks/people.js';
import customFields from '../request/prosperworks/custom-fields.mjs';
import { findTemplateIdByCohortName } from '../request/docusign/templates.mjs';
import { findSentEnvelopesByStudentEmail, voidEnvelope, findTemplateFromEnvelopeTemplateUri } from '../request/docusign/envelopes.mjs';
import { createJWT, getAccessTokenFromJWT } from '../request/docusign/token.mjs';
import { getAccessToken } from '../request/quickbooks/tokens.mjs';
import { findCustomerByEmail } from '../request/quickbooks/customer.mjs';
import { createCustomer } from '../request/quickbooks/customer.mjs';
import { createInvoice, sendInvoice } from '../request/quickbooks/invoice.mjs';
import { findItemByName } from '../request/quickbooks/item.mjs';

const router = express.Router();

export default router
  .post('/copper/opportunity/updated', express.json(), async (req, res, next) => {
    const { body } = req;
    console.log('webhook received', body);
    if(!Object.keys(body.updated_attributes).length) return res.send('irrelevant webhook');
    const cohortChanged = !!body.updated_attributes?.custom_fields?.['94620']
    console.log('cohort changed?', cohortChanged);
    const interviewScheduledToAccepted = !!(body.updated_attributes?.stage?.[0] === 'Interview Scheduled' && body.updated_attributes?.stage?.[1] === 'Accepted')
    console.log('interview scheduled to accepted?', interviewScheduledToAccepted);
    const fullConditional = cohortChanged || interviewScheduledToAccepted;
    console.log('full conditional', fullConditional);
    if(fullConditional) {
        try {
            const jwt = await createJWT();
            const docusign_access_token = await getAccessTokenFromJWT(jwt);
            const opportunity = await opportunities.get(body.ids[0]);
            const cohortId = opportunity?.custom_fields?.find(field => field.custom_field_definition_id === 94620)?.value || null;
            const cohortName = customFields.getCohortNameById(cohortId);
            console.log('cohort name', cohortName);
            const templateId = await findTemplateIdByCohortName(cohortName, docusign_access_token);    
            const person = await people.findById(opportunity.primary_contact_id);
            const email = person.emails[0].email;
            console.log('email', email);
            const { name } = person;
            // if(interviewScheduledToAccepted) {
            //     const quickbooks_access_token = await getAccessToken();
            //     let customer = await findCustomerByEmail(email, quickbooks_access_token);
            //     if(customer === null) {
            //         customer = await createCustomer(cohortName, person, quickbooks_access_token);
            //     };
            //     console.log('customer', customer);
            //     const product = await findItemByName('Deposit', quickbooks_access_token);
            //     const invoice =  await createInvoice(customer, product, cohortName, quickbooks_access_token);
            //     const sentInvoice = await sendInvoice(email, invoice.Invoice.Id, quickbooks_access_token)
            //     console.log('sent invoice', sentInvoice);
            // }  
            const sentEnvelopes = await findSentEnvelopesByStudentEmail(email, docusign_access_token);
            await Promise.all(
            sentEnvelopes.filter(envelope => {
                return envelope.emailSubject.includes('Enrollment Agreement');
            })
            .map(envelope => {
                if(envelope.status === 'sent') return voidEnvelope(envelope.envelopeId, docusign_access_token);
            })
            );
            const sentEnvelopesTemplates = await Promise.all(
                sentEnvelopes
                .filter(envelope => {
                    return envelope.status !== 'voided'
                })
                .map(envelope => {
                    return findTemplateFromEnvelopeTemplateUri(envelope.templatesUri, docusign_access_token);
                })
            );
            const templateAlreadyUsedCheck = sentEnvelopesTemplates.reduce((outerAcc, templateArr) => {
                if(templateArr.reduce((innerAcc, template) => {
                    if(template.templateId === templateId) innerAcc=true;
                    return innerAcc;
                }, false)) {
                    outerAcc=true;
                }
                return outerAcc;
            }, false);
            if(templateAlreadyUsedCheck) return res.send('envelope already sent');
            const envelopeArgs = {
            templateId: templateId,
            signerEmail: email,
            signerName: name
            }
            console.log(envelopeArgs);
            const envelope = await useTemplate({
                basePath: process.env.DOCUSIGN_BASE_PATH,
                accessToken: docusign_access_token,
                accountId: process.env.DOCUSIGN_ACCOUNT_ID,
                envelopeArgs
            });
            return res.send(envelope);
        }
        catch(err) {
            console.log(err.message);
            next(err);
        }
    } else {
        return res.send('irrelevant webhook');
    }
  });
1
does your template use "signer' as the role name? placeholder recipients has a name and it must match what you use when you use the templateRoles in your codeInbar Gazit
That was totally it! Thanks a bunchEvan Andrewson

1 Answers

3
votes

Inbar Gazit figured it out - it turns out I had student as the role name in the template and signer as the role name in my code so that's why it wasn't working.