when user clicks on case to change caseOwner/user, i have to add this user to all associated cases(per customer). I am using below code ,but it is updating only one record/case. i can see in debug logs all cases were updated with latest owner but not really updated/stored in caseObject. please help me this.
trigger caseAssignment on Case (after insert, after update) {
set<id> ownerId = new Set<Id>();
set<id> customerId = new set<Id>();
for(Case caseobj : trigger.new){
ownerId.add(caseobj.OwnerId);
customerId.add(caseobj.AccountId);
}
for( User user:[Select id, FirstName, LastName from user where Id IN :ownerId]){
for(Case cas : [Select Id, OwnerId, First_Name__c, CaseNumber, AccountId From Case where AccountId IN: customerId]){
cas.OwnerId = user.Id;
}
}
Without an update DML statement, your code will have no effect on your data.
Probably should create an update list
i.e. list updateCaseList = new list()
Then in your inner for loop, add "cas" to updateCaseList and then at the end of the method, issue the update command (update updateCaseList).
Assuming that the logic you wrote is correct you're never updating the cases
trigger caseAssignment on Case (after insert, after update)
{
Set<Id> ownerId = new Set<Id>();
Set<Id> customerId = new Set<Id>();
List<Case> casesToUpdate = new List<Case>();
for(Case caseobj : trigger.new)
{
ownerId.add(caseobj.OwnerId);
customerId.add(caseobj.AccountId);
}
for( User user:[Select id, FirstName, LastName from user where Id IN :ownerId])
{
for(Case cas : [Select Id, OwnerId, First_Name__c, CaseNumber, AccountId From Case where AccountId IN: customerId])
{
Case c = new Case();
c.ID = cas.ID;
c.OwnerId = user.Id;
casesToUpdate.add(c);
}
}
update casesToUpdate;
}
Related
I have below requirement and I'm new to SF development, need assistance if my approach is correct or not.
When any update happens on ServiceTerritory object, if the Time_Zone__c field of ServiceTerritory is not matching with User Object TimeZoneSidKey field, then update ServiceTerritory object Time_Zone__c field with User Object TimeZoneSidKey field.
ServiceTerritory object : has Center_Instructor_Contact__c field tagged to ID field in Contact object.
Contact object : has ID field and AccountId field
User Object : has AccountId field
public static void afterUpdate(List<ServiceTerritory> serviceTerritories, Map<Id, ServiceTerritory> oldRecords) {
Set<Id> recIds = new Set<Id>();
for (ServiceTerritory record : serviceTerritories) {
recIds.add(record.Id);
}
Set<Id> STMembers = new Set<Id>();
for (ServiceTerritory member : [SELECT Id, Center_Instructor_Contact__c FROM ServiceTerritory WHERE Id IN :recIds]) {
STMembers.add(member.Center_Instructor_Contact__c);
}
//Contact object : has ID field and AccountId field
Set<Id> ContactIDs = new Set<Id>();
for (Contact Cnt : [SELECT AccountId FROM Contact WHERE Id IN :STMembers]) {
ContactIDs.add(Cnt.AccountId);
}
//User Object : has AccountId field
Set<Id> UserIDs = new Set<Id>();
for (User Cnt : [SELECT AccountId, TimeZoneSidKey FROM User WHERE AccountId IN :ContactIDs]) {
UserIDs.add(Cnt.AccountId);
}
}
and here how to compare and update ServiceTerritory object if the timezone is not matching between the objects.
Not many Salesforce instances will have access to "Field Service Lightning" which is where ServiceTerritory table is used. If you sign up for free Salesforce Developer Edition it probably won't exist there. So it's bit hard to understand the question and help. Plus if you wrote "User Object : has AccountId field" it sounds like you're using Experience Cloud (formerly known as communities), that narrows down the specialists even more.
So it's Service Territory -> "up" to -> Contact -> "down" to (community) -> User?
If you're using community users they'll have AccountId and ContactId in them, no need going via Account (and in fact you could get stupid results that way... What if not all contacts in account are community-enabled, what if they are but have different timezones...)
Try something like that but you'll have to experiment a lot. And change your code to run "before update", you'll get save to database for free
List<ServiceTerritory> serviceTerritories; // passed to your function
Set<Id> contactIds = new Set<Id>();
for (ServiceTerritory st : serviceTerritories) {
contactIds.add(st.Center_Instructor_Contact__c);
}
System.debug(contactIds);
// Grab all these Contacts and their community users (it's a related list so it'll be a subquery but really there will be at most one user
Map<Id, Contact> contacts = new Map<Id, Contact>([SELECT Id,
(SELECT TimezoneSidKey FROM Users)
FROM Contact
WHERE Id IN :contactIds AND Id IN (SELECT ContactId FROM User)]);
// Loop again and check against "reference data"
for (ServiceTerritory st : serviceTerritories) {
if(contacts.containsKey(st.Center_Instructor_Contact__c)){
Contact c = contacts.get(st.Center_Instructor_Contact__c);
System.debug(c);
System.debug('comparing ' + st.Time_Zone__c + ' and ' + c.Users);
if(st.Time_Zone__c != c.Users[0].TimezoneSidKey){
System.debug('fixing ' + st.Id);
st.Time_Zone__c = c.Users[0].TimezoneSidKey;
}
}
}
List<Contact> conList = [SELECT Id, Email FROM Contact WHERE LastName='Smith'];
List<Contact> listToUpdate = new List<Contact>();
for(Contact con:conList)
{
if(con.Email != null)
continue;
else
listToUpdate.add(con);
delete listToUpdate; }
it should delete records with no email.error: System.DmlException: Delete failed. First exception on row 0 with id 0035j00000LnS5fAAF; first error: ENTITY_IS_DELETED, entity is deleted: []
The way you format the code is rubbish. You don't see that you have put the delete operation inside the loop. If you have many contacts and you call delete on something that was deleted in previous iteration - yes, that's the error you'll get.
This is better:
List<Contact> conList = [SELECT Id, Email FROM Contact WHERE LastName='Smith'];
List<Contact> listToUpdate = new List<Contact>();
for(Contact con:conList) {
if(con.Email != null){
continue;
} else {
listToUpdate.add(con);
}
}
delete listToUpdate;
this is best
delete [SELECT Id
FROM Contact
WHERE LastName='Smith' AND Email = null];
because it'll query the minimum amount of rows and there's no loop at all.
I need to add all(SUM) the amount from the opportunity of all closed won opportunity which lies between the start and end date of quota.
Opportunity should be closed won
closed date should be within the start and end date of quota
assigned to the user which is a look up field on quota which is equal to
owner of quota
Below is the code
public with sharing class listopponquota {
public list<Opportunity> oppList{get;set;}
public listopponquota()
{
String selectedVal ='';
oppList = new list<Opportunity>();
oppList();
}
*public pageReference oppList() {
Id qId = (Id) ApexPages.currentPage().getParameters().get('id');
system.debug('Id-->'+qId);
List<Opportunity> oppList1 = new List<Opportunity>();
oppList1 = [Select Id, Name, CloseDate, StageName,OwnerId,Amount From Opportunity where StageName = 'Closed Won'];
system.debug('quotaList1-->'+quotaList1);
if(quotaList1.size() > 0){
for(quota__c q : quotaList1){
map<id,double> amtmap = new map<id,double>();
for(aggregateresult ag : [SELECT SUM(Amount) sum,Quota__c FROM Opportunity where Quota__c in :quotaList1 and StageName = 'Closed Won' group by Quota__c ]){
amtmap.put((ID)ag.get('Quota__c'), double.valueof(ag.get('SUM')));
{
amtmap.put((ID)ag.get('Quota__c'), double.valueof(ag.get('SUM')));
}
list<Quota__c>Qtalist = new list<Quota__c>();
for(id iid : QtaIds){
Quota__c quot = new Quota__c(id=iid);
if(amtmap.containskey(iid)){
q.Actual_Amount__c = amtmap.get(iid);
}else{
q.Actual_Amount__c = 0;
}
Qtalist.add(quot);
}
if(Qtalist.size()>0){
update Qtalist;
return null;
}
}
}
}
}
}*
Part of the issue may be that you are not defining quotaList1. You should also probably pull that SOQL query out of the for loop. Grab all the records you need prior to entering the loop.
A quick modification to your SOQL query:
[SELECT SUM(Amount) sum,Quota__c FROM Opportunity where Quota__c in :quotaList1 and IsWon = true group AND CloseDate >= Quota__r.StartDate__c AND CloseDate <= Quota__r.EndDate__c AND Quota__r.OwnerId =: System.UserInfo.getUserId() by Quota__r.Name ]
Most importantly though, how do the objects relate? Are the opportunities children of the Quota__c object, or is there also a field on the Quota__c defining the opp it is tied to?
I want to use last inserted id from database, but that Id is in string format. Is there any way I can get last inserted string ID?
Every time I am using
p.UserId = db.AspNetUsers.Max(m => m.Id);
but it is returning wrong results. I think it is string so max won't work. Can anyone please suggest how to solve this problem?
Table structure:
Patient: ID (PK), UID (fk of UserLogin), Name
AspNetUsers table:
CREATE TABLE [dbo].[AspNetUsers]
(
[Id] NVARCHAR(128) NOT NULL,
[Email] NVARCHAR (256) NULL,
)
Patient table:
CREATE TABLE Patient
(
PatientId INT IDENTITY(1,1) PRIMARY KEY,
PId AS 'P' + RIGHT('00000' + CAST(PatientId AS NVARCHAR(10)), 10) PERSISTED,
UserId NVARCHAR(128) FOREIGN KEY REFERENCES AspNetUsers(Id)
)
Example ID is in format like this : 62d8d072-5261-4aaf-b552-d75453cc3421
This is the code , first I am getting value from view in AspNetUsers table , therefore it will generate id in table and I want to use that Id for my Patient table.
[HttpPost]
[ValidateAntiForgeryToken]
[AllowAnonymous]
public async Task<ActionResult> SignUp(Patientview pv)
{
ClinicDbContext db = new ClinicDbContext();
if (ModelState.IsValid)
{
try
{
var user = new ApplicationUser { UserName = pv.Email, Email = pv.Email };
var result = await UserManager.CreateAsync(user, pv.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
}
else
{
return View(pv);
}
Patient p = new Patient();
p.FirstName = pv.FirstName;
p.LastName = pv.LastName;
p.DateOfBirth = pv.DateOfBirth;
p.Email = pv.Email;
p.PhoneNumber = pv.PhoneNumber.ToString();
p.StreetAddress = pv.StreetAddress.ToString();
p.City = pv.City;
p.State = pv.State;
p.ZipCode = pv.ZipCode;
p.UserId = db.AspNetUsers.Max(m => m.Id);
_context.Patients.Add(p);
_context.SaveChanges();
return RedirectToAction("Index", "Admin");
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
System.Diagnostics.Debug.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
eve.Entry.Entity.GetType().Name, eve.Entry.State);
foreach (var ve in eve.ValidationErrors)
{
System.Diagnostics.Debug.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
ve.PropertyName, ve.ErrorMessage);
}
}
throw;
}
}
else
{
return View(pv);
}
}
Normally with EF you would map the relationship between entities with the FKs and let EF manage the assignment of the FK when the primary record and associated records are saved. However, in your case the relationship is relatively loosely coupled.
Are all Patient records going to be associated to ASP.Net authenticated users? If so you can look at changing the PK type on Patient to match the ASPNet table then set up the Patient as a 1-to-1 relationship to ASPNetUser.
Alternatively, if Patients can be ASPNetUsers (but can also be dissociated) then I would look at adding a PatientId column as an autoincrementing integer or sequential GUID (newsequentialId())to ASPNetUser and mapping that to the PatientId in patient as either optional or required a many-to-1. This gets around the ugliness of the string PK on ASPNetUser and allows you to use a FK type that is more suited to your application. (Int or GUID)
A third option you can use to get that newly inserted PK; The PK will only be created after the DbContext SaveChanges so this leaves you with calling SaveChanges twice to get that first id:
//...
var user = new ApplicationUser { UserName = pv.Email, Email = pv.Email };
var result = await UserManager.CreateAsync(user, pv.Password);
if (result.Succeeded)
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
else
return View(pv);
_context.SaveChanges();
Patient p = new Patient();
p.PatientId = Guid.Parse(user.UserId); // User ID will be populated after the above SaveChanges call.
p.FirstName = pv.FirstName;
//...
_context.SaveChanges(); //Save the Patient.
Typically though this isn't ideal as you can get the situation where the first SaveChanges succeeds, but the second fails. These records should likely go through together, so this can be achieved with a tranasaction scope, or a unit or work such as DbContextScope.
Using a TransactionScope:
using (var tx = new TransactionScope())
{
var user = new ApplicationUser { UserName = pv.Email, Email = pv.Email };
var result = await UserManager.CreateAsync(user, pv.Password);
if (result.Succeeded)
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
else
return View(pv);
_context.SaveChanges();
Patient p = new Patient();
p.PatientId = Guid.Parse(user.UserId); // User ID will be populated after the above SaveChanges call.
p.FirstName = pv.FirstName;
//...
_context.SaveChanges(); //Save the Patient.
tx.Complete()
}
In general though, mapping the relationship between entities would be a better option because then the FK constraints can be set up to manage things like cascade deletes.
I understand that you want to get the the last inserted field in the database.
Why don't you use Last() function. :)
p.UserId = db.AspNetUsers.Select(X=>x.id).Last();
Will give you the Userid from the last row of the table.
Max is selecting the maximum value which may or may not yield you the last value.
I have an external id in Account named Applicant_ID__c. I am using data loader to import data into salesforce Opportunity. Below is my mapping file content.
Date\ Cancelled=Date_Cancelled__c
Date\ Denied=Date_Denied__c
Date\ Decisioned=Date_Decisioned__c
App\ Status=Application_Status__c
Date\ Submitted=Application_Submitted__c
Closing\ Date=CloseDate
Application\ Source=Application_Source__c
Application\ Type=Application_Type__c
Application\ Sub-Type=Application_Sub_Type__c
App\ ID=App_ID__c
Property=Property_Name__r\:Property_Code__c
Applicant\ ID=Account\:Applicant_ID__c
Record\ Type\ ID=RecordTypeId
The above mapping is working correctly now what i want is to populate the opportunity name from trigger.
Below is my trigger content
trigger MapStatusToStageBeforeOpportunintyCreation on Opportunity (before insert, before update) {
for (Opportunity o : Trigger.New){
Account acc = [Select LastName From Account Where Applicant_ID__c =:Account:Applicant_ID__c];
o.Name =acc.LastName;
}
}
Thanks in advance.
That answer you created and excepted is going to blow up if insert 101 Opportunities, but if you want to use the Applicant_ID__c you can query it out in the account query
trigger MapStatusToStageBeforeOpportunintyCreation on Opportunity (before insert, before update)
{
Set<ID> acctIDS = new Set<ID>();
for (Opportunity o : Trigger.new)
{
if(o.AccountId != null)
{
acctIDS.add(o.AccountID);
}
}
Map<ID, Account> acctMap = new Map<ID, Account>([Select LastName, Applicant_ID__c From Account Where ID =: acctIDS]);
for(Opportunity o : Trigger.new)
{
for(ID acctID :acctMap.keySet())
{
if(o.AccountID == acctID)
{
o.Lastname = acctMap.get(acctID).LastName;
}
}
}
}
You are querying it wrong
First, you should Never Query in for loop
List'<'Opportuniy opplist = new list'<'Opportunity'>'();<Br/>
// Remove the single quotes <br/>
for (Opportunity o : Trigger.New){<Br/>
o.OpportunityApplicentID = o.Account.Applicant_ID__c;<Br/>
o.Name =acc.LastName;<Br/>
opplist.add(o);<Br/>
}
update opplist;
+Instead of using Applicant_ID__c =:Account:Applicant_ID__c this..Just use Applicant_ID__c =:Account.Applicant_ID__c.Don't use colon .Use dot operator