I am new to CRM and have been able to figure out everything up to now. I have read so many post and internet post and tried them. I have watched some many videos. It seems it should be easy. The contact record has the ParentCustomerID, and ParentCustomerName that holds the account if there is one associated. Now I am just totally confused on the required steps.
Requirement: - I need Account Name to be displayed on the contact level phone call form and saved in phone call table so that it can be visible in the phone call view.
I have in Phone Call N:1 Relationship field str_companyid (lookup) primary Entity is Account with Referential behavior.
I tried a Phone Call N:1 Relationship field new_companystring (lookup) primary Entity is Contact with Referential behavior. I came to the conclusion that this is not a valid approach. Let me know if incorrect.
Do I need a N:N instead?
I have added the str_companyid field to the form. I went to the "Create a phone call for a contact" workflow process. On the "Create PhoneCall" step I have added the dynamic field {Company(Contact)}. After save and publishes; I created a phone call and it isn't populated.
I have tried different Web Resource JS. I have added the JS in the onload of the form properties.
Why doesn't something as easy as this work? I can't seem to get the retrieveRecord to work. I have also tried the xmlHttpObject object but it returns 0.
Can someone help assist me on what I am missing? What are the complete steps to accomplish this?
![I have screenshots below and the code I was running][1]
function PopulateCompanyName()
{
//get group GUID
if (Xrm.Page.getAttribute("to").getValue()[0].id != null) {
var lookup = Xrm.Page.getAttribute("to").getValue();
alert(lookup[0].id);
alert(lookup[0].typename);
alert(lookup[0].name);
alert(lookup);
SDK.JQuery.retrieveRecord(lookup[0].id,
lookup[0].typename,
"ParentCustomerID",
null,
function (lookup) {
Xrm.Page.getAttribute("Company").setValue(lookup[0].str_companyid);
});
}
else {
Xrm.Page.getAttribute("str_companyid").setValue(null);
}
}
function GetCompany()
///Get lookup ID
{
alert("I am Here");
var lookupfield = Xrm.Page.getAttribute("to").getValue();
if (lookupfield != null && lookupfield [0] != null)
{
var householdlookupvalue = lookupfield [0].id;
}
else
{
var householdlookupvalue = " ";
}
alert("I am here2");
alert(householdlookupvalue);
}
// Prepare variables for a contact to retrieve.
var authenticationHeader = Xrm.Page.context.getAuthenticationHeader();
// Prepare the SOAP message.
var xml = ""+
""+
authenticationHeader+
""+
""+
"contact"+
""+lookupfield [0].id+""+
""+
""+
"parentcustomerid"+
""+
""+
""+
""+
"";
alert(xml );
// Prepare the xmlHttpObject and send the request.
var xHReq = new ActiveXObject("Msxml2.XMLHTTP");
xHReq.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xHReq.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/Retrieve");
xHReq.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xHReq.setRequestHeader("Content-Length", xml.length);
xHReq.send(xml);
// Capture the result.
var resultXml = xHReq.responseXML;
alert("at results");
var errorCount = resultXml.selectNodes('//error').length;
alert("errorCount " + errorCount); ////////////////////////////////////returns 0; it shouldn't
alert("After the result XML "+resultXml .toString() + " ::::");
// Check for errors.
var errorCount = resultXml.selectNodes('//error').length;
if (errorCount != 0)
{
}
// Display the retrieved value.
else
{
//Create an array to set as the DataValue for the lookup control.
var lookupData = new Array();
//Create an Object add to the array.
var lookupItem= new Object();
//Set the id, typename, and name properties to the object.
lookupItem.id = resultXml.selectSingleNode("//q1:parentcustomerid").nodeTypedValue;
lookupItem.entityType = 'account';
lookupItem.name = resultXml.selectSingleNode("//q1:parentcustomerid").getAttribute("name");
// Add the object to the array.
lookupData[0] = lookupItem;
alert(lookupitem.name)
// Set the value of the lookup field to the value of the array.
Xrm.Page.getAttribute("str_companyid").setValue(lookupData);
}
var contact = new Array();
contact = Xrm.Page.getAttribute("to").getValue();
alert("I am here");
alert(contact);
if (contact == null || contact[0].entityType != "contact" || contact.length > 1) {
return;
}
alert("inside if")
var serverUrl = Xrm.Page.context.getClientUrl();
var oDataSelect = serverUrl + "/XRMServices/2011/OrganizationData.svc/ContactSet?$select=ParentCustomerId&$filter=ContactId eq guid'" + contact[0].id + "'";
var retrieveReq = new XMLHttpRequest();
retrieveReq.open("GET", oDataSelect, false);
retrieveReq.setRequestHeader("Accept", "application/json");
retrieveReq.setRequestHeader("Content-Type", "application/json;charset=utf-8");
retrieveReq.onreadystatechange = function () {
GetContactData(this);
};
retrieveReq.send();
}
I replied in the other forum but I post here as reference and with more technical details.
The to attribute of phonecall entity is a partylist type, this means that it can handle several records from different entities. In your case you want to get the Parent Account (field parentcustomerid) if a contact is inside the to field.
Your first code contains same typo and use the msdn Retrieve example, the second code uses CRM 4.0 endpoints, they are still supported inside CRM 2011, but it's better to avoid them so you can use the REST endpoint instead of the SOAP one.
a working code in your case can be:
function setToParentAccount() {
// set only if to Field (Recipient) has 1 record and is a contact
if (Xrm.Page.getAttribute("to").getValue() != null) {
var recipient = Xrm.Page.getAttribute("to").getValue();
if (recipient.length == 1 && recipient[0].entityType == "contact") {
var contactId = recipient[0].id;
var serverUrl;
if (Xrm.Page.context.getClientUrl !== undefined) {
serverUrl = Xrm.Page.context.getClientUrl();
} else {
serverUrl = Xrm.Page.context.getServerUrl();
}
var ODataPath = serverUrl + "/XRMServices/2011/OrganizationData.svc";
var contactRequest = new XMLHttpRequest();
contactRequest.open("GET", ODataPath + "/ContactSet(guid'" + contactId + "')", false);
contactRequest.setRequestHeader("Accept", "application/json");
contactRequest.setRequestHeader("Content-Type", "application/json; charset=utf-8");
contactRequest.send();
if (contactRequest.status === 200) {
var retrievedContact = JSON.parse(contactRequest.responseText).d;
var parentAccount = retrievedContact.ParentCustomerId;
if (parentAccount.Id != null && parentAccount.LogicalName == "account") {
var newParentAccount = new Array();
newParentAccount[0] = new Object();
newParentAccount[0].id = parentAccount.Id;
newParentAccount[0].name = parentAccount.Name;
newParentAccount[0].entityType = parentAccount.LogicalName;
Xrm.Page.getAttribute("str_companyid").setValue(newParentAccount);
} else {
Xrm.Page.getAttribute("str_companyid").setValue(null);
}
} else {
alert("error");
}
} else {
Xrm.Page.getAttribute("str_companyid").setValue(null);
}
}
}
to be called inside OnLoad event and OnChange event of the to field.
Related
I try to create folder in sharepoint online, based on some of tutorial. the problem comes since creating folder is not given "Title" column value.
I want to create folder and also update column "Title".
here is the code for create folder
public string CreateDocumentLibrary(string siteUrl, string relativePath)
{
//bool responseResult = false;
string resultUpdate = string.Empty;
string responseResult = string.Empty;
if (siteUrl != _siteUrl)
{
_siteUrl = siteUrl;
Uri spSite = new Uri(siteUrl);
_spo = SpoAuthUtility.Create(spSite, _username, WebUtility.HtmlEncode(_password), false);
}
string odataQuery = "_api/web/folders";
byte[] content = ASCIIEncoding.ASCII.GetBytes(#"{ '__metadata': { 'type': 'SP.Folder' }, 'ServerRelativeUrl': '" + relativePath + "'}");
string digest = _spo.GetRequestDigest();
Uri url = new Uri(String.Format("{0}/{1}", _spo.SiteUrl, odataQuery));
// Set X-RequestDigest
var webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
webRequest.Headers.Add("X-RequestDigest", digest);
// Send a json odata request to SPO rest services to fetch all list items for the list.
byte[] result = HttpHelper.SendODataJsonRequest(
url,
"POST", // reading data from SP through the rest api usually uses the GET verb
content,
webRequest,
_spo // pass in the helper object that allows us to make authenticated calls to SPO rest services
);
string response = Encoding.UTF8.GetString(result, 0, result.Length);
if (response != null)
{
//responseResult = true;
responseResult = response;
}
return responseResult;
}
I already tried to use CAML, but, the problem is, the list of sharepoint is big, so got the error prohibited access related to limit tresshold.
Please help.
Refer below code to update folder name.
function renameFolder(webUrl,listTitle,itemId,name)
{
var itemUrl = webUrl + "/_api/Web/Lists/GetByTitle('" + listTitle + "')/Items(" + itemId + ")";
var itemPayload = {};
itemPayload['__metadata'] = {'type': getItemTypeForListName(listTitle)};
itemPayload['Title'] = name;
itemPayload['FileLeafRef'] = name;
var additionalHeaders = {};
additionalHeaders["X-HTTP-Method"] = "MERGE";
additionalHeaders["If-Match"] = "*";
return executeJson(itemUrl,"POST",additionalHeaders,itemPayload);
}
function getItemTypeForListName(name) {
return"SP.Data." + name.charAt(0).toUpperCase() + name.slice(1) + "ListItem";
}
In Add Link page, is it possible to change the default values like title, address, show these links to, by using URL parameters?
According to this, it seems possible in sharepoint2010. Does anyone know whether it works in 2013??
If not, is it possible to add a link by post REST API??
This problem can be solved by the steps below.
Add a custom action. Just follow the steps here.
In my case code is as below
SP.SOD.executeFunc("callout.js", "Callout", function() {
var itemCtx = {};
itemCtx.Templates = {};
itemCtx.BaseViewID = 'Callout';
// Define the list template type
itemCtx.ListTemplateType = 101;
itemCtx.Templates.Footer = function(itemCtx) {
// context, custom action function, show the ECB menu (boolean)
return CalloutRenderFooterTemplate(itemCtx, AddCustomAction, true);
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(itemCtx);
});
function AddCustomAction(renderCtx, calloutActionMenu) {
// Add your custom action
calloutActionMenu.addAction(new CalloutAction({
text: "FAVORITE",
// tooltip: 'This is your custom action',
onClickCallback: function() {
CreateCustomNewQuickLink(renderCtx.CurrentItem.FileLeafRef, renderCtx.CurrentItem.FileRef);
}
}));
// Show the default document library actions
CalloutOnPostRenderTemplate(renderCtx, calloutActionMenu);
}
function CreateCustomNewQuickLink(title, url) {
var urlAddress = $(location).attr('protocol') + "//" + $(location).attr('host') + '/_Layouts/quicklinksdialogformTEST.aspx?Mode=Link' +
'&title=' + encodeURIComponent(title) +
'&url=' + encodeURIComponent(url);
ShowNewQuicklinkPopup(urlAddress, PageRefreshOnDialogClose);
}
Create a new add link page which is copied from "quicklinksdialogform.aspx". I add some javascript as below.
$(init)
function init() {
var args = new Object();
args = GetUrlParms();
if (args["title"] != undefined) {
$(".ms-long")[0].value = decodeURIComponent(args["title"]);
}
if (args["url"] != undefined) {
$(".ms-long")[1].value = decodeURIComponent(args["url"]);
}
}
function GetUrlParms() {
var args = new Object();
var query = location.search.substring(1);
var pairs = query.split("&");
for (var i = 0; i < pairs.length; i++) {
var pos = pairs[i].indexOf('=');
if (pos == -1) continue;
var argname = pairs[i].substring(0, pos);
var value = pairs[i].substring(pos + 1);
args[argname] = unescape(value);
}
return args;
}
It works like below
I’m testing document signing via a Docusign template through the Docusign API. Once the document signing is complete, each recipient is supposed to receive a Document completed notification, with the link to view the document. But the Document completion Notification is not sent to each recipient as expected, when signing process is initiated using the DocuSign API. Please direct me to the help link on this.
I also, would like to know how to set up the certificate completion document to be sent to each recipient on completion of signing. Any help on above is appreciated.
Thanks
I am seeing you are setting clientUserId for all types of signers except Vendor roles. Now setting clientUserId for the signer tells DocuSign that you are implementing embedded signing in your app. As its an embedded signing, so by Default and Design, DocuSign does not send any types of email notification to the embedded signer. To make DocuSign send the completion email with Certification of Completion, you need to modify Signing Settings in your DocuSign Account. In your DS Account, Go To Admin -> Select Signing Settings from the Left Hand Side Navigation under SIGNING AND SENDING section. Then, scroll to the bottom on Signing Settings page to Envelope Delivery section as shown in below screenshot, select Send Completion emails to embedded signers and also select Attach Certificate of completion to envelope. This should resolve your issue.
Please find below the code for creating and sending envelope and initiating signing for the Agent and Purchaser roles.
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult Create(CreateContractViewModel viewModel)
{
if (!ModelState.IsValid)
return Json(new { success = false, errors=ModelStateExtensions.GetErrors(ViewData.ModelState.Values) }, JsonRequestBehavior.AllowGet);
try
{
#region "Validation"
if (viewModel.Purchasers == null) //only allow max. of 2 purchasers at this point in time.
return Json(new { success = false, errors = "Minimum of one Purchaser is required." },
JsonRequestBehavior.AllowGet);
if (viewModel.Purchasers.Count > 2) //only allow max. of 2 purchasers at this point in time.
return Json(new { success = false, errors = "Number of Purchasers allowed exceed." },
JsonRequestBehavior.AllowGet);
#endregion
// Get template based on drop down selection.
var envTemplate = Templates.Get(viewModel.SelectTemplateId);
// Assign all parties. eg. recipients, signers, and CCs
var docusignRecipients = envTemplate.Recipients;
var signers = docusignRecipients.Signers;
var carbonCopies = docusignRecipients.CarbonCopies;
var templateRolesList = new List<TemplateRole>();
if (viewModel.Purchasers.Count == 1) //remove Purchaser 2 if there's only 1 Purchaser needed.
{
var remove = signers.SingleOrDefault(x => x.RoleName.Equals(RoleNames.Purchaser_2));
if (remove != null)
signers.Remove(remove);
}
// Minimum of 1 Purchaser must exist.
var purchaser1 = viewModel.Purchasers[0];
var purchaser2 = viewModel.Purchasers.Count > 1
? viewModel.Purchasers[1]
: new Purchaser();
#region "Setup Template Roles"
// Recipients
var envelopeRecipients = new Recipients
{
RecipientCount = docusignRecipients.RecipientCount,
Signers = new List<Signer>(),
CarbonCopies = new List<CarbonCopy>()
};
// Signers
TemplateRoles.Signers.AddRoles(viewModel, signers, purchaser1, purchaser2, envelopeRecipients,
docusignRecipients);
// Carbon Copies
TemplateRoles.CarbonCopies.AddRoles(carbonCopies, envelopeRecipients, docusignRecipients);
#endregion
#region "Prepare & Create Envelope"
// Server template
var serverTemplates = new List<ServerTemplate>
{
new ServerTemplate
{
Sequence = "1",
TemplateId = viewModel.SelectTemplateId
}
};
// Server inline template
var serverInlineTemplates = new List<InlineTemplate>
{
new InlineTemplate
{
Sequence = "2",
Recipients = envelopeRecipients
}
};
// refactor this part to a new method.
var documentFactory = new DocumentFactory(viewModel.SelectTemplateId, _documentService);
var type = viewModel.OptionalInserts.GetType();
var optionalInserts = type.GetProperties();
var templateList = new List<CompositeTemplate>();
foreach (var insert in optionalInserts)
{
var value = insert.GetValue(viewModel.OptionalInserts);
var isChecked = (bool)value;
if (!isChecked) continue;
var template = documentFactory.GetTemplate(insert.Name);
var compositeTemplate = template.Compose();
templateList.Add(compositeTemplate);
}
// Prepare composite template, combining the Server and Inline templates
var compositeTemplates = new List<CompositeTemplate>
{
new CompositeTemplate
{
ServerTemplates = serverTemplates,
InlineTemplates = serverInlineTemplates
}
};
templateList.ForEach(t => compositeTemplates.Add(t));
// Create Envelope Definition
var envDef = Envelopes.CreateEnvDef(envTemplate, compositeTemplates);
// Create Envelope
var envSummary = Envelopes.CreateEnvelope(envDef);
#endregion
#region "Generate View Url"
// Generate recipient Url - Agent as 1st recipient by default
var agent = envelopeRecipients.Signers.SingleOrDefault(x => x.RoleName.Equals(RoleNames.Agent));
if (agent == null)
return
Json(
new
{
success = false,
errors = "No Agent role has been found.",
JsonRequestBehavior.AllowGet
});
var returnUrl = Url.Action("Sign", "Contract",
new { envelopeId = envSummary.EnvelopeId, routingOrder = agent.RoutingOrder, selectedTemplateId = viewModel.SelectTemplateId });//modified on 15-6-2017
// Get View Options.
var viewOptions = DocuSign.Recipients.ViewRequest(returnUrl, agent.ClientUserId, agent.Name, agent.Email);
// Create Recipient View
var view = Envelopes.CreateRecipientView(envSummary.EnvelopeId, viewOptions);
#endregion
return Json(new { success = true, returnUrl = view.Url, JsonRequestBehavior.AllowGet });
}
catch (Exception e)
{
return Json(new
{
success = false,
errors = e.Message,
JsonRequestBehavior.AllowGet
});
}
}
public ActionResult Sign(CreateContractViewModel viewModel)
//public ActionResult Sign() //previous code
{
var paramEvent = Request.QueryString["event"];
var paramEnvId = Request.QueryString["envelopeId"];
var paramRoutingOrder = Request.QueryString["routingOrder"];
var selectedTemplateId = Request.QueryString["selectedTemplateId"];
var contractIdQueryString = Request.QueryString["contractId"];
// Validation
if (string.IsNullOrEmpty(paramEvent) || string.IsNullOrEmpty(paramEnvId) ||
string.IsNullOrEmpty(paramRoutingOrder) || (paramEvent != SigningStatus.Signing_Complete))
return View("Error");
// Get next Signer
var recipients = Envelopes.ListRecipients(paramEnvId);
var signers = recipients.Signers;
///////addded on 25/5/2017 to check docusign value extraction
//var cfe = Envelopes.ListRecipientsWithTags(paramEnvId);
//Envelopes.ListCustomFields(paramEnvId);
//List<TextCustomField> tcfList = cfe.TextCustomFields;
//foreach (var tcf in tcfList)
//{
// string dfd = tcf.FieldId;
// string ddfdfd = tcf.Name;
// string sdf = tcf.Value;
// //string str = cfe.TextCustomFields[0].FieldId;
//}
//EnvelopesApi envelopesApi = new EnvelopesApi();
//CustomFieldsEnvelope cfe = envelopesApi.ListCustomFields(accountId, _templateId2);
//TemplateCustomFields cfUpdate = new TemplateCustomFields();
//cfUpdate.TextCustomFields = new System.Collections.Generic.List<TextCustomField>();
//TextCustomField tcf = new TextCustomField();
//tcf.FieldId = cfe.TextCustomFields[0].FieldId;
// Get template based on drop down selection.
//var envTemplate = Templates.Get(viewModel.SelectTemplateId);
//// Assign all parties. eg. recipients, signers, and CCs
//var docusignRecipients = envTemplate.Recipients;
//var signers1 = docusignRecipients.Signers;
int ContractId = 0;
if (contractIdQueryString != null && contractIdQueryString !="")
{
ContractId = int.Parse(contractIdQueryString.Trim());
}
ContractId= GetTabs(signers, selectedTemplateId, paramRoutingOrder, ContractId);
/////
//note:ClientUserId is made null only for the Vendor role in TemplateRoles.Signers.AddRoles method, so that
//signing continues for the Agent and Purchaser roles only
var nextSigner = (from s in signers
where
!string.IsNullOrEmpty(s.ClientUserId) &&
(Convert.ToInt32(s.RoutingOrder) > Convert.ToInt32(paramRoutingOrder))
orderby s.RoutingOrder
select s).FirstOrDefault();
//added following on 06/06/2018 to prevent workflow from proceeding to the next signers. But this will prevent capturing signed dates by signers
//if( paramEvent == "signing_complete" && paramRoutingOrder == "1")
// {
// return View("Completed");
// }
// return View("Completed");
//
#region Code that proceeds workflow to the next signer. Need to have an option to allow agent to go for following approach which allows purchaser to sign via the application or, another option that allows purchaser to receive an email notification for completing signing as done in above commented code
// No next Signer redirect to Completed page.
if (nextSigner == null) return View("Completed");
//var returnUrl = Url.Action("Sign", "Contract",
// new
// {
// envelopeId = paramEnvId,
// routingOrder = nextSigner.RoutingOrder,
// recipientId = nextSigner.RecipientId
// });//original code
var returnUrl = Url.Action("Sign", "Contract",
new
{
envelopeId = paramEnvId,
routingOrder = nextSigner.RoutingOrder,
recipientId = nextSigner.RecipientId,
selectedTemplateId = selectedTemplateId,
contractId = ContractId
});//modified on 19-6-2017
// Get View Options.
var viewOptions = DocuSign.Recipients.ViewRequest(returnUrl, nextSigner.ClientUserId, nextSigner.Name,
nextSigner.Email);
// Create Recipient View
var view = Envelopes.CreateRecipientView(paramEnvId, viewOptions);
return Redirect(view.Url);
#endregion
}
public static class TemplateRoles
{
public static class Signers
{
public static void AddRoles(CreateContractViewModel viewModel, List<Signer> signers, Purchaser purchaser1, Purchaser purchaser2,
global::DocuSign.eSign.Model.Recipients r, global::DocuSign.eSign.Model.Recipients recipients)
{
try
{
foreach (var signer in signers)
{
switch (signer.RoleName)
{
default:
throw new Exception("Unknown Signer role was found on the template.");
region "Role: Agent"
case RoleNames.Agent:
// Fill all Sign tabs for Agent role, which includes Purchaser fields.
// Agent role is the first point of the draft, therefore all the fields need to be prefilled.
var signerTabs = signer.Tabs;
if (signerTabs != null)
{
if (signerTabs.TextTabs != null)
{
var signerTextTabs = signerTabs.TextTabs;
DocuSign.Tabs.Sign(viewModel, signerTextTabs, purchaser1, purchaser2);
}
if (signerTabs.CheckboxTabs != null)
{
var signerCheckboxTabs = signerTabs.CheckboxTabs;
DocuSign.Tabs.SignCheckBoxes(viewModel, signerCheckboxTabs, purchaser1, purchaser2);//Assigning check box values
}
}
var agentSigner = recipients.Signers.Find(x => x.RoleName == "Agent");
if (agentSigner != null)
{
var s = new Signer();
s = agentSigner;
s.RoleName = signer.RoleName;
s.Name = signer.Name;
s.Email = signer.Email;
s.RoutingOrder = signer.RoutingOrder;
s.ClientUserId = Guid.NewGuid().ToString();
s.Tabs = signerTabs;
r.Signers.Add(s);
}
break;
#endregion
#region "Role: Purchaser 1"
case RoleNames.Purchaser_1:
var purchaserSigner = recipients.Signers.Find(x => x.RoleName == "Purchaser 1");
if (purchaserSigner != null)
{
var p1 = new Signer();
p1 = purchaserSigner;
p1.RoleName = RoleNames.Purchaser_1;
p1.Name =
(!string.IsNullOrEmpty(purchaser1.CompanyName)
? purchaser1.CompanyName
: $"{purchaser1.FirstName} {purchaser1.Surname}");
p1.Email = (!string.IsNullOrEmpty(purchaser1.Email) ? purchaser1.Email : null);
p1.RoutingOrder = signer.RoutingOrder;
p1.ClientUserId = Guid.NewGuid().ToString();
p1.Tabs = signer.Tabs;
r.Signers.Add(p1);
}
break;
#endregion
#region "Role: Purchaser 2"
case RoleNames.Purchaser_2:
var purchaser2Signer = recipients.Signers.Find(x => x.RoleName == "Purchaser 2");
if (purchaser2Signer != null)
{
var p2 = new Signer();
p2 = purchaser2Signer;
p2.RoleName = RoleNames.Purchaser_2;
p2.Name =
(!string.IsNullOrEmpty(purchaser2.CompanyName)
? purchaser2.CompanyName
: $"{purchaser2.FirstName} {purchaser2.Surname}");
p2.Email = (!string.IsNullOrEmpty(purchaser2.Email) ? purchaser2.Email : null);
p2.RoutingOrder = signer.RoutingOrder;
p2.ClientUserId = Guid.NewGuid().ToString();
p2.Tabs = signer.Tabs;
r.Signers.Add(p2);
}
break;
#endregion
#region "Role: Vendor"
case RoleNames.Vendor: // No embedded signing.
var vendorSigner = recipients.Signers.Find(x => x.RoleName == "Vendor");
if (vendorSigner != null)
{
var v = new Signer();
v = vendorSigner;
v.RoleName = signer.RoleName;
v.Name = signer.Name;
v.Email = signer.Email;
v.RoutingOrder = signer.RoutingOrder;
v.ClientUserId = null;
r.Signers.Add(v);
}
break;
#endregion
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
}
}
I have a list, but I only want to narrow down my list to only documents with the current unid which appears on the browser, I did this by calling on the getDocumentByKey method of the viewEv object and pass in the unid arguement.
Strangly, this worked for only the newest document. The other documents, just shows all the list not belonging to the unid on the browser.
Any help will be appreciated.
Below is my code:
function getCalObj(){
var viewEv:NotesView = database.getView("Diary");
viewEv.setAutoUpdate(false);
var docEv:NotesDocument = viewEv.getFirstDocument();
var doc:NotesDocument = diaryDoc.getDocument();
var sUNID = doc.getUniversalID();
print("unid: " + sUNID);
docEv = viewEv.getDocumentByKey(sUNID, true);
while (docEv != null) {
........
}
}
Use getAllDocumentsByKey() to get all documents with this sUNID.
var dcEv:NotesDocumentCollection = viewEv.getAllDocumentsByKey(sUNID);
if (dcEv.getCount() > 0) {
var docEv:NotesDocument = dcEv.getFirstDocument();
while (docEv != null) {
........
}
Being very new to SharePoint coding I have been assigned the task to create a prototype code to upload a file and setting the field values for that file that will show up when opening the sharepoint page with the file.
This has to be done from a remote machine and not the Sharepoint server itself so using the .Net objects for Sharepoint is out the question.
I quickly found out how to upload a file through the Sharepoint Web Service Copy.asmx:
void UploadTestFile() {
var file = #"C:\Temp\TestFile.doc";
string destinationUrl = "http://mysharepointserver/Documents/"
+ Path.GetFileName(file);
string[] destinationUrls = { destinationUrl };
var CopyWS = new Copy.Copy();
CopyWS.UseDefaultCredentials = true;
CopyWS.Url = "http://mysharepointserver/_vti_bin/copy.asmx";
CopyResult[] result;
byte[] data = File.ReadAllBytes(file);
FieldInformation mf1 = new FieldInformation {
DisplayName = "title",
InternalName = "title",
Type = FieldType.Text,
Value = "Dummy text"
};
FieldInformation mf2 = new FieldInformation {
DisplayName = "MyTermSet",
InternalName = "MyTermSet",
Type = FieldType.Note,
Value = "Test; Unit;"
};
CopyWS.CopyIntoItems(
"+",
destinationUrls,
new FieldInformation[] { mf1, mf2 },
data,
out result);
}
This code easily uploads any file to the target site but only fills the "title" field with info. The field MyTermSet in which I have added 3 terms allready - Test, Unit and Page - will not update with the values "Test;" and "Unit;".
Being very new to Sharepoint and me not grasping all the basics googling has told me that updating "File", "Computed" or "Lookup" fields does not work with the CopyIntoItems method, and MyTermSet being a Taxonomy field is - if I am correct - a Lookup field.
So how do I get MyTermSet updated with the values "Test;" and "Unit;" ?
I would really prefer If someone has a sample code on this. I have followed several hint-links but I am none the wiser. I have found no sample-code on this at all.
Have anyone made one single method that wraps it all? Or another method that takes in the destinationUrl from the file upload and updates the Term Set/Taxonomy field.
Puzzling together what I have found so far, I am now able to do as I wanted. But I would really like to be able to get the Taxonomy field GUIDs dynamically and NOT having to explicitly set them myself:
void UploadTestFile(string FileName, string DocLib, Dictionary<string, string> Fields = null) {
//Upload the file to the target Sharepoint doc lib
string destinationUrl = DocLib + Path.GetFileName(FileName);
string[] destinationUrls = { destinationUrl };
var CopyWS = new Copy.Copy();
CopyWS.UseDefaultCredentials = true;
CopyWS.Url = new Uri(new Uri(DocLib), "/_vti_bin/copy.asmx").ToString();
CopyResult[] result;
var data = File.ReadAllBytes(FileName);
CopyWS.CopyIntoItems(
"+",
destinationUrls,
new FieldInformation[0],
data,
out result);
if (Fields == null) return; //Done uploading
//Get the ID and metadata information of the fields
var list = new ListsWS.Lists();
list.UseDefaultCredentials = true;
var localpath = new Uri(DocLib).LocalPath.TrimEnd('/');
var site = localpath.Substring(0, localpath.LastIndexOf("/")); //Get the site of the URL
list.Url = new Uri(new Uri(DocLib), site + "/_vti_bin/lists.asmx").ToString(); //Lists on the right site
FieldInformation[] fiOut;
byte[] filedata;
var get = CopyWS.GetItem(destinationUrl, out fiOut, out filedata);
if (data.Length != filedata.Length) throw new Exception("Failed on uploading the document.");
//Dictionary on name and display name
var fieldInfos = fiOut.ToDictionary(x => x.InternalName, x => x);
var fieldInfosByName = new Dictionary<string, FieldInformation>();
foreach (var item in fiOut) {
if (!fieldInfosByName.ContainsKey(item.DisplayName)) {
fieldInfosByName.Add(item.DisplayName, item);
}
}
//Update the document with fielddata - this one can be extended for more than Text and Note fields.
if (!fieldInfos.ContainsKey("ID")) throw new Exception("Could not get the ID of the upload.");
var ID = fieldInfos["ID"].Value; //The ID of the document we just uploaded
XDocument doc = new XDocument(); //Creating XML with updates we need
doc.Add(XElement.Parse("<Batch OnError='Continue' ListVersion='1' ViewName=''/>"));
doc.Element("Batch").Add(XElement.Parse("<Method ID='1' Cmd='Update'/>"));
var methNode = doc.Element("Batch").Element("Method");
//Add ID
var fNode = new XElement("Field");
fNode.SetAttributeValue("Name", "ID");
fNode.Value = ID;
methNode.Add(fNode);
//Loop each field and add each Field
foreach (var field in Fields) {
//Get the field object from name or display name
FieldInformation fi = null;
if (fieldInfos.ContainsKey(field.Key)) {
fi = fieldInfos[field.Key];
}
else if (fieldInfosByName.ContainsKey(field.Key)) {
fi = fieldInfosByName[field.Key];
}
if (fi != null) {
//Fix for taxonomy fields - find the correct field to update
if (fi.Type == FieldType.Invalid && fieldInfos.ContainsKey(field.Key + "TaxHTField0")) {
fi = fieldInfos[field.Key + "TaxHTField0"];
}
else if (fi.Type == FieldType.Invalid && fieldInfosByName.ContainsKey(field.Key + "_0")) {
fi = fieldInfosByName[field.Key + "_0"];
}
fNode = new XElement("Field");
fNode.SetAttributeValue("Name", fi.InternalName);
switch (fi.Type) {
case FieldType.Lookup:
fNode.Value = "-1;#" + field.Value;
break;
case FieldType.Choice:
case FieldType.Text:
fNode.Value = field.Value;
break;
case FieldType.Note: //TermSet's
var termsetval = "";
var terms = field.Value.Split(';');
foreach (var term in terms) {
termsetval += "-1;#" + term + ";";
}
fNode.Value = termsetval.TrimEnd(';');
break;
default:
//..Unhandled type. Implement if needed.
break;
}
methNode.Add(fNode); //Adds the field to the XML
}
else {
//Field does not exist. No use in uploading.
}
}
//Gets the listname (not sure if it is the full path or just the folder name)
var listname = new Uri(DocLib).LocalPath;
var listcol = list.GetListCollection(); //Get the lists of the site
listname = (from XmlNode x
in listcol.ChildNodes
where x.Attributes["DefaultViewUrl"].InnerText.StartsWith(listname, StringComparison.InvariantCultureIgnoreCase)
select x.Attributes["ID"].InnerText).DefaultIfEmpty(listname).First();
//Convert the XML to XmlNode and upload the data
var xmldoc = new XmlDocument();
xmldoc.LoadXml(doc.ToString());
list.UpdateListItems(listname, xmldoc.DocumentElement);
}
Then I call it like this:
var fields = new Dictionary<string, string>();
fields.Add("Test", "Dummy Text");
fields.Add("MrTermSet", "Page|a4ba29c1-3ed5-47e9-b43f-36bc59c0ea5c;Unit|4237dfbe-22a2-4d90-bd08-09f4a8dd0ada");
UploadTestFile(#"C:\Temp\TestFile2.doc", #"http://mysharepointserver/Documents/", fields);
I would however prefer to call it like this:
var fields = new Dictionary<string, string>();
fields.Add("Test", "Dummy Text");
fields.Add("MrTermSet", "Page;Unit");
UploadTestFile(#"C:\Temp\TestFile2.doc", #"http://mysharepointserver/Documents/", fields);