I'm trying to insert a word document into a Docusign template. The document inserts properly, but in addition to the two signers set up in the code, one of the signers that was on the template stays. Also, the second signature field is removed. Is there a setting that I'm missing? Here's my code:
List<TemplateRole> roleslist = new List<TemplateRole>();
TemplateRole InternalSignerRole = new TemplateRole(); // Set the Template Roles for the Internal Signer
InternalSignerRole.Email = _currentDocInfo.sInternalSignerEmail;
InternalSignerRole.Name = _currentDocInfo.sInternalSignerName;
InternalSignerRole.RoleName = "SignerInternal";
roleslist.Add(InternalSignerRole); // add to Template Roles list
TemplateRole ExternalSignerRole = new TemplateRole(); // Set the Template Roles for the External Signer
ExternalSignerRole.Email = _currentDocInfo.sExternalSignerEmail; //Create Template Roles for ExternalSigner
ExternalSignerRole.Name = _currentDocInfo.sExternalSignerEmail;
ExternalSignerRole.RoleName = "SignerExternal";
roleslist.Add(ExternalSignerRole);
var apiClient = new ApiClient(conn.Base_URL);
DocuSign.eSign.Client.Configuration.Default.ApiClient = apiClient;
DocuSign.eSign.Client.Configuration.Default.AddDefaultHeader("X-DocuSign-Authentication", authHeader);
string accountId = null;
// login call is available in the authentication api
var authApi = new AuthenticationApi();
var loginInfo = authApi.Login();
// parse the first account ID that is returned (user might belong to multiple accounts)
accountId = loginInfo.LoginAccounts[0].AccountId;
var baseUrl = loginInfo.LoginAccounts[0].BaseUrl;
var separator = new string[] { "/restapi" };
var basePath = baseUrl.Split(separator, StringSplitOptions.None)[0] + "/restapi";
apiClient = new ApiClient(basePath);
EnvelopeDefinition envDef = new EnvelopeDefinition();
envDef.EmailSubject = emailSubject;
envDef.EmailBlurb = emailBody;
//add custom fields you sent over with the document
envDef.CustomFields = letterCustomFields;
// Add a document to the envelope
envDef.Documents = letterDocs;
// Add a recipient to sign the document
envDef.TemplateRoles = roleslist;
envDef.TemplateId = "478d85c2-dc7c-4a89-a985-7d7a9101e36a";
First off, please don't use legacy authentication. That is old, not as secure and should not be used in new code that you're building.
Note that tabs (signature elements) are associated with both a recipient (a specific one) as well as a document (a specific one).
If you are trying to replace a document in a template, when creating an envelope from it (which is what you're doing, you're not replacing the document in the template, but rather in the envelope you create), you need to ensure the tabs refer to the same document and same recipient (based on the role).
Also, another recommendation is to use composite templates, which provide more flexibility for such scenarios. See excellent blog post by Gil Vincent for more information.
Related
Trying to add workflow step to pause the workflow for approval for second signer.
Please note I was able to add the pause when creating envelopes with recipients added.
But was not able to add the workflow step when trying to create envelope from templates. The templates are created in docusign with only roles added.
Later when creating the envelope through API we added TemplateRoles to add signers against each role.
In this case when we tried to add workflow step to pause the workflow it didn’t pause and sent invitation for the second signer. Can you please help us on this and correct us if we are doing any thing wrong.
Please find the snip of the code below:
var workflowStep = new WorkflowStep()
{
Action ="pause_before",
TriggerOnItem = "routing_order",
ItemId = "2"
};
var workflowsteps = new List<WorkflowStep>();
workflowsteps.Add(workflowStep);
TemplateRole signer = new TemplateRole();
signer.Email = "test#example.com";
signer.Name = "Test";
signer.RoleName = "QA";
signer.RoutingOrder = "1";
TemplateRole signer1 = new TemplateRole();
signer1.Email = "test123#example.com";
signer1.Name = "Test123";
signer1.RoleName = "RS";
signer1.RoutingOrder = "2";
var tempRoles = new List<TemplateRole>();
tempRoles.Add(signer);
tempRoles.Add(signer1);
EnvelopesApi envelopesApi = new EnvelopesApi(apiclient);
EnvelopeDefinition envDef = new EnvelopeDefinition();
envDef.TemplateId = templateId;
envDef.Status = "Sent";
envDef.TemplateRoles = tempRoles;
envDef.Workflow = new Workflow { WorkflowSteps = workflowsteps };
EnvelopeSummary envelopeSummary = envelopesApi.CreateEnvelope(accountId, envDef);
I hesitate to add this because I haven't tested it but I'll mention it in case it unblocks you and see if I can verify later...
I believe if you create the envelope/template with status = paused rather than sent, you should be able to update the template with ARR.
The problem is that when you get to the 'pause' in the above code, it's already 'too late'.
Epicor ERP 10.2.500 has been recently released with the addition of Epicor Functions. They can be called from within Method and Data Directives.
Do anybody has been able to do so with a Form Customization within Epicor?
This is possible via a REST call to your function API. In this case, I had a function that sent an email from some inputs.
private void epiButtonC1_Click(object sender, System.EventArgs args)
{
//API Key is included in the query param in this example.
var request = (HttpWebRequest)WebRequest.Create("https://{appserver}/{EpicorInstance}/api/v2/efx/{CompanyID}/{LibraryID}/{functionName}/?api-key={yourAPIKey}");
request.Method = "POST";
//All REST v2 requests also sent with authentication method (Token, Basic)
//This should be Base64 encoded
string username = "userName";
string password = "passWord";
string encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
request.Headers.Add("Authorization", "Basic " + encoded);
//Add body to correspond to request signature
request.ContentType = "application/json";
using(var writer = new StreamWriter(request.GetRequestStream()))
{
var values = new Dictionary<string, string>;
{
{"toEmailAddress", "someEmail#email.com"},
{"fromEmailAddress","someOtherEmail#email.com"},
{"body","This is the body"},
{"subject","Hello from Client Code!"}
};
string json = JsonConvert.SerializeObject(values);
writer.Write(json);
}
using (var response = request.GetResponse())
using (var reader = new StreamReader(response.GetResponseStream()))
{
var result = reader.ReadToEnd();
epiTextBoxC1.Text = result.ToString();
}
}
Haven't done it myself personally, but looking into the first post release notes about it here leads me to believe there is no out of the box solution, yet in this version/initial release.
However I'm sure you could do a HTTP request from within the Epicor customization if you have the REST API enabled in your environment.
If you create your own dll that calls the EpicorFunction you can use it within the customization. Still looking for a way to call them directly.
REST endpoint is the recommended way to perform the function call as pointed out by a-moreng.
If for some reason you cannot use this, you can use a passthrough method to any server-side BO via a customization Adapter. For instance, create an updatable BAQ which you can call from a customization using the DynamicQueryAdapter.
Pick an arbitrary table and field to save the BAQ.
Create three string parameters to store the Function library name, the function name, and a delimited list of parameters.
On the GetList method, create a Base Processing Directive.
Split your delimited parameter list and convert them to the appropriate datatypes.
Use the resulting variables to call your function.
If desired, you can pass return variables into the ttResults of the BAQ
I was trying to pre-populate the custom field value from C# code but I was not able to. I have used following snippet of code to do so
var client = new Client("MY API KEY");
var request = new TemplateSignatureRequest();
request.AddTemplate("docID");
request.Title = "Test Titel";
request.Subject = "Test Subject";
request.Message = "Test Message.";
request.AddSigner("Me", "xxxxx#example.com", "Test");
request.AddSigner("Client", "xxxxx#example.com", "Test");
var firstName = request.GetCustomField("FirstName");
firstName.Value = "John";
request.TestMode = true;
var response = client.SendSignatureRequest(request);
I have already assigned the customer field to me and verified the API ID key for the field also.But still not able to get the result. Is there anything else we need to add to so that value John will be shown.
Try
request.AddCustomField("fName", "Alex");
Also, please feel free to reach out to apisupport#hellosign.com for more assistance if you would like.
Please be patient and Do Not flag this as duplicate: Using the Rally REST API, how can I get the non-API (website) URL for a user story?
I want to be able to generate a link for the user story.
Something like this: https://rally1.rallydev.com/#/-/detail/userstory/*********
As opposed to this: https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement/88502329352
The link will be integrated into another application for the managers to see the user story.
I did read about the getDetailUrl() method, but in my case I am creating the user stories by parsing email and linking that to a notification service in Slack.
I am aware of the formattedID and (_ref), but I would have to query for it again, and I am creating batches of userstories through a loop. I need the actual web site link to the user story.
Here is my sample code:
public void CreateUserStory(string workspace, string project, string userstoryName){
//authenticate with Rally
this.EnsureRallyIsAuthenticated();
//DynamicJsonObject for HierarchicalRequirement
DynamicJsonObject toCreate = new DynamicJsonObject();
toCreate[RallyConstant.WorkSpace] = workspace;
toCreate[RallyConstant.Project] = project;
toCreate[RallyConstant.Name] = userstoryName;
try
{
//Create the User Story Here
CreateResult createUserStory = _api.Create(RallyConstant.HierarchicalRequirement, toCreate);
Console.WriteLine("Created Userstory: " + "URL LINK GOES HERE");
}
catch (WebException e)
{
Console.WriteLine(e.Message);
}
}
We don't have a method in the .NET toolkit for doing this, but it's easy to create.
The format is this:
https://rally1.rallydev.com/#/detail/<type>/<objectid>
Just fill in the type (hierarchicalrequirement turns into userstory, but all the others are the same as the wsapi type) and the objectid from the object you just created.
var parameters = new NameValueCollection();
parameters["fetch"] = "FormattedID";
var toCreate = new DynamicJsonObject();
var createResult = restApi.create("hierarchicalrequirement", toCreate, parameters);
var type = Ref.getTypeFromRef(createResult.Reference);
var objectID = Ref.getOidFromRef(createResult.Reference);
var formattedID = createResult.Object["FormattedID"];
And you can specify fetch fields to be returned on the created object so you don't have to re-query for it.
I'm working on converting my old Sitecore (< 8) code to work with Sitecore EXM. I'm having a hard time adding users to Recipient Lists from code. The answers in this post: Sitecore 8 EXM add a contact to list from listmanager don't answer my questions completely, and since I cannot comment, I've decided to start a new topic.
My first problem is that my EcmFactory.GetDefaultFactory().Bl.RecipientCollectionRepository.GetEditableRecipientCollection(recipientListId) gives a compilation error on the RecipientCollectionRepository, it says it does not exist. So I've used slightly different code. My code now, is as follows:
var contactRepository = new ContactRepository();
var contactName = this.Email.Text;
var contact = contactRepository.LoadContactReadOnly(contactName);
contact = contactRepository.CreateContact(Sitecore.Data.ID.NewID);
contact.Identifiers.AuthenticationLevel = Sitecore.Analytics.Model.AuthenticationLevel.None;
contact.System.Classification = 0;
contact.ContactSaveMode = ContactSaveMode.AlwaysSave;
contact.Identifiers.Identifier = contactName;
contact.System.OverrideClassification = 0;
contact.System.Value = 0;
contact.System.VisitCount = 0;
var contactPreferences = contact.GetFacet<IContactPreferences>("Preferences");
contactPreferences.Language = "nl-NL";
var contactEmailAddresses = contact.GetFacet<IContactEmailAddresses>("Emails");
contactEmailAddresses.Entries.Create("test").SmtpAddress = this.Email.Text;
contactEmailAddresses.Preferred = "test";
var contactPersonalInfo = contact.GetFacet<IContactPersonalInfo>("Personal");
contactPersonalInfo.FirstName = contactName;
contactPersonalInfo.Surname = "recipient";
if (recipientList != null)
{
var xdbContact = new XdbContactId(contact.ContactId);
if (!recipientList.Contains(xdbContact, true).Value)
{
recipientList.AddRecipient(xdbContact);
}
contactRepository.SaveContact(contact, new ContactSaveOptions(true, null));
}
So the recipientList is found, and the first time I add a contact to it, it increases the "Recipients" to 1 (checked using the /sitecore/system/List Manager/All Lists/E-mail Campaign Manager/Custom/RecipientList).
I also have a message which has this Opt-in recipient list, but when I check that message, it says it will be sent to 0 subscribers.
Any thoughts on this?
See this article listing known issues in Sitecore EXM:
https://kb.sitecore.net/articles/149565
"The recipient list shows "0" total recipients after recipients have been subscribed to the list. (62217)"
I got around this in a sandbox environment by adding a simple list (from csv, one contact) to the message. This upped the total recipient count from 0 to 1 which allows the message to be activated. All recipients in the composite list were sent a message.
Do you have a distributed environment? If so the RecipientCollectionRepository will not work as it is only available on a Content Management server. You could try using the ClientApi:
ClientApi.UpdateSubscriptions(RecipientId recipientId, string[] listsToSubscribe, string[] listsToUnsubscribe, string managerRootId, bool confirmSubscription)
and just add the id of the list you want to subscribe people to in the first string array.
Just a quick note with this option, listToUnsubscribe does not actually remove a contact from a list. You are meant to pass through the ID of the opt out list. This basically excludes them from any future emails. One draw back is that you will no longer be able to resubscribe them.
If this does not work for you you will need to create your own API between your CD server and your CM server where the CM server uses the recipientCollectionRepository to subscribe and unsubscribe