Sending email with template using trigger - apex-code

I have the following Trigger:
trigger send_notification on Inquery__c (after update) {
Inquery__c inquery = trigger.new[0];
String[] toAddresses = new String[] {inquery.email__c};
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setTargetObjectId(inquery.OwnerID);
mail.setSenderDisplayName('Salesforce Support');
mail.setUseSignature(false);
mail.setBccSender(false);
mail.setSaveAsActivity(false);
if (Trigger.isUpdate) {
if(inquery.Quilification__c == 'Qualified') {
EmailTemplate et=[Select id from EmailTemplate where DeveloperName=:'Invitation_to_register_for_Class'];
mail.setTemplateId(et.id);
Messaging.SendEmailResult [] r =
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});
}
if(inquery.Quilification__c == 'Disqualified') {
EmailTemplate et=[Select id from EmailTemplate where DeveloperName=:'Ineligible_course_candidate'];
mail.setTemplateId(et.id);
Messaging.SendEmailResult [] r =
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});
}
}
}
I managed to fix this from its original problem,
And just wanted to share,
Thanks

I managed to fix it and send the email,
I have updated the code,
i.e. the code above works

Related

Error comparing current app version number with latest. Version name=production.release.1.0.0.5 and lastest version= [duplicate]

I need to check current version of Installed Application and Playstore application version. If it is not same app should navigate to Playstore .
im using xam.Plugin.LatestVersion(2.1.0) To get the latestversion number of application from play console. unfortunately not getting latest version number of application from play store. The below code im using.
private async void ChekAppVersion()
{
try
{
latestVersionNumber = await CrossLatestVersion.Current.GetLatestVersionNumber();
installedVersionNumber = CrossLatestVersion.Current.InstalledVersionNumber;
if (installedVersionNumber != latestVersionNumber)
{
await DisplayAlert("New Version", "There is a new version of this app available. Please update now?", "Ok");
await CrossLatestVersion.Current.OpenAppInStore();
ChekAppVersion();
}
else
{
}
}
catch (Exception ex)
{
}
}
Im getting the installedVersionNumber, but im unable to get the latestVersionNumber(Playstore).
Please help on this.
They have removed the version from div, now it's displayed with js, but data is still there inside a <script> tag. My current fixed code is:
private bool _lockCheckUpdates;
public async Task<bool> CheckNeedUpdate()
{
if (Connectivity.NetworkAccess != NetworkAccess.Internet || _lockCheckUpdates)
return false;
_lockCheckUpdates = true;
try
{
HttpClient myClient = CreateClient();
if (Device.RuntimePlatform == Device.Android)
{
var bundle = "com.todo.app"; //ANDROID BUNDLE NAME HERE
string url = $"https://play.google.com/store/apps/details?id={bundle}&hl=en";
string raw = await myClient.GetStringAsync(new Uri(url));
var doc = new HtmlDocument();
doc.LoadHtml(raw);
var scripts = doc.DocumentNode.Descendants()
.Where(n => n.Name == "script" && n.InnerText.Contains("AF_initDataCallback({key: 'ds:4'"))
.ToArray();
var script = scripts.First().InnerText;
var engine = new Jurassic.ScriptEngine();
var eval = "(function() { var AF_initDataCallback = function(p) { return p.data[1][2][140][0][0][0]; }; return " + script + " })()";
var result = engine.Evaluate(eval);
//var json = JSONObject.Stringify(engine, result); //for debug, check in browser console with JSON.parse(json)
var remote = $"{result}".ToDouble();
var local = App.Version.ToDouble();
return local < remote;
}
else if (Device.RuntimePlatform == Device.iOS)
{
var bundle = "com.todo.app";//iOS BUNDLE NAME HERE
string url = $"http://itunes.apple.com/lookup?bundleId={bundle}";
string raw = await myClient.GetStringAsync(new Uri(url));
var dto = JsonConvert.DeserializeObject<AppStoreRecord>(raw);
double local = App.Version.ToDouble();
if (dto.ResultCount > 0)
{
double remote = dto.Results[0].Version.ToDouble();
return remote > local;
}
}
}
catch (Exception e)
{
Logger.Error("CheckNeedUpdate", e);
}
finally
{
_lockCheckUpdates = false;
}
return false;
}
Using nugets
Jurassic to evaluate the script on page,
HtmlAgilityPack to parse html,
Xamarin.Essentials to check if we are online,
and AppoMobi.Specials for .ToDouble() etc
I hope this could also be useful to fix https://github.com/edsnider/latestversionplugin/issues/43 :)
The plugin you are using no longer works for Android https://github.com/edsnider/latestversionplugin/issues/43
You will need to find a new way to get the desired information.
PR has been made on this plugin... it works again ;-)

Not receiving Change Notification of Calendar Events containing custom properties

We want to receive change notifications from our user's Outlook calendars. We'd like to limit those notifications to only those calendar items that contain our custom property.
CODE WHICH CREATES CALENDAR EVENT
private static async Task<Event> CreateAppointmentAsync(GraphServiceClient graphClient)
{
var newEvent = new Microsoft.Graph.Event
{
Subject = "Test Calendar Appointmnt",
Start = new DateTimeTimeZone() { TimeZone = TimeZoneInfo.Local.Id, DateTime = "2020-11-21T21:00:00" },
End = new DateTimeTimeZone() { TimeZone = TimeZoneInfo.Local.Id, DateTime = "2020-11-21T22:00:00" },
Location = new Location() { DisplayName = "Somewhere" },
Body = new ItemBody { Content = "Some Random Text" },
};
Microsoft.Graph.Event addedEvent;
try
{
newEvent.SingleValueExtendedProperties = new EventSingleValueExtendedPropertiesCollectionPage();
newEvent.SingleValueExtendedProperties.Add(new SingleValueLegacyExtendedProperty { Id = "String {00020329-0000-0000-C000-000000000046} Name CompanyID", Value = "12345" });
addedEvent = await graphClient.Me.Calendar.Events.Request().AddAsync(newEvent);
}
catch (Exception e)
{
throw e;
}
return addedEvent;
}
THE SUBSCRIPTION CODE SNIPPET
var subscription = new Subscription
{
ChangeType = "created",
NotificationUrl ="<OUR-URL>",
Resource = "me/events/?$filter=singleValueExtendedProperties/any(ep: ep/id eq 'String {00020329-0000-0000-C000-000000000046} Name CompanyID' and ep/value ne null)",
ExpirationDateTime = DateTimeOffset.Parse("2020-11-13T18:23:45.9356913Z"),
ClientState = "custom_data_state",
LatestSupportedTlsVersion = "v1_2"
};
The subscription is created successfully, but notifications are not being sent for those items containing the specific custom property described above.
It turns out I was only capturing the "created" notification. I neglected to add "updated" and "deleted".
I was testing with an event that already existed in my calendar. No events were being fired because I didn't create the subscription to detect updates and deletes.
Here is the corrected subscription:
var subscription = new Subscription
{
ChangeType = "created,updated,deleted",
NotificationUrl ="<OUR-URL>",
Resource = "me/events/?$filter=singleValueExtendedProperties/any(ep: ep/id eq 'String {00020329-0000-0000-C000-000000000046} Name CompanyID' and ep/value ne null)",
ExpirationDateTime = DateTimeOffset.Parse("2020-11-13T18:23:45.9356913Z"),
ClientState = "custom_data_state",
LatestSupportedTlsVersion = "v1_2"
};

CRM 2013 : How can I Schedule Concurrent Appointments (using Appointment & RecurringAppointmentMaster entities)?

We have a plugin that uses the BookRequest & RescheduleRequest Methods to schedule Appointment & RecurringAppointmentMaster entities.
Recently I was tasked with implementing the ability to schedule multiple appts in a given timeslot.
So in researching this, I found some posts referring to resource capacity (in work hours) & setting the Effort field of the ActivityParty to 1.0 in the Appointment.
I thought, great this will be easy.
So I changed the plugin to store the effort:
activityParty = new Entity("activityparty");
activityParty["partyid"] = new EntityReference("systemuser", apptCaregiverId);
activityParty["effort"] = (Double)1.0;
But when I ran the code, the BookRequest returned this error that confused me: ErrorCode.DifferentEffort
I searched for ErrorCode.DifferentEffort, 2139095040, BookRequest, you name it found nothing useful.
What exactly does this error mean?
Why is it so difficult to schedule concurrent appointments in CRM?
This is what I learned the hard way, so maybe it will spare someone else some frustration.
I looked in the database & noticed that the activityparty entities associated with appointments all had the effort field set to 2139095040 and I wondered where that number was coming from? In a post unrelated to CRM, I found out the 2139095040 means 'positive infinity'.
I revisited the posts where they talk about setting the effort to 1.0 & realized that they were all referring to the ServiceAppointment entity (not Appointment) and then I finally stumbled on the list of error codes
Scheduling Error Codes
DifferentEffort = The required capacity of this service does not match the capacity of resource {resource name}.
Not exactly the truth, but whatever.
The real issue is the Appointment entity does not reference a Service, therefore the capacity of the non-existent service is ‘Positive Infinity’ (2139095040).
Setting the Effort equal to anything but 2139095040 throws this error.
It isn’t really checking the capacity of the resource here, it’s just saying that the non-existent service capacity must be = 2139095040
Anyway to get around this I removed the logic that sets the effort = 1.0 and when BookRequest or RescheduleRequest returns ErrorCode.ResourceBusy, I check the Capacity vs the # appts scheduled in that timeslot & if there is capacity left over, I force it to overbook by using Create or Update.
private Guid BookAppointment(Entity appointment, bool setState, out List<string> errors)
{
Guid apptId = Guid.Empty;
try
{
BookRequest request = new BookRequest
{
Target = appointment
};
BookResponse booked = (BookResponse)this.orgService.Execute(request);
apptId = ParseValidationResult(booked.ValidationResult, setState, appointment, true, out errors);
}
catch (Exception ex)
{
errors = new List<string> { ex.GetBaseException().Message };
}
return apptId;
}
private Guid RescheduleAppointment(Entity appointment, out List<string> errors)
{ // used to reschedule non-recurring appt or appt in recurrence
Guid apptId = Guid.Empty;
try
{
RescheduleRequest request = new RescheduleRequest
{
Target = appointment
};
RescheduleResponse rescheduled = (RescheduleResponse)this.orgService.Execute(request);
apptId = ParseValidationResult(rescheduled.ValidationResult, false, appointment, false, out errors);
}
catch (Exception ex)
{
errors = new List<string> { ex.GetBaseException().Message };
}
return apptId;
}
private Guid ParseValidationResult(ValidationResult result, bool setState, Entity appointment, Boolean addNew, out List<string> errors)
{
Guid apptId = result.ActivityId;
errors = new List<string>();
if (result.ValidationSuccess == true)
{
if (setState == true)
{
SetStateRequest state = new SetStateRequest();
state.State = new OptionSetValue(3); // Scheduled
state.Status = new OptionSetValue(5); // Busy
state.EntityMoniker = new EntityReference("appointment", apptId);
SetStateResponse stateSet = (SetStateResponse)this.orgService.Execute(state);
}
}
else
{
String error;
String errortxt;
Boolean overbookAppt = true;
foreach (var errorInfo in result.TraceInfo.ErrorInfoList)
{
bool unavailable = false;
if (errorInfo.ErrorCode == "ErrorCode.ResourceNonBusinessHours")
{
errortxt = "{0} is being scheduled outside work hours";
}
else if (errorInfo.ErrorCode == "ErrorCode.ResourceBusy")
{
errortxt = "{0} is unavailable at this time";
unavailable = true;
}
else
{
errortxt = "failed to schedule {0}, error code = " + errorInfo.ErrorCode;
}
Dictionary<Guid, String> providers;
Dictionary<Guid, String> resources;
DateTime start = DateTime.Now, end = DateTime.Now;
Guid[] resourceIds = errorInfo.ResourceList.Where(r => r.EntityName == "equipment").Select(r => r.Id).ToList().ToArray();
if (unavailable == true)
{
if (appointment.LogicalName == "recurringappointmentmaster")
{
start = (DateTime)appointment["starttime"];
end = (DateTime)appointment["endtime"];
}
else
{
start = (DateTime)appointment["scheduledstart"];
end = (DateTime)appointment["scheduledend"];
}
Dictionary<Guid, Boolean> availability = GetAvailabilityOfResources(resourceIds, start, end);
resourceIds = availability.Where(a => a.Value == false).Select(t => t.Key).ToArray(); // get ids of all unavailable resources
if (resourceIds.Count() == 0)
{ // all resources still have capacity left at this timeslot - overbook appt timeslot
overbookAppt = true;
} // otherwise at least some resources are booked up in this timeslot - return error
}
if (errortxt.Contains("{0}"))
{ // include resource name in error msg
if (resourceIds.Count() > 0)
{
LoadProviderAndResourceInfo(resourceIds, out providers, out resources);
foreach (var resource in providers)
{
error = String.Format(errortxt, resource.Value);
errors.Add(error);
}
foreach (var resource in resources)
{
error = String.Format(errortxt, resource.Value);
errors.Add(error);
}
}
}
else
{ // no place for name in msg - just store it
errors.Add(errortxt);
break;
}
}
if (overbookAppt == true && errors.Count() == 0)
{ // all resources still have capacity left at this timeslot & no other errors have been returned - create appt anyway
if (addNew)
{
appointment.Attributes.Remove("owner"); // Create message does not like when owner field is specified
apptId = this.orgService.Create(appointment);
if (setState == true)
{
SetStateRequest state = new SetStateRequest();
state.State = new OptionSetValue(3); // Scheduled
state.Status = new OptionSetValue(5); // Busy
state.EntityMoniker = new EntityReference("appointment", apptId);
SetStateResponse stateSet = (SetStateResponse)this.orgService.Execute(state);
}
}
else
{
this.orgService.Update(appointment);
}
}
}
return apptId;
}
private Dictionary<Guid, Boolean> GetAvailabilityOfResources(Guid[] resourceIds, DateTime start, DateTime end)
{
Dictionary<Guid, Boolean> availability = new Dictionary<Guid, Boolean>();
QueryMultipleSchedulesRequest scheduleRequest = new QueryMultipleSchedulesRequest();
scheduleRequest.ResourceIds = resourceIds;
scheduleRequest.Start = start;
scheduleRequest.End = end;
// TimeCode.Unavailable - gets appointments
// TimeCode.Filter - gets resource capacity
scheduleRequest.TimeCodes = new TimeCode[] { TimeCode.Unavailable, TimeCode.Filter };
QueryMultipleSchedulesResponse scheduleResponse = (QueryMultipleSchedulesResponse)this.orgService.Execute(scheduleRequest);
int index = 0;
TimeInfo[][] timeInfo = new TimeInfo[scheduleResponse.TimeInfos.Count()][];
foreach (var schedule in scheduleResponse.TimeInfos)
{
TimeInfo resourceCapacity = schedule.Where(s => s.SubCode == SubCode.ResourceCapacity).FirstOrDefault();
Int32 capacity = (resourceCapacity != null) ? (Int32)resourceCapacity.Effort : 1;
Int32 numAppts = schedule.Where(s => s.SubCode == SubCode.Appointment).Count();
// resource is available if capacity is more than # appts in timeslot
availability.Add(resourceIds[index++], (capacity > numAppts) ? true : false);
}
return availability;
}
This is really a better solution than setting the Effort = 1 anyway because now we don’t need a one-time on-demand workflow to update existing data.
I hope this helps save you some time if you ever need to do this.

CRM SDK 2013 Activity doesn't exist just after creating it

I have a custom comment activity which I'm updating in code and this used to work but has started failing recently. It creates the activity but when I try to retrieve it or execute SetStateResponse on it, I get "tk_comment With Id = 9a1686d1-7d9d-e611-80e3-00155d001104 Does Not Exist" - which doesn't make sense as I've just created it! The activity record shows up against the account but I can't click on it there or do anything (Record is unavailable - The requested record was not found or you do not have sufficient permissions to view it.).
This is the code I'm using. I'd love you to tell me I've made some simple mistake :)
using (_serviceProxy = ServerConnection.GetOrganizationProxy(serverConfig))
{
_serviceProxy.EnableProxyTypes();
try
{
tk_comment comment = new tk_comment();
int maxLength = 190; //subject has a max length of 200 characters
if (subject.Length > maxLength)
{
comment.Subject = subject.Substring(0, maxLength);
comment.Description = subject.Substring(maxLength, subject.Length - maxLength);
}
else
{
comment.Subject = subject;
}
comment.RegardingObjectId = entity.ToEntityReference();
comment.ActualStart = CommentDate;
comment.ActualEnd = CommentDate;
comment.ScheduledStart = CommentDate;
comment.ScheduledEnd = CommentDate;
Guid commentID = _serviceProxy.Create(comment);
try
{
tk_comment aComment = (tk_comment)_serviceProxy.Retrieve(tk_comment.EntityLogicalName, commentID, new ColumnSet(allColumns: true));
}
catch (Exception ex)
{
SingletonLogger.Instance.Error("Always an error here " + ex.Message);
}
Account test = (Account) _serviceProxy.Retrieve(Account.EntityLogicalName, entity.Id, new ColumnSet(allColumns: true));
// tk_comment newComment = (tk_comment)_serviceProxy.Retrieve(tk_comment.EntityLogicalName, commentID, new ColumnSet(allColumns: true));
SetStateRequest request = new SetStateRequest();
request.EntityMoniker = new EntityReference(tk_comment.EntityLogicalName, commentID);
request.State = new OptionSetValue((int) tk_commentState.Completed); //completed
request.Status = new OptionSetValue(2); //completed
SetStateResponse response = (SetStateResponse)_serviceProxy.Execute(request); //always an error here too
}
Appreciate any suggestions
Cheers, Mick
It seems like you don't have proper read permission of this custom activity entity.
OR You need to validate all the permissions of this custom entity.

Different ways of adding items to a dictionary with different results

I'm dabbling in swift after a long time away and I've hit an issue that I can't figure out. I'm trying two different ways to add items to a dictionary and getting some different results.
I was initially adding values to a dictionary by doing:
userInfo = ["username":username]
userInfo = ["email":email]
userInfo = ["password":password]
I would then print("\(userInfo)") but it would only contain password.
I then tried switching it up to:
userInfo!["username"] = username
userInfo!["email"] = email
userInfo!["password"] = password
but this resulted in fatal error: unexpectedly found nil while unwrapping an Optional value for username
I finally switched it to the following configuration
userInfo = ["username":username]
userInfo!["email"] = email
userInfo!["password"] = password
and everything prints put. Whats up with that?
Full implementation:
nextPressed()
{
if let userInfo:[String:String] = try registrationValidation()
{
print("\(userInfo)")
}
}
func registrationValidation () throws -> [String:String]?
{
var userInfo: [String:String]?
var problems: [ValidationMessage] = []
if let username = usernameField.text
{
let p1 = validateUsername(username)
problems.appendContentsOf(p1)
userInfo = ["username":username]
//userInfo!["username"] = username
//Above results in nil, yet lines below work?
}
if let email = emailField.text
{
let p2 = validateEmail(email)
problems.appendContentsOf(p2)
//userInfo = ["email":email]
userInfo!["email"] = email
}
if let password = passwordField.text
{
let p3 = validatePassword(password)
problems.appendContentsOf(p3)
//userInfo = ["password":password]
userInfo!["password"] = password
}
if !problems.isEmpty{
throw ValidationError(problems:problems)
}
else
{
print("validation succeeded")
return userInfo
}
}
I think this would be a better way to do what you want to achieve like :
func registrationValidation () throws -> [String:String]?
{
var userInfo = [String:String]() // **Initialize an empty dictionary**
var problems: [ValidationMessage] = []
if let username = usernameField.text
{
let p1 = validateUsername(username)
problems.appendContentsOf(p1)
userInfo["username"] = username
}
if let email = emailField.text
{
let p2 = validateEmail(email)
problems.appendContentsOf(p2)
//userInfo = ["email":email] **// This line will result in creating a new dictionary object**
userInfo["email"] = email
}
if let password = passwordField.text
{
let p3 = validatePassword(password)
problems.appendContentsOf(p3)
//userInfo = ["password":password]
userInfo["password"] = password
}
if !problems.isEmpty{
throw ValidationError(problems:problems)
}
else
{
print("validation succeeded")
return userInfo
}
}

Resources