In CRM I am trying to automate the process of creating a new email from a previous email in the chain. This email has to go to the customer of the case, who could be either an account or a contact.
I can retrieve the Guid of the contact/account but I dont know how to retrieve the logical name.
This is what I have so far:
OrganizationServiceProxy service = CRMCentralCRMServiceInstance;
Guid customerId = GetCustomerIdFromCase(caseId);
Entity email = new Entity("email");
Entity activityPartyTo = new Entity("activityparty");
//"account" is a guess, it could be "contact"
EntityReference customerReferenceTo = new EntityReference("account", customerId);
activityPartyTo["partyid"] = customerReferenceTo;
EntityCollection toEntityCollection = new EntityCollection();
toEntityCollection.Entities.Add(activityPartyTo);
email["to"] = toEntityCollection;
.
.
.
newEmailId = service.Create(email);
public Guid GetCustomerIdFromCase(Guid caseId) {
Guid customerId = Guid.Empty;
List<CRMCase> caseList = GetCRMCasesById(caseId);
if (caseList.Count > 0)
{
CRMCase cmcCase = caseList.First();
customerId = cmcCase.CustomerId;
}
return (customerId);
}
public List<CRMCase> GetCRMCasesById(Guid caseId)
{
List<CRMCase> crmCases = new List<CRMCase>();
try
{
OrganizationServiceProxy service = CRMCentralCRMServiceInstance;
ConditionExpression condition1 = new ConditionExpression();
ConditionExpression condition2 = new ConditionExpression();
condition1.AttributeName = "incidentid";
condition1.Operator = ConditionOperator.Equal;
condition1.Values.Add(caseId.ToString("N"));
condition2.AttributeName = "statecode";
condition2.Operator = ConditionOperator.In;
condition2.Values.Add("Active");
condition2.Values.Add("Resolved");
FilterExpression filter = new FilterExpression();
filter.FilterOperator = LogicalOperator.And;
filter.Conditions.Add(condition1);
filter.Conditions.Add(condition2);
QueryExpression query = new QueryExpression();
query.EntityName = "incident";
query.ColumnSet = new ColumnSet(true);
query.Criteria = filter;
RetrieveAttributeRequest retrieveAttributeRequest = new RetrieveAttributeRequest();
retrieveAttributeRequest.EntityLogicalName = "incident";
retrieveAttributeRequest.LogicalName = "statuscode";
retrieveAttributeRequest.RetrieveAsIfPublished = true;
RetrieveAttributeResponse retrieveAttributeResponse = (RetrieveAttributeResponse)service.Execute(retrieveAttributeRequest);
StatusAttributeMetadata statusCodeAttribute = (StatusAttributeMetadata)retrieveAttributeResponse.AttributeMetadata;
retrieveAttributeRequest = new RetrieveAttributeRequest();
retrieveAttributeRequest.EntityLogicalName = "incident";
retrieveAttributeRequest.LogicalName = "prioritycode";
retrieveAttributeRequest.RetrieveAsIfPublished = true;
retrieveAttributeResponse = (RetrieveAttributeResponse)service.Execute(retrieveAttributeRequest);
PicklistAttributeMetadata priorityCodeAttribute = (PicklistAttributeMetadata)retrieveAttributeResponse.AttributeMetadata;
retrieveAttributeRequest = new RetrieveAttributeRequest();
retrieveAttributeRequest.EntityLogicalName = "incident";
retrieveAttributeRequest.LogicalName = "statecode";
retrieveAttributeRequest.RetrieveAsIfPublished = true;
retrieveAttributeResponse = (RetrieveAttributeResponse)service.Execute(retrieveAttributeRequest);
StateAttributeMetadata stateCodeAttribute = (StateAttributeMetadata)retrieveAttributeResponse.AttributeMetadata;
EntityCollection casesColl = service.RetrieveMultiple(query);
foreach (Entity entity in casesColl.Entities)
{
Entity incidentCRMCase = entity;
CRMCase cRMCase = GetCRMCaseFromIncidentCase(incidentCRMCase, statusCodeAttribute.OptionSet.Options, stateCodeAttribute.OptionSet.Options, priorityCodeAttribute.OptionSet.Options);
crmCases.Add(cRMCase);
}
}
catch (SoapException se)
{
string action = MethodBase.GetCurrentMethod().DeclaringType.Name + " :: " + MethodBase.GetCurrentMethod().Name;
string message = "Unexpected error in action: " + action
+ Environment.NewLine + se.Message
+ Environment.NewLine + se.Detail.InnerText;
throw new Exception(message);
}
return (crmCases);
}
I found this brute force method but I would rather find a cleaner way if there is.
Ok. Really complicated code. Try to use something like following:
private EntityReference GetCustomerFromCase(Guid caseId)
{
Entity Case = CRMCentralCRMServiceInstance.Retrieve("incident", caseId, new ColumnSet("customerid"));
return Case.GetAttributeValue<EntityReference>("customerid");
}
Related
I am using following code snippet to set the Invoice ID of Invoices in plugin pre-operation. But I am unable to do so. I want to seek your kind suggestion to set the value.
Update
QueryExpression qe = new QueryExpression
{
EntityName = "invoice",
ColumnSet = new ColumnSet("salesorderid", "invoicenumber"),
Criteria = new FilterExpression
{
Conditions = {
new ConditionExpression("salesorderid",ConditionOperator.Equal,orderId)
}
}
};
EntityCollection ec = service.RetrieveMultiple(qe);
if (ec.Entities.Count == 0)
{
string orderName = generateInvoiceID(service, orderId);
foreach (Entity id in ec.Entities)
{
id.Attributes["invoicenumber"] = Convert.ToInt32(orderName) + 01;
}
}
Looking at the snippet looks like you have the plugin registered on "SalesOrder" entity and you are trying to update invoice entity, so it does not matter if it is a pre-op or a post-op, you would need to explicitly call IOrganizationService.Update
var qe = new QueryExpression
{
EntityName = "invoice",
ColumnSet = new ColumnSet("salesorderid", "invoicenumber"),
Criteria = new FilterExpression
{
Conditions =
{
new ConditionExpression("salesorderid", ConditionOperator.Equal, orderId)
}
}
};
var ec = service.RetrieveMultiple(qe);
var orderName = generateInvoiceID(service, orderId);
foreach (var entity in ec.Entities)
{
var invoice = new Entity("invoice") { Id = entity.Id };
invoice.Attributes.Add("invoicenumber", Convert.ToInt32(orderName) + 01);
service.Update(invoice); //call the update method.
}
I am trying to write the following a (pseudo)query in C# for CRM 4:
Status = active
AND
(
mail = somemail
OR
(
firstName like firstNameSearchTerm
AND
lastName like LastNameSearchTerm
)
)
The problem is, that middle names might be part of firstName or LastName. I am having a hard time putting this into ConditionExpressions / FilterExpressions.
#region mail conditions
// Create the ConditionExpression.
ConditionExpression mail1Condition = new ConditionExpression();
mail1Condition.AttributeName = "emailaddress1";
mail1Condition.Operator = ConditionOperator.Like;
mail1Condition.Values = new object[] { Registration.Email };
ConditionExpression mail2Condition = new ConditionExpression();
mail2Condition.AttributeName = "emailaddress2";
mail2Condition.Operator = ConditionOperator.Like;
mail2Condition.Values = new object[] { Registration.Email };
ConditionExpression mail3Condition = new ConditionExpression();
mail3Condition.AttributeName = "emailaddress3";
mail3Condition.Operator = ConditionOperator.Like;
mail3Condition.Values = new object[] { Registration.Email };
ConditionExpression statusCondition = new ConditionExpression();
statusCondition.AttributeName = "statuscode";
statusCondition.Operator = ConditionOperator.Equal;
statusCondition.Values = new object[] { "1" };
FilterExpression mailFilter = new FilterExpression();
mailFilter.FilterOperator = LogicalOperator.Or;
mailFilter.Conditions = new ConditionExpression[] { mail1Condition, mail2Condition, mail3Condition };
#endregion mail conditions
#region name conditions
/* FIRST NAME */
FilterExpression firstNameFilter = new FilterExpression();
firstNameFilter.FilterOperator = LogicalOperator.Or;
List<ConditionExpression> firstNameConditions = new List<ConditionExpression>();
var firstAndMiddleNames = Registration.FirstName.Trim().Split(' ');
firstAndMiddleNames = firstAndMiddleNames.Select(s => s.Replace(s, "%"+s+"%")).ToArray(); // Add wildcard search
foreach (var item in firstAndMiddleNames)
{
ConditionExpression firstNameCondition = new ConditionExpression();
firstNameCondition.AttributeName = "firstname";
firstNameCondition.Operator = ConditionOperator.Like;
firstNameCondition.Values = new object[] { item };
firstNameConditions.Add(firstNameCondition);
}
firstNameFilter.Conditions = firstNameConditions.ToArray();
/* LAST NAME */
FilterExpression lastNameFilter = new FilterExpression();
lastNameFilter.FilterOperator = LogicalOperator.Or;
List<ConditionExpression> lastNameConditions = new List<ConditionExpression>();
var lastAndMiddleNames = Registration.LastName.Trim().Split(' ');
lastAndMiddleNames = lastAndMiddleNames.Select(s => s.Replace(s, "%" + s + "%")).ToArray(); // Add wildcard search
foreach (var item in lastAndMiddleNames)
{
ConditionExpression lastNameCondition = new ConditionExpression();
lastNameCondition.AttributeName = "lastname";
lastNameCondition.Operator = ConditionOperator.Like;
lastNameCondition.Values = new object[] { item };
lastNameConditions.Add(lastNameCondition);
}
lastNameFilter.Conditions = firstNameConditions.ToArray();
#endregion name conditions
FilterExpression nameFilter = new FilterExpression();
nameFilter.FilterOperator = LogicalOperator.And;
nameFilter.Filters = new FilterExpression[] { firstNameFilter, lastNameFilter };
// Create the outer most filter to AND the state condition with the other filters
FilterExpression stateFilter = new FilterExpression();
stateFilter.FilterOperator = LogicalOperator.And;
stateFilter.Conditions = new ConditionExpression[] { statusCondition };
stateFilter.Filters = new FilterExpression[] { nameFilter };
query.EntityName = EntityName.contact.ToString();
query.Criteria = stateFilter;
query.ColumnSet = columns;
BusinessEntityCollection contacts = Service.RetrieveMultiple(query);
I
The query currently bypasses the mail filter for debugging purposes.
The result is that it finds all contacts matching the firstname or lastname (should be AND). Why???
There was a simple typo in the following line
lastNameFilter.Conditions = firstNameConditions.ToArray();
should be
lastNameFilter.Conditions = lastNameConditions.ToArray();
I am able to successfully create an invoice, and a payment, but don't seem to be able to properly link the payment to the invoice. I have tried several variations, but it either does not link at all, or I get a "Business Validation Error: Unexpected Internal Error." error in my error logs. Below is my c# code. Is there a simplified way (example) of linking a payment to an invoice?
Invoice i = QBGet_InvoiceByMDVInvoiceNum(MDVInvoiceNum);
Payment p = new Payment();
Customer customer = QBGet_CustomerByName(ClientName, "CompanyName");
Account acc = QBGet_AccountsReceivableAccount();
p.TxnDate = DateTime.Now;
p.TxnDateSpecified = true;
List<Line> lineList1 = new List<Line>();
Line pmtLine = new Line();
pmtLine.Amount = ReceivedPaymentAmt;
pmtLine.AmountSpecified = true;
List<LinkedTxn> linkedTxnList = new List<LinkedTxn>();
LinkedTxn linkedtxn = new LinkedTxn();
linkedtxn.TxnId = i.Id;
linkedtxn.TxnType = "invoice";
linkedTxnList.Add(linkedtxn);
pmtLine.LinkedTxn = linkedTxnList.ToArray();
//p.LinkedTxn = linkedTxnList.ToArray();
lineList1.Add(pmtLine);
p.Line = lineList1.ToArray();
p.CustomerRef = new ReferenceType()
{
Value = customer.Id
};
p.DepositToAccountRef = new ReferenceType() { Value = acc.Id };
p.PaymentRefNum = ReceiptCheckNo;
p.TotalAmt = ReceivedPaymentAmt;
p.TotalAmtSpecified = true;
DataService service = new DataService(context);
var result = service.Add<Payment>(p);
I have also tried this approach:
p.CustomerRef = new ReferenceType()
{
Value = customer.Id
};
p.PrivateNote ="ReferralID: " + ReferralId + "\r\n" + "PaymentDetailID: " + PaymentDetailID + "\r\n" + Comments;
p.PaymentRefNum = ReceiptCheckNo;
p.PaymentType = PaymentTypeEnum.Check;
p.PaymentTypeSpecified = true;
p.DocNumber = MDVInvoiceNum;
p.TotalAmt = ReceivedPaymentAmt;
p.TotalAmtSpecified = true;
p.TxnDate = PaymentReceivedDate;
p.TxnDateSpecified = true;
LinkedTxn[] lt = {new LinkedTxn()
{
TxnId=i.Id,
TxnType="invoice"
}
};
Line l = new Line()
{
Amount = ReceivedPaymentAmt,
LinkedTxn = lt
};
Line[] aryL = {l};
DataService service = new DataService(context);
Payment pmt = service.Add(p);
p.Line = aryL;
p.LinkedTxn = lt;
Payment pmt2 = service.Update(p);
Sharing the Java code and corresponding working JSON payload. It might help.
private void paymentAgainstInvoice() {
Payment payment = new Payment();
Date currentDateTime = null;
try {
currentDateTime = DateUtils.getCurrentDateTime();
} catch (ParseException e) {
e.printStackTrace();
}
payment.setTxnDate(currentDateTime);
Line line = new Line();
line.setAmount(new BigDecimal("100"));
LinkedTxn linkedTxn = new LinkedTxn();
linkedTxn.setTxnId("248");
linkedTxn.setTxnType("Invoice");
List<LinkedTxn> linkedTxnList = new ArrayList<LinkedTxn>();
linkedTxnList.add(linkedTxn);
line.setLinkedTxn(linkedTxnList);
List<Line> lineList = new ArrayList<Line>();
lineList.add(line);
payment.setLine(lineList);
ReferenceType custReferenceType = new ReferenceType();
custReferenceType.setValue("29");
custReferenceType.setName("ABC");
payment.setCustomerRef(custReferenceType);
payment.setTotalAmt(new BigDecimal("100"));
ReferenceType accountRefType = new ReferenceType();
accountRefType.setValue("63");
payment.setPaymentRefNum("ABC-100-Invoice");
payment.setDepositToAccountRef(accountRefType );
try {
this.service.add(payment);
} catch (FMSException e) {
e.printStackTrace();
}
}
JSON payload ( Payment )
{
"CustomerRef":{
"value":"29",
"name":"ABC"
},
"DepositToAccountRef":{
"value":"63"
},
"PaymentRefNum":"ABC-100-Invoice",
"TotalAmt":100,
"TxnDate":"2014-11-30",
"Line":[
{
"Amount":100,
"LinkedTxn":[
{
"TxnId":"248",
"TxnType":"Invoice"
}
]
}
]
}
I have an issue with my plugin, I have a custom entity new_smsmessage and from my plugin I want to retrieve custom attributes to send text message, but it gives me the following error message "The given key was not present in the dictionary". The plugin's code is shown bellow and the names of attributes are correct in the CRM entity:
public void Execute(IServiceProvider serviceProvider)
{
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
Entity entity = (Entity)context.InputParameters["target"];
string uservalue = "";
string phonevalue = "";
string aliasevalue = "";
ColumnSet columnSet = new ColumnSet(true);
ColumnSet allFields = new ColumnSet() { AllColumns = true };
ExternalSMSService1.ExternalSMSService wbSrvSMS = new ExternalSMSService1.ExternalSMSService();
string strToken = wbSrvSMS.Login(userName, pwd);
string smsResult = string.Empty;
if (entity.Attributes.Contains("new_username"))
{
uservalue = entity.Attributes["new_username"].ToString();
}
else
{
throw new InvalidPluginExecutionException("field name not found");
}
if (entity.Attributes.Contains("new_userphone"))
{
phonevalue = entity.Attributes["new_userphone"].ToString();
}
else
{
throw new InvalidPluginExecutionException("field Phone not found");
}
if (entity.Attributes.Contains("new_aliasecode"))
{
phonevalue = entity.Attributes["new_aliasecode"].ToString();
}
else
{
throw new InvalidPluginExecutionException("aliase Phone not found");
}
string smsmessage = entity.Attributes["new_message"].ToString();
string[] strArr = null;
string[] strArr2;
char[] splitchar = { ';' };
strArr = uservalue.Split(splitchar);
char[] splitchar2 = { '-' };
strArr2 = phonevalue.Split(splitchar2);
for (int i = 0; i < strArr.Length; i++)
{
StringBuilder strMsg = new StringBuilder();
strMsg.Append("<SEND_SMS>");
strMsg.Append("<MSG_DATA TEXT='" + smsmessage + "' SHORT_CODE='" + aliasevalue + "'/>");
strMsg.Append("<RECIPIENTS>");
strMsg.Append("<RECIPIENT MOBILE_NUMBER='" + strArr2[i].ToString() + "' RECP_NAME ='" + strArr[i].ToString() + "'/>");
strMsg.Append("</RECIPIENTS>");
strMsg.Append("</SEND_SMS>");
smsResult = wbSrvSMS.SendSMS(strMsg.ToString(), strToken);
}
}
Try to change line
Entity entity = (Entity)context.InputParameters["target"];
to
Entity entity = (Entity)context.InputParameters["Target"];
It's ok now, i've just forgot to modify my variable
Thanks
Always first check key before getting like.
if (_entity.Attributes.ContainsKey("field1"))
{Here code to get field1 value }
Because return entity not contains attributes having null values.
I'm trying to pull information from a CRM installation and so far this is fine for using the default fields. However I'm having difficulty retrieving custom fields, for example Contacts have a custom field called web_username.
My code at present is
QueryExpression query = new QueryExpression();
query.EntityName = "contact";
ColumnSet cols = new ColumnSet();
cols.Attributes = new string[] { "firstname", "lastname" };
query.ColumnSet = cols;
BusinessEntityCollection beReturned = tomService.RetrieveMultiple(query);
foreach (contact _contact in beReturned.BusinessEntities)
{
DataRow dr = dt.NewRow();
dr["firstname"] = _contact.firstname;
dr["lastname"] = _contact.lastname;
dt.Rows.Add(dr);
}
How do I include custom fields in my query? I've tried searching around but with no luck yet but I could be searching incorrectly as I'm not used to CRM terms.
Cheers in advance!
I've since been able to solve this. In case it is of use to anyone else this is what I did. The query is set up as before except I've added my custom field to the ColumnSet.
cols.Attributes = new string[] { "firstname", "lastname", "new_web_username" };
And then used RetrieveMultipleResponse and Request with ReturnDynamicEntities set to true
RetrieveMultipleResponse retrived = new RetrieveMultipleResponse();
RetrieveMultipleRequest retrive = new RetrieveMultipleRequest();
retrive.Query = query;
retrive.ReturnDynamicEntities = true;
retrived = (RetrieveMultipleResponse)tomService.Execute(retrive);
Please still comment if there is a better way for me to do this.
EDIT
Using the example in my original question if you cast to a contact
contact myContact = (contact)myService.Retrieve(EntityName.contact.ToString(), userID, cols);
You can then access properties of the object
phone = myContact.telephone1;
password = myContact.new_password;
If you update your CRM webreference custom fields you've added in CRM are available.
public List<Entity> GetEntitiesCollection(IOrganizationService service, string entityName, ColumnSet col)
{
try
{
QueryExpression query = new QueryExpression
{
EntityName = entityName,
ColumnSet = col
};
var testResult = service.RetrieveMultiple(query);
var testResultSorted = testResult.Entities.OrderBy(x => x.LogicalName).ToList();
foreach (Entity res in testResultSorted)
{
var keySorted = res.Attributes.OrderBy(x => x.Key).ToList();
DataRow dr = null;
dr = dt.NewRow();
foreach (var attribute in keySorted)
{
try
{
if (attribute.Value.ToString() == "Microsoft.Xrm.Sdk.OptionSetValue")
{
var valueofattribute = GetoptionsetText(entityName, attribute.Key, ((Microsoft.Xrm.Sdk.OptionSetValue)attribute.Value).Value, _service);
dr[attribute.Key] = valueofattribute;
}
else if (attribute.Value.ToString() == "Microsoft.Xrm.Sdk.EntityReference")
{
dr[attribute.Key] = ((Microsoft.Xrm.Sdk.EntityReference)attribute.Value).Name;
}
else
{
dr[attribute.Key] = attribute.Value;
}
}
catch (Exception ex)
{
Response.Write("<br/>optionset Error is :" + ex.Message);
}
}
dt.Rows.Add(dr);
}
return testResultSorted;
}
catch (Exception ex)
{
Response.Write("<br/> Error Message : " + ex.Message);
return null;
}
}
//here i have mentioned one another function:
var valueofattribute = GetoptionsetText(entityName, attribute.Key, ((Microsoft.Xrm.Sdk.OptionSetValue)attribute.Value).Value, _service);
//definition of this function is as below:
public static string GetoptionsetText(string entityName, string attributeName, int optionSetValue, IOrganizationService service)
{
string AttributeName = attributeName;
string EntityLogicalName = entityName;
RetrieveEntityRequest retrieveDetails = new RetrieveEntityRequest
{
EntityFilters = EntityFilters.All,
LogicalName = entityName
};
RetrieveEntityResponse retrieveEntityResponseObj = (RetrieveEntityResponse)service.Execute(retrieveDetails);
Microsoft.Xrm.Sdk.Metadata.EntityMetadata metadata = retrieveEntityResponseObj.EntityMetadata;
Microsoft.Xrm.Sdk.Metadata.PicklistAttributeMetadata picklistMetadata = metadata.Attributes.FirstOrDefault(attribute => String.Equals(attribute.LogicalName, attributeName, StringComparison.OrdinalIgnoreCase)) as Microsoft.Xrm.Sdk.Metadata.PicklistAttributeMetadata;
Microsoft.Xrm.Sdk.Metadata.OptionSetMetadata options = picklistMetadata.OptionSet;
IList<OptionMetadata> OptionsList = (from o in options.Options
where o.Value.Value == optionSetValue
select o).ToList();
string optionsetLabel = (OptionsList.First()).Label.UserLocalizedLabel.Label;
return optionsetLabel;
}