I have created an Approval Process and am launching it from an Apex code behind a custom button. This is working fine, but the problem I am facing is that I am not able to set the approver from the Apex code. It always takes the Approver that is set in the Approval Process.
Here is my code:
Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
req.setComments('Submitted for approval. Please approve. Source:ApexClass');
req.setObjectId(dcr.Id);
req.setNextApproverIds(new Id[] {'0057E000001dn5T'}); // This is the id of a user
Approval.ProcessResult result = Approval.process(req);
This submits the record for approval, but sends it to the Approver that is set in the Approval Process, and not to the user with id '0057E000001dn5T' that is set in the code
I also tried by changing the following line from above code
req.setNextApproverIds(new Id[] {'0057E000001dn5T'});
to
List<Id> approverIdList = new List<Id>();
Id approverId = [SELECT DCR_Send_to_Approver_AGN__c FROM User
WHERE Id = :UserInfo.getUserId()].DCR_Send_to_Approver_AGN__c;
approverIdList.add(approverId);
req.setNextApproverIds(approverIdList);
and
list<string> approverIdList = new list<string>();
group g = [SELECT (select userOrGroupId from groupMembers) FROM group
WHERE name= 'testUserGroup'];
for (GroupMember gm : g.groupMembers) {
approverIdList.add(gm.userOrGroupId);
}
req.setNextApproverIds(approverIdList);
...but nothing worked.
So how I can set the approver from the Apex code? Any help would be appreciated.
As you have assigned an approver in your approval process, it will not let you to override. You need to select Manually Chosen to populate the approver using apex.
Related
Hi I have a custom object which has a custom field of type lookup to Account. The child custom record gets created when Account record is created. I am creating child record in after insert trigger on Account and keeping the name of child record same as of the name of Account.
But In the name I am getting 15 digit Id instead of real name of account. What can be the issue?
Code## for Trigger
if(Trigger.isAfter && (Trigger.isInsert)){
AccountTriggerHelper.createReferrer(Trigger.new);
}
In Apex Class:
public static void createReferrer(List<Account> accountList){
List<Referral__c> newReferral = new List<Referral__c>();
for(Account acc : accountList) {
if(acc.Talos_RecordType__c=='Referrer'){
system.debug('==acc=1='+acc);
Referral__c ref = new Referral__c();
System.debug('-----acc.Name----'+acc.Name);
ref.Name = acc.Name;
ref.Account__c = acc.Id;
ref.Email__c = acc.PersonEmail;
ref.Talos_IQOS_Expert_ID__c = acc.Talos_IQOS_Expert_ID__c;
ref.Talos_Referrer_Type__c = acc.Referrer_Type__c;
ref.User_Id__c = acc.UserID__c;
ref.Email_Validation__c = true;
ref.Store_Code__c = acc.Store_Code__c;
newReferral.add(ref);
system.debug('==referral=1='+newReferral);
}
}
Thanks,
Marc
This code can't lead to population of Id in the Name field. There might be another trigger on Account or child Object, or any workflow, process builder on your org creating that change again. Can you check the created date and modified date of the child record.
If they are different, then most probably I am right.
I have created share object in my salesforce environment.
From Setup-> security Controls -> Sharing Settings -> I made my custom object access to "Private". So suppose my object name is EVT_Client__c & I am trying to insert data into EVT_Client__Share from trigger(AfterInsert) I am unable to do it. I am getting error as given below.
Once data get inserted into EVT_Client__c object our trigger tries to insert data into EVT_Client__share object but we are getting error. Profile user who is inserting data into EVT_Client__c object through UI having Read/create/edit/delete access on object.
System.TypeException: DML operation INSERT not allowed on
EVT_Client__Share
My code in trigger is as below in which I am getting error.
public with sharing class EVT_Client_TriggerHandler {
private void ShareClientToThirdPartyJobGroup(List<EVT_Client__c> lstClients){
List<EVT_Client__Share> lstSharesForThirdPartyGroup = new List<EVT_Client__Share>();
List<Group> lstThirdPartyGroups = [Select Id, RelatedId from Group where Name = 'Third Party'];
for(EVT_Client__c client: lstClients){
for(Group roleGroup : lstThirdPartyGroups ){
EVT_Client___Share objShareForThirdPartyGroup = new EVT_Client__Share(ParentId = client.Id,
UserOrGroupId = roleGroup.Id,
AccessLevel = 'Edit',
RowCause = Schema.EVT_Client__Share.RowCause.User_Client__Access__c);
lstSharesForThirdPartyGroup.add(objShareForThirdPartyGroup);
}
}
insert lstSharesForThirdPartyGroup;
}
}
You're sure it's not a "detail" in any master-detail relationship? The OWD would then say "controlled by parent" instead of "private". Can you switch to Classic view, go to page layout and verify the [Sharing] button can be added, displays OK, this user can manually share this record from UI?
Post your code sample? I suspect you need to define Apex Sharing Reason first. It's bit like roles if you ever played with Account/Contact/Opportunity/Case roles.
Once it's set you should be able to do something like this code sample: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_bulk_sharing_creating_with_apex.htm (they use "manual" as sharing reason but you might have more luck with custom sharing reason.
I quickly created your object and this worked like a charm for me:
trigger Stack57201752 on EVT_Client__c (after insert) {
List<Group> groups = [SELECT Id FROM Group WHERE Name = 'Third Party'];
List<EVT_Client__Share> shares = new List<EVT_Client__Share>();
for(EVT_Client__c c : trigger.new){
for(Group g : groups){
shares.add(new EVT_Client__Share(
ParentId = c.Id,
UserOrGroupId = g.Id,
AccessLevel = 'Edit',
RowCause = 'Manual'
));
}
}
insert shares;
}
And when I click the [Sharing] button on the record it looks good:
So... Stupid question time: have you clicked this checkbox?
I have a requirement to make to make a file private and be available to only the user whose role name consists the name of the file for a specific custom object. For this I am trying to retrieve from Content Document Link with the custom object name LinkedEntity.Type and ContentDocumentid as filters, when I hard code the ContentDocumentid it is working fine but when I try to dynamically provide the ContentDocumentId then the query is not returning any result. I am adding a snippet of my code. Please Help!!. Thanks
List<Id> listOfConDocuId = new List<Id>();
for(ContentVersion cv: Trigger.new){
if((!cv.Title.contains('product proposal')) || (!cv.Title.contains('final')) || (!cv.Title.contains('packet')))
listOfConDocuId.add(cv.ContentDocumentId);
}
Map<Id, Project__c> mapOfProjectId = new Map<Id, Project__c>([SELECT Id FROM Project__c]);
Set<Id> setOfProjectId = mapOfProjectId.keySet();
List<ContentDocumentLink> LinkedProject = [SELECT ContentDocumentId, LinkedEntityId, ContentDocument.Title FROM ContentDocumentLink where LinkedEntityId in :setOfProjectId and LinkedEntity.Type='Project__c' and ContentDocumentId IN :listOfConDocuId];`
I don't think it's necessary to add a WHERE clause for both ID and TYPE. Id should be enough. As far as restricting files to only users with certain roles, have you tried sharing the Custom Object (Project__c) with only those users and then simply linking the files to that Custom Object record with Inferred Permission?
Read more about the sharing types and visibility of Content Document Link here:
https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_contentdocumentlink.htm
I was not able to insert mock data for AccountPartner through test class. I tried by inserting 2 accounts and one Partner object. Actually same code is working in case of running from Apex class or executing from developer console. Please see the below code and output and let me know solution..
#isTest
private class TestAccountPartner {
private static testmethod void unittest(){
test.startTest();
Account sourceAccount = new Account();
Account targetAccount = new Account();
sourceAccount.AccountNumber='Number1';
sourceAccount.Name='name1';
targetAccount.AccountNumber='Number2';
targetAccount.Name='name2';
insert sourceAccount;
insert targetAccount;
Partner p = new Partner(AccountFromId=sourceAccount.ID, AccountToId=targetAccount.ID);
insert p;
Account sa = [select ID from Account where Name='name1'];
Account ta = [select ID from Account where Name='name2'];
System.debug('Source Account is: '+sa);
System.debug('Target Account is: '+ta);
List<Partner> partners = [select AccountFromId from partner];
System.debug('Partner objects are: '+partners);
List<AccountPartner> accountPartners = [select AccountFromId from AccountPartner];
System.debug('account partners are: '+accountPartners);
test.stopTest();
}
}
Output is:
07:24:48:174 USER_DEBUG [26]|DEBUG|Source Account is: Account:{Id=00128000007YZk7AAG}
07:24:48:174 USER_DEBUG [27]|DEBUG|Target Account is: Account:{Id=00128000007YZk8AAG}
07:24:48:176 USER_DEBUG [30]|DEBUG|Partner objects are: (Partner:{AccountFromId=00128000007YZk7AAG, Id=00I28000000ZeBTEA0})
07:24:48:177 USER_DEBUG [33]|DEBUG|account partners are: ()
It's been a while but I think this is because account partner is one of the special Role type relationships. Have you tried accessing the Target account's AccountPartner collection and using the add() method to add the Source account.
This isn't identical to your situation, but the solution has a similar example that is adding partners:
https://salesforce.stackexchange.com/questions/3805/how-to-update-account-object-when-related-accountpartner-is-updated-inserted-del
I have a simple SOQL query that returns information relating to a Contact and CampaignMember. I'm attempting to populate a custom object with the results of the SOQL query. However I get the following error when loading the Visualforce page:
Invalid field campaign.name for CampaignMember
List campaignMembers = [select campaign.name, contact.id,contact.firstname, contact.lastname, status, campaignId from CampaignMember where contactId = '003U000000U0eNq' and campaignId in :campaigns];
for (Integer i = 0; i < campaignMembers.size(); i++) {
results.add(new CampaignMemberResult(
(String)campaignMembers[i].get('CampaignId'),
(String)campaignMembers[i].get('campaign.name'),
true
));
}
I've ran the SOQL query seperately in the Developer Console and it queries successfully. Why can I not pull in the campaign.name from the SOQL query within the for loop?
The error you see is caused by the fact you should write it as campaignMembers[i].Campaign.Name. Or if you insist on the getter syntax, campaignMembers[i].getSobject('Campaign').get('Name').
Any special reason you need the wrapper object (or whatever CampaignMemberResult is)?
I have strange feeling you're writing too much code to achieve something simple ;) The syntax with campaignMembers[i].Campaign.Name will also mean you don't have to use casts to String.
Plus - if you need to know "in which campaigns does this Contact occur" you have 2 ways:
flat
select contact.id,contact.firstname, contact.lastname,
campaignid, campaign.name,
status
from CampaignMember
where contactId = '003U000000U0eNq'
subquery
From contact you go down to the related list of campaignmembers, then up to campaigns to get their names
SELECT Id, FirstName, LastName,
(SELECT CampaignId, Campaign.Name FROM CampaignMembers)
FROM Contact WHERE Id = '003U000000U0eNq'
Example how to use "flat" result straight in visualforce (without CampaignMemberResult):
Apex:
public List<CampaignMember> flatMembers {get;set;} // insert dick joke here
flatMembers = [select contact.id,contact.firstname, contact.lastname,
campaignid, campaign.name,
status
from CampaignMember
where contactId = '003U000000U0eNq'];
VF:
<apex:pageBlockTable value="{!flatMembers}" var="cm">
<apex:column value="{!cm.Contact.LastName}" />
<apex:column value="{!cm.Status}" />
<apex:column value="{!cm.Campaign.Name}" />
EDIT
My end goal is a Visualforce page to be displayed on the contact
record showing a list of all campaigns with a checkbox alongside each
indicating if the contact is a member or not.
You do realize it can quickly grow into a pretty long table? Maybe some filter on campaigns (if you feel like reading about sth advanced - check the documentation for "StandardSetController"). Also I'm pretty sure there are some ways to add Contacts/Leads to Campaigns from Campaign reports - maybe something out of the box would save your time and be more maintainable...
But code solution would be pretty straightforward, start with a helper wrapper class:
public class CampaignWrapper{
public Boolean selected {get;set;}
public Campaign c {get; private set;}
public CampaignWrapper(Campaign c){
this.c = c;
selected = !c.CampaignMembers.isEmpty();
}
}
Then a query and build the list of wrappers:
List<CampaignWrapper> wrappers = new List<CampaignWrapper>();
for(Campaign c : [SELECT Id, Name, (SELECT Id FROM CampaignMember WHERE ContactId = '...')
FROM Campaign
LIMIT 1000]){
wrappers.add(new CampaignMember(c));
}
You should be all set ;) If it's just for displaying - you might not even need the wrapper class (some tricks in visualforce expressions maybe or use Map<Campaign, Boolean> even...
1000 records is the limit of collections passed to Visualforce (10K if your page will be readonly). Past that - pagination, most likely with use with abovementioned StandardSetController.