docusignapi | place to sign are lost when updating an envelope - docusignapi

my UI when create and wh
My code to update:
var recipients = envelopesApi.ListRecipients(accountId, envelopeId, new EnvelopesApi.ListRecipientsOptions { includeTabs = true.ToString() });
foreach (var doc in documents)
{
var retornoDelete = envelopesApi.DeleteDocuments(accountId, envelopeId, new EnvelopeDefinition { Documents = new List<Document> { doc } });
}
var resultUpdateDocuments = envelopesApi.UpdateDocuments(accountId, envelopeId, new EnvelopeDefinition { Documents = envelope.Documents, Recipients = recipients });
var resultUpdateRecipients = envelopesApi.UpdateRecipients(accountId, envelopeId, recipients, new EnvelopesApi.UpdateRecipientsOptions { resendEnvelope = "true" });
I have try this link bellow, but not work for me:
DocuSign: Signer Tabs are lost when updating an envelope

Im not sure what you are trying to do in this code, but you are both updating the recipient and the document. It make a lot more sense to create a new envelope at this point, instead of 3 API calls - you can make just one.
The reason you don't see the tab (SignIn) is because you are updating the recipients and documents again and that won't by itself update the tabs. You need to make yet another API call for this (https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopedocumenttabs/update/)
I recommend you reconsider this flow to just create a new envelope with all the information in one call. But if you need to do it this way - you'll need another API call.

the Create Tabs work here, i guess this will sufficient
foreach (var item in recipients.Signers)
{
try
{
var tabsRecipient = envelope.Recipients.Signers.Where(x => x.Email == item.Email).Select(x => x.Tabs).First();
var resultUpdateTabs = envelopesApi.CreateTabs(accountId, envelopeId, item.RecipientId, tabsRecipient);
}
catch (Exception ex)
{
// this recipient have a constraint
}
}

Related

Remove/Correct Identity Verification from a signer from DocuSign SDK

I create an envelope and I want to implement the Correct functionality same as the DocuSign portal from API.
On creation I setup the authentication type to a signer and working perfectly.
Signer signer = new Signer
{
Email = email,
Name = name,
RecipientId = recipientId
};
//On Create
RecipientSMSAuthentication smsAuth = new RecipientSMSAuthentication();
smsAuth.SenderProvidedNumbers = new List<string>();
foreach (var telephone in telephoneNumbers)
{
smsAuth.SenderProvidedNumbers.Add(telephone);
}
signer.IdCheckConfigurationName = "SMS Auth $";
signer.SmsAuthentication = smsAuth;
When I try to correct this signer and remove or change (etc phone) this authentication type is not working
//On Update
signer.IdCheckConfigurationName = "";
signer.SmsAuthentication = null;
I use the UpdateAsync api call
Recipients Recipients = new Recipients();
List<Signer> Signers = new List<Signer>();
Signers.Add(signer);
Recipients.Signers = Signers;
await envelopesApi.UpdateAsync(accountId, envelopeId, new Envelope() { Recipients = Recipients }, new EnvelopesApi.UpdateOptions() { resendEnvelope = "true" });
A couple of things.
First, you're using the old method for SMS verification in this code. A new method which is going to give you more flexibility was introduced recently. It looks like this:
RecipientIdentityVerification workflow = new RecipientIdentityVerification()
{
WorkflowId = workflowId,
InputOptions = new List<RecipientIdentityInputOption> {
new RecipientIdentityInputOption
{
Name = "phone_number_list",
ValueType = "PhoneNumberList",
PhoneNumberList = new List<RecipientIdentityPhoneNumber>
{
new RecipientIdentityPhoneNumber
{
Number = phoneNumber,
CountryCode = countryAreaCode,
}
}
}
}
};
Signer signer1 = new Signer()
{
Name = signerName,
Email = signerEmail,
RoutingOrder = "1",
Status = "Created",
DeliveryMethod = "Email",
RecipientId = "1", //represents your {RECIPIENT_ID},
Tabs = signer1Tabs,
IdentityVerification = workflow,
};
Note that your account may not have the new auth method enabled, you can either create a new developer account or contact support to enable it for you,.
Second, updating recipients of an existing envelopes has some limits. It can only be done if the envelope is in a "Draft" status ("created") and not after it was sent ("sent"). You may need to use the Correct action in that case.

Add documents to draft envelope without signHereTabs

we are developing, with Java library from REST API, a procedure to sign multiple documents where the signature position is set using anchorString in signHereTabs for each signer (anchorString is a string inserted into the document to be signed);
since we have documents with size greater than 25MB, we are using what has been reported in https://developers.docusign.com/esign-rest-api/guides/resource-limits , that is we create a draft envelope (status=created) and then we updates the envelope with the documents;
the problem is that when we set the envelope with status = sent, the signer receives the email, open the link to DocuSign, but only the first document allow to access the anchorString.
Is there any particular way to update the list of documents in the draft envelope ?
Thanks
...
// add a recipient to sign the document, identified by name and email we used above
int recipientId = 0;
List<Signer> signerList = new ArrayList<Signer>();
/* to fix the position where the signature has to be inserted */
int buyerIdx = 0;
int supplierIdx = 0;
for(DSSignerInfo signerInfo : signers) {
Tabs tabs = new Tabs();
Signer signer = new Signer();
signer.setEmail(signerInfo.getEmail());
signer.setName(signerInfo.getName());
signer.setRecipientId(String.valueOf(++recipientId));
signer.setRoutingOrder(String.valueOf(recipientId)); // sequential
signer.setRoleName("role unknown");
RecipientEmailNotification emailNotification = new RecipientEmailNotification();
emailNotification.setEmailBody("emailBody - "+signerInfo.getName());
emailNotification.setEmailSubject("emailSubject - "+signerInfo.getName());
emailNotification.setSupportedLanguage(signerInfo.getLanguage());
signer.setEmailNotification(emailNotification);
// create a signHere tab somewhere on the document for the signer to sign
// default unit of measurement is pixels, can be mms, cms, inches also
for(int documentId = 1; documentId <= documentFiles.size(); documentId++) {
SignHere signHere = new SignHere();
signHere.setDocumentId("" + documentId);
signHere.setPageNumber("1");
signHere.setRecipientId(String.valueOf(recipientId));
if(signerInfo.getRole().equalsIgnoreCase("buyer")) {
signHere.setAnchorString("BUYER_"+buyerIdx);
} else {
signHere.setAnchorString("SUPPLIER_"+supplierIdx);
}
signHere.setAnchorXOffset("10");
signHere.setAnchorYOffset("10");
tabs.addSignHereTabsItem(signHere);
}
signer.setTabs(tabs);
signerList.add(signer);
if(signerInfo.getRole().equalsIgnoreCase("buyer")) {
buyerIdx++;
} else {
supplierIdx++;
}
}
Recipients recipients = new Recipients();
recipients.setSigners(signerList);
envDef.setRecipients(recipients);
try {
String envelopeId = null;
EnvelopesApi envelopesApi = null;
// create a byte array that will hold our document bytes
int documentId = 1;
for(String documentFile : documentFiles) {
byte[] fileBytes = null;
try {
// read file
Path path = Paths.get(documentFile);
fileBytes = Files.readAllBytes(path);
} catch (IOException ioExcp) {
// handle error
System.out.println("Exception: " + ioExcp);
return null;
}
// add a document to the envelope
Document doc = new Document();
String base64Doc = Base64.getEncoder().encodeToString(fileBytes);
doc.setDocumentBase64(base64Doc);
String fileName = new File(documentFile).getName();
doc.setName(documentId+"_"+fileName);
doc.setFileExtension(fileName.lastIndexOf('.') > 0 ? fileName.substring(fileName.lastIndexOf('.') + 1) : "");
doc.setDocumentId("" + documentId++);
envDef.addDocumentsItem(doc);
if(envelopeId == null || envelopesApi == null) {
// To save as a draft set to "created" (for test purpose I create and envelope with only one file)
envDef.setStatus("created");
envelopesApi = new EnvelopesApi();
EnvelopeSummary envelopeSummary = envelopesApi.createEnvelope(accountId, envDef);
envelopeId = envelopeSummary.getEnvelopeId();
} else {
// the files after the 1st are updated in the draft envelope
envDef.setRecipients(recipients);
List<Document> tmpDocumentList = new ArrayList<Document>();
doc.setApplyAnchorTabs("true");
tmpDocumentList.add(doc);
envDef.setDocuments(tmpDocumentList);
EnvelopeDocumentsResult envelopeDocumentsResult = envelopesApi.updateDocuments(accountId, envelopeId, envDef);
}
}
Envelope envelope = envelopesApi.getEnvelope(accountId, envelopeId);
envelope.setStatus("sent");
envelope.setPurgeState(null);
EnvelopesApi.UpdateOptions uo = envelopesApi. new UpdateOptions();
uo.setAdvancedUpdate("true");
EnvelopeUpdateSummary envelopeUpdateSummary = envelopesApi.update(accountId, envelopeId, envelope, uo);
documentId = 1;
for(String documentFile : documentFiles) {
Tabs tabs = envelopesApi.getDocumentTabs(accountId, envelopeId, ""+documentId++);
System.out.println("CARLO Tabs 3, documentId "+(documentId - 1)+": "+tabs);
}
Thanks for your answer.
More details:
in the envelope we have more than one document;
the size of each document is less than 25MB;
the sum of the sizes of all the documents is more than 25MB.
We can upload documents in envelope with status "created", but when the status is changed to "sent" and the signer goes into the signature page then it is not required to sign these documents; it seem that the signHereTabs is not set in the documents added while envelope status is "created".
If after having set envelope status = "sent" we execute the following code
documentId = 1;
for(String documentFile : documentFiles) {
Tabs tabs = envelopesApi.getDocumentTabs(accountId, envelopeId, ""+documentId++);
System.out.println("Tabs: documentId "+(documentId - 1)+": "+tabs);
}
we obtain
Tabs: documentId 1: class Tabs {
...
signHereTabs: [class SignHere {
anchorCaseSensitive: null
anchorHorizontalAlignment: null
anchorIgnoreIfNotPresent: null
anchorMatchWholeWord: null
anchorString: BUYER_0
anchorUnits: pixels
anchorXOffset: 10
anchorYOffset: -10
conditionalParentLabel: null
conditionalParentValue: null
customTabId: null
documentId: 1
errorDetails: null
mergeField: null
name: SignHere
optional: false
pageNumber: 1
recipientId: edb96dfd-9700-4328-ba45-825a1284b030
scaleValue: 1.0
stampType: signature
stampTypeMetadata: null
status: null
tabId: e484087c-70c2-431c-9825-47605e1f44c2
tabLabel: Sign Here
tabOrder: null
templateLocked: null
templateRequired: null
tooltip: null
xPosition: 123
yPosition: 297
}]
...
}
Tabs: documentId 2: class Tabs {
...
signHereTabs: []
...
}
where documentId 1 has been uploaded when the envelope has been created (status="created"), and documentId 2 has been uploaded in a second step (both documentId 1 and 2 contain the anchorString: BUYER_0).
If your document size is greater than 25MB then also putting document in the draft mode will not help, instead you have to use ChunkedUploads to add any document less than 50MB. Adding multiple documents via draft is useful if your JSON Request Payload is greater than 25 MB, but it will not be useful if any document in the envelope is greater than 25 MB.
To add on to Amit's answer, every individual API request to DocuSign must be less than 25MB.
Since the default technique is to send Base64 encoded documents within a JSON object, the effective max total size for all of the documents sent in a single request is around 18MB.
You can avoid the Base64 overhead by sending the API request as a multi-part MIME message. This technique enable you to send the documents as binary objects. See the code example for scenario 10 in C# (also available for PHP, Java, Node.js, Python, and Ruby)
Additional
If each of your documents is less than 18 MB, then you can use the "regular" JSON object and Base64 encode one document at a time. If the sum of the document sizes is greater than 18MB then you must upload them one at a time:
Create the envelope, include one of the documents. The document status should be created so the envelope is not sent at this time.
Add more documents to the envelope, one at a time. You can use EnvelopeDocuments::updateList API method. You'd probably want query parameter apply_document_fields on.
Update the envelope status to sent using Envelopes::update
For adding tabs to the documents, you could define them at the beginning if you use anchor tab positioning. Or you could add the tabs to the envelope definition after you finish adding the documents to the envelope.
Thanks all for the answers.
I've solved the problem in this way:
- step 2: set on the parameter apply_document_fields on each added file,
- step 3: set again the recipients in the envelope before set it as 'sent'.
From my point of view this question is solved.

Can I delete a file in Acumatica via the API?

I'm creating a file in Acumatica by calling an action from the API, so that I can retrieve the file in my application.
Is it possible to delete the file via API after I'm done with it? I'd rather not have it cluttering up my Acumatica database.
Failing this, is there a recommended cleanup approach for these files?
Found examples of how to delete a file from within Acumatica, as well as how to save a new version of an existing file! The below implementation saves a new version but has the deletion method commented out. Because I built this into my report generation process, I'm not later deleting the report via API, but it would be easy to translate a deletion into an action callable by the API.
private IEnumerable ExportReport(PXAdapter adapter, string reportID, Dictionary<String, String> parameters)
{
//Press save if the SO is not completed
if (Base.Document.Current.Completed == false)
{
Base.Save.Press();
}
PX.SM.FileInfo file = null;
using (Report report = PXReportTools.LoadReport(reportID, null))
{
if (report == null)
{
throw new Exception("Unable to access Acumatica report writer for specified report : " + reportID);
}
PXReportTools.InitReportParameters(report, parameters, PXSettingProvider.Instance.Default);
ReportNode reportNode = ReportProcessor.ProcessReport(report);
IRenderFilter renderFilter = ReportProcessor.GetRenderer(ReportProcessor.FilterPdf);
//Generate the PDF
byte[] data = PX.Reports.Mail.Message.GenerateReport(reportNode, ReportProcessor.FilterPdf).First();
file = new PX.SM.FileInfo(reportNode.ExportFileName + ".pdf", null, data);
//Save the PDF to the SO
UploadFileMaintenance graph = new UploadFileMaintenance();
//Check to see if a file with this name already exists
Guid[] files = PXNoteAttribute.GetFileNotes(Base.Document.Cache, Base.Document.Current);
foreach (Guid fileID in files)
{
FileInfo existingFile = graph.GetFileWithNoData(fileID);
if (existingFile.Name == reportNode.ExportFileName + ".pdf")
{
//If we later decide we want to delete previous versions instead of saving them, this can be changed to
//UploadFileMaintenance.DeleteFile(existingFile.UID);
//But in the meantime, for history purposes, set the UID of the new file to that of the existing file so we can save it as a new version.
file.UID = existingFile.UID;
}
}
//Save the file with the setting to create a new version if one already exists based on the UID
graph.SaveFile(file, FileExistsAction.CreateVersion);
//Save the note attribute so we can find it again.
PXNoteAttribute.AttachFile(Base.Document.Cache, Base.Document.Current, file);
}
//Return the info on the file
return adapter.Get();
}
The response from Acumatica:
S-b (Screen-base) API allows clean way of downloading report generated as file. C-b (Contract-base) simply does not have this feature added. I suggest you provided feedback here: feedback.acumatica.com (EDIT: Done! https://feedback.acumatica.com/ideas/ACU-I-1852)
I think couple of workaround are:
1) use s-b using login from c-b to generate report and get as file (see example below), or
2) create another method to delete the file once required report file is downloaded. For that, you will need to pass back FileID or something to identify for deletion.
example of #1
using (DefaultSoapClient sc = new DefaultSoapClient("DefaultSoap1"))
{
string sharedCookie;
using (new OperationContextScope(sc.InnerChannel))
{
sc.Login("admin", "123", "Company", null, null);
var responseMessageProperty = (HttpResponseMessageProperty)
OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name];
sharedCookie = responseMessageProperty.Headers.Get("Set-Cookie");
}
try
{
Screen scr = new Screen(); // add reference to report e.g. http://localhost/Demo2018R2/Soap/SO641010.asmx
scr.CookieContainer = new System.Net.CookieContainer();
scr.CookieContainer.SetCookies(new Uri(scr.Url), sharedCookie);
var schema = scr.GetSchema();
var commands = new Command[]
{
new Value { LinkedCommand = schema.Parameters.OrderType, Value = "SO" },
new Value { LinkedCommand = schema.Parameters.OrderNumber, Value = "SO004425" },
schema.ReportResults.PdfContent
};
var data = scr.Submit(commands);
if(data != null && data.Length > 0)
{
System.IO.File.WriteAllBytes(#"c:\Temp\SalesOrder.pdf",
Convert.FromBase64String(data[0].ReportResults.PdfContent.Value));
}
}
finally
{
sc.Logout();
}
}
Hope this helps. Also, it would be great if you update the stackover post based on these suggestions.
Thanks
Nayan Mansinha
Lead - Developer Support | Acumatica

SharePoint CSOM: How to update person or group field using ValidateUpdateListItem?

I am updating a SharePoint list item using the ValidateUpdateListItem method of the client-side object model to prevent creation of a new item version. This basically works fine for all fields except the ones with person or group field type. Does anyone know what is the correct string representation of a user or group value to be used as FieldValue of an ListItemFormUpdateValue object? I have already tried everything that seems reasonable to me (user ID from User Info, login name, lookup-value like combinations of these data etc.) without any success.
I just ran into a problem where updating more than 12 person or group fields with item update caused it to throw an exception. Apparently this is caused due to the list view look up threshold in SP online (12 as of this date).
http://blog.vanmeeuwen-online.nl/2012/07/value-does-not-fall-within-expected.html
To work around that I used the ValidateUpdateListItem method to update the person or group ids. The trick is to assign it a json in the format of
[{"Key":"i:0#.f|membership|user#yoursite.onmicrosoft.com"}]
formValues.Add(new ListItemFormUpdateValue() { FieldName = "AssignedTo", FieldValue = "[{'Key':'i:0#.f|membership|user#yoursite.onmicrosoft.com'}]" });
For multiple values, it can be comma separated. Have not tried it with group but i think it should work.
Hopefully this can be useful for someone.
Unfortunately ListItem.ValidateUpdateListItem method does not support the update of user field value. For example, in the following example AssignedTo field will not be updated:
using (var ctx = GetContext(webUri, userName, password))
{
var list = ctx.Web.Lists.GetByTitle(listTitle);
var item = list.GetItemById(itemId);
var formValues = new List<ListItemFormUpdateValue>();
formValues.Add(new ListItemFormUpdateValue() { FieldName = "Title", FieldValue = taskName});
formValues.Add(new ListItemFormUpdateValue() { FieldName = "AssignedTo", FieldValue = userId.ToString() }); //not supported
item.ValidateUpdateListItem(formValues, true, string.Empty);
ctx.ExecuteQuery();
}
Instead consider ListItem.Update Method to update user field value as demonstrated below:
using (var ctx = GetContext(webUri, userName, password))
{
var list = ctx.Web.Lists.GetByTitle(listTitle);
var item = list.GetItemById(itemId);
item["Title"] = taskName;
var assignedToValue = new FieldUserValue() { LookupId = userId };
var assignedToValues = new[] { assignedToValue };
item["AssignedTo"] = assignedToValues; //multi-valued user field
item.Update();
ctx.ExecuteQuery();
}

Envelope Tabs removed when using CreateEnvelopeFromTemplates()

Im using the DocuSign API and im having some issues with the recipient not getting the tabs I save on the website ui. I create a template using DocuSign.com and set the recipient to Role=[testRole] Email=[] Name=[] Type=[Sign] under Recipients and routing. Because I have no recipients yet. Then using the api before i send it out i set the recipient to :
//Recipient Info
Recipient recipient = new Recipient();
recipient.Email = recipientEmail;
recipient.UserName = recipientName;
recipient.SignerName = recipientName;
recipient.Type = RecipientTypeCode.Signer;
recipient.RoleName = recipientRoleName;
recipient.ID = "1";
recipient.SignInEachLocationSpecified = true;
recipient.RoutingOrder = 1;
Recipient[] recipients = new Recipient[] { recipient };
//Template reference from server ID
TemplateReference templateReference = new TemplateReference();
templateReference.Template = templateID;
templateReference.TemplateLocation = TemplateLocationCode.Server;
//Envelope Info
EnvelopeInformation envelopeInfo = new EnvelopeInformation();
envelopeInfo.AccountId = AccountID;
envelopeInfo.Subject = subject;
envelopeInfo.EmailBlurb = message;
I set recipient.RoleName to the same thing as i set on the website UI and still the recipient doesn't get the signature tabs. am i missing something here? Or how do i relate the empty recipient i created using the DocuSign UI to the recipient im sending it to so that it has the tabs present?
Figured it out after shooting in the dark for a while. I was so sure the issue was in Recipient but when I took a look at TemplateReference I found RoleAssignments which apparently setting up in Recipient.Role does nothing. You have to set it up in TemplateReference using something like:
//Recipient Role
var recipientRole = new TemplateReferenceRoleAssignment();
recipientRole.RecipientID = "101";
recipientRole.RoleName = recipientRoleName;
//Template reference from server ID
TemplateReference templateReference = new TemplateReference();
templateReference.Template = templateID;
templateReference.TemplateLocation = TemplateLocationCode.Server;
templateReference.RoleAssignments = new TemplateReferenceRoleAssignment[] { recipientRole };

Resources