I have the following code that creates a case in SugarCRM via C#.
I am asking, does anybody know how I would go about adding a reply on this case via c# to sugarCRM api?
NameValueCollection fieldListCollection = new NameValueCollection();
fieldListCollection.Add("id", string.Empty);
fieldListCollection.Add("name", "Something went wrong");
fieldListCollection.Add("description", "This software is not working");
fieldListCollection.Add("status", "test"); //New, Assigned, Closed, Pending Input, Rejected, Duplicate
fieldListCollection.Add("priority", "test"); //High, Medium, Low
fieldListCollection.Add("account_id", AccountId); // Don't pass this if you don't want to associate an account with it
fieldListCollection.Add("contact_id", ContactId); // Don't pass this if you don't want to associate with this contact with it
SugarCRM.name_value[] fieldList = new SugarCRM.name_value[fieldListCollection.Count];
int count = 0;
foreach (string name in fieldListCollection)
{
foreach (string value in fieldListCollection.GetValues(name))
{
SugarCRM.name_value field = new SugarCRM.name_value();
field.name = name; field.value = value;
fieldList[count] = field;
}
count++;
}
SugarCRM.new_set_entry_result result = SugarClient.set_entry(SessionID, "Cases", fieldList); //Accounts, Incidents, Contacts, Cases
Console.WriteLine("New ID: " + result.id);
Related
foreach (var part in emailInfoResponse.Result.Payload.Parts)
{
if (part.Parts != null)
foreach (var innerPart in part.Parts)
{
if (innerPart.MimeType == "text/plain")
{
body = innerPart.Body.Data;
}
}
}
I am successfully reading the body ONLY of the main mail. It is not taking the data from the reply messages assigned to the mail,
any ideas how I can I read the replies to the mail too? Or even if there is a way to take only the replies of a specific mail
To get later / other messages in a conversation, you need to retrieve the source thread:
String threadID = emailInfoResponse.Result.ThreadId;
Thread thread = service.Users.Threads.Get(userID, threadID).Execute();
foreach( var msg in thread.Messages )
{
/* your code for each message */
}
Per the Gmail message reference, messages can share a threadId if they have both the correct headers and the same subject. Otherwise, they will be on different email threads.
You'd probably want to refactor a bit and start from a ThreadList. This way, you can find all conversations that match a specific input query (to find only the messages that correspond to these client lists):
Make data storage object: Dictionary<String, Container>, where the string is the company (from the email subject, or wherever), and the container probably only needs unique values so HashSet or similar.
Page through the ThreadList
For each thread
Page through messages
For each message, if the first message, get the subject i.e. company name (all messages have to share a subject in the same thread).
Then append the clients to the data storage object based on the subject (company name).
Construct your database records from the data storage object as appropriate.
public static MimeKit.MimeMessage Reply(MimeKit.MimeMessage message, bool replyToAll)
{
var reply = new MimeKit.MimeMessage();
if (message.ReplyTo.Count > 0)
{
reply.To.AddRange(message.ReplyTo);
}
else if (message.From.Count > 0)
{
reply.To.AddRange(message.From);
}
else if (message.Sender != null)
{
reply.To.Add(message.Sender);
}
if (replyToAll)
{
reply.To.AddRange(message.To);
reply.Cc.AddRange(message.Cc);
}
if (!message.Subject.StartsWith("Re:", StringComparison.OrdinalIgnoreCase))
reply.Subject = "Re:" + message.Subject;
else
reply.Subject = message.Subject;
if (!string.IsNullOrEmpty(message.MessageId))
{
reply.InReplyTo = message.MessageId;
foreach (var id in message.References)
reply.References.Add(id);
reply.References.Add(message.MessageId);
}
using (var quoted = new StringWriter())
{
var sender = message.Sender ?? message.From.Mailboxes.FirstOrDefault();
quoted.WriteLine("On {0}, {1} wrote:", message.Date.ToString("f"), !string.IsNullOrEmpty(sender.Name) ? sender.Name : sender.Address);
using (var reader = new StringReader(message.TextBody))
{
string line;
while ((line = reader.ReadLine()) != null)
{
quoted.Write("> ");
quoted.WriteLine(line);
}
}
reply.Body = new MimeKit.TextPart("plain")
{
Text = quoted.ToString()
};
}
return reply;
}
I am using Sendgrid to send emails with templates that contain multiple variables.
Everything works well when I have only one recipient for an email.
When I have multiple recipients either in To or one in To and one in Cc, the first email is ok but the following have empty strings in the substition tags.
Below is my code :
private bool SendEmail(MailAddress from, string[] to, string template, Dictionary<string, string> keyToReplace, string[] cc = null)
{
var message = new SendGridMessage();
message.From = from;
message.AddTo(to);
if (cc != null && cc.Any())
{
foreach (var ccAddress in cc)
{
message.AddCc(ccAddress);
}
}
message.Subject = " ";
message.Text = string.Empty;
message.Html = "<p></p>";
message.EnableTemplate("<%body%>");
message.EnableTemplateEngine(templateIds[template]);
foreach (var keyValue in keyToReplace)
{
var key = keyValue.Key;
if (!key.StartsWith("#"))
{
key = string.Format("#{0}#", key);
}
var value = keyValue.Value;
if (string.IsNullOrEmpty(keyValue.Value))
{
value = " ";
}
message.AddSubstitution(key, new List<string> { value });
}
var transportWeb = transportFactory(credentials);
transportWeb.Deliver(message);
logger.Info("Mail sent to : " + string.Join(", ", to));
return true;
}
I enventually updated the Sendgrid nuget package from version 5.0.0 to version 9.5.0 and it fixed the issue.
I have a DB ad Microsoft Identity Manager to generate user accounts from HR to MS Active Directory and so on.
I have a such code for generate unique email:
case "mailgenerate":
if (mventry["email"].IsPresent)
{
// Do nothing, the mail was already generated.
}
{
if (csentry["FIRST"].IsPresent && csentry["LAST"].IsPresent);
{
string FirstName = replaceRUEN(csentry["FIRST"].Value);
string LastName = replaceRUEN(csentry["LAST"].Value);
string email = FirstName + "." + LastName + "#test.domain.com";
string newmail = GetCheckedMail(email, mventry);
if (newmail.Equals(""))
{
throw new TerminateRunException("A unique mail could not be found");
}
mventry["email"].Value = newmail;
}
}
break;
//Generate mail Name method
string GetCheckedMail(string email, MVEntry mventry)
{
MVEntry[] findResultList = null;
string checkedmailName = email;
for (int nameSuffix = 1; nameSuffix < 100; nameSuffix++)
{
//added ; and if corrected
findResultList = Utils.FindMVEntries("email", checkedmailName,1);
if (findResultList.Length == 0)
{
// The current mailName is not in use.
return (checkedmailName);
}
MVEntry mvEntryFound = findResultList[0];
if (mvEntryFound.Equals(mventry))
{
return (checkedmailName);
}
// If the passed email is already in use, then add an integer value
// then verify if the new value exists. Repeat until a unique email is checked
checkedmailName = checkedmailName + nameSuffix.ToString();
}
// Return an empty string if no unique mailnickName could be created.
return "";
}
Problem:
When I run sync cycle for first time I get normal email like
duplicateuser1#test.domain.com
For next sync cycle this emails are updated to
duplicateuser#test.domain.com1
This code I'm also using to generate mailnickname and accountname without any problems.
Can anybody say why it is happens?
Thanks!
The problem is the line:
checkedmailName = checkedmailName + nameSuffix.ToString();
checkedmailName has a value like this: firstName.lastName#test.domain.com
So, you're doing this:
checkedmailName = firstName.lastName#test.domain.com + 1;
You need to do something like this:
checkedmailName = checkedmailName.Split('#')[0] + nameSuffix.ToString()+ "#" + checkedmailName.Split('#')[1];
Whith this, you're getting the part before #, adding a int value and then, appending the #+ domain.
Updated by author of thread I changed split -> Split and it works. Thanks!
I have a scenario in CRM where I need to update existing accounts with their Vat and Registration number. There is well over 30 thousand accounts in the system. I am trying to update using the CRM SDK API but I am battling to figure out how to perform the actual update. The vat number and reg have been provided to me in a spreadsheet with their corresponding number, please note that the accounts are already in CRM so I just need to update the correct account with its Vat and Reg number, How can I do this in CRM, please advice on my code below:
public static void UpdateAllCRMAccountsWithVATAndRegistrationNumber(IOrganizationService service)
{
QueryExpression qe = new QueryExpression();
qe.EntityName = "account";
qe.ColumnSet = new ColumnSet("account", "new_vatno", "new_registrationnumber");
qe.Criteria.AddCondition("accountnumber", ConditionOperator.In,"TA10024846", "TA10028471", "TA20014015", "TA4011652", "TA4011557");
EntityCollection response = service.RetrieveMultiple(qe);
foreach (var acc in response.Entities)
{
acc.Attributes["new_vatno"] = //this is where I am struggling to figure out how I am gong to match the records up,
acc.Attributes["new_registrationnumber"] = //this is where I am struggling to figure out how I am gong to match the records up,
service.Update(acc);
}
}
How am I going to ensure that I update the correct records. I have the vat and reg numbers for the accounts in a spreadsheet, please see example image below. Can I please get advised here. Thanks.
I would load the list of VAT updates from the spreadsheet into a dictionary and then load the 30k record from CRM into memory. Then I would match them up and use ExecuteMultipleRequest to do the updates. Alternatively, you could query CRM using the account numbers (if the list is small enough.) I made the assumption you had thousands of updates to do across the record set of 30k. Note, if the Account record size was very large and couldn't be loaded into memory you would need to do account number queries.
Here is the rough code for the basic solution (I haven't tested, method should be split up, and there is minimal error handling):
public class VatInfo
{
public string RegistrationNumber;
public string TaxNumber;
public static Dictionary<string, VatInfo> GetVatList()
{
//TODO: Implement logic to load CSV file into a list. Dictionary key value should be Account Number
throw new NotImplementedException();
}
}
public class UpdateVatDemo
{
public const int maxBatchSize = 100;
public static void RunVatUpdate(IOrganizationService conn)
{
var vats = VatInfo.GetVatList();
var pagingQuery = new QueryExpression("account");
pagingQuery.ColumnSet = new ColumnSet("accountnumber");
Queue<Entity> allEnts = new Queue<Entity>();
while (true)
{
var results = conn.RetrieveMultiple(pagingQuery);
if (results.Entities != null && results.Entities.Any())
results.Entities.ToList().ForEach(allEnts.Enqueue);
if (!results.MoreRecords) break;
pagingQuery.PageInfo.PageNumber++;
pagingQuery.PageInfo.PagingCookie = results.PagingCookie;
}
ExecuteMultipleRequest emr = null;
while (allEnts.Any())
{
if (emr == null)
emr = new ExecuteMultipleRequest()
{
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = true,
ReturnResponses = true
},
Requests = new OrganizationRequestCollection()
};
var ent = allEnts.Dequeue();
if (vats.ContainsKey(ent.GetAttributeValue<string>("accountnumber")))
{
var newEnt = new Entity("account", ent.Id);
newEnt.Attributes.Add("new_vatno", vats[ent.GetAttributeValue<string>("accountnumber")].TaxNumber);
newEnt.Attributes.Add("new_registrationnumber", vats[ent.GetAttributeValue<string>("accountnumber")].RegistrationNumber);
emr.Requests.Add(new UpdateRequest() { Target = newEnt });
}
if (emr.Requests.Count >= maxBatchSize)
{
try
{
var emResponse = (ExecuteMultipleResponse) conn.Execute(emr);
foreach (
var responseItem in emResponse.Responses.Where(responseItem => responseItem.Fault != null))
DisplayFault(emr.Requests[responseItem.RequestIndex],
responseItem.RequestIndex, responseItem.Fault);
}
catch (Exception ex)
{
Console.WriteLine($"Exception during ExecuteMultiple: {ex.Message}");
throw;
}
emr = null;
}
}
}
private static void DisplayFault(OrganizationRequest organizationRequest, int count,
OrganizationServiceFault organizationServiceFault)
{
Console.WriteLine(
"A fault occurred when processing {1} request, at index {0} in the request collection with a fault message: {2}",
count + 1,
organizationRequest.RequestName,
organizationServiceFault.Message);
}
}
Updating the fetched entity is bound to fail because of its entity state, which would not be null.
To update the fetched entities, you need to new up the entity:
foreach (var acc in response.Entities)
{
var updateAccount = new Entity("account") { Id = acc.Id };
updateAccount .Attributes["new_vatno"] = null; //using null as an example.
updateAccount .Attributes["new_registrationnumber"] = null;
service.Update(acc);
}
Code below shows how I managed to get it righy. forst let me explain. I imported my records into a seperate SQL table, in my code I read that table into a list in memory, I then query CRM accounts that need to be updated, I then loop though each account and check if the account number in CRM matches the account number from my sql database, if it matches, I then update the relevant Reg no and Vat no, See code below:
List<Sheet1_> crmAccountList = new List<Sheet1_>();
//var crmAccount = db.Sheet1_.Select(x => x).ToList().Take(2);
var crmAccounts = db.Sheet1_.Select(x => x).ToList();
foreach (var dbAccount in crmAccounts)
{
CRMDataObject modelObject = new CRMDataObject()
{
ID = dbAccount.ID,
Account_No = dbAccount.Account_No,
Tax_No = dbAccount.Tax_No.ToString(),
Reg_No = dbAccount.Reg_No
//Tarsus_Country = dbAccount.Main_Phone
};
}
var officialDatabaseList = crmAccounts;
foreach (var crmAcc in officialDatabaseList)
{
QueryExpression qe = new QueryExpression();
qe.EntityName = "account";
qe.ColumnSet = new ColumnSet("accountnumber", "new_vatno", "new_registrationnumber");
qe.Criteria.AddCondition("accountnumber", ConditionOperator.In,'list of account numbers go here'
EntityCollection response = service.RetrieveMultiple(qe);
foreach (var acc in response.Entities)
{
if (crmAcc.Account_No == acc.Attributes["accountnumber"].ToString())
{
//acc.Attributes["new_vatno"] = crmAcc.VAT_No.ToString();
acc.Attributes["new_registrationnumber"] = crmAcc.Reg_No.ToString();
service.Update(acc);
}
}
}
Does anybody know if by using tweetsharp, one can send a message to a persons follow list? I have made the following code that allows me to message a single person via userid, but not to a list.
Any ideas?
var service = new
TweetSharp.TwitterService("ConsumerKey","ConsumerSecret","TokenKey","TokenSec
retKey");
var twitterStatus = service.SendTweet(new SendTweetOptions() { Status ="Hello World" });
if (twitterStatus != null)
{
MessageBox.Show("It worked");
}
You can start off by getting the TwitterService object to obtain followers, then follow up with the SendMessage function.
TwitterService service = new TwitterService("key", "secret");
service.AuthenticateWith(userToken, userSecret);
var friendship =
service.GetFriendshipInfo(new GetFriendshipInfoOptions
{
SourceScreenName = "handle",
TargetScreenName = "handle"
});
if (friendship.Relationship.Source.FollowedBy)
{
yield return handle;
}
Then on return do something like:
foreach (string handle in client.ReturnFollowingUsers(handles).Distinct()))
{
TwitterDirectMessage dm = client.SendMessage(handle, message);
}