Approve Actions not working by apex - salesforce

In Salesforce.com apex class.
I'm trying to do a custom approve method:
List< ProcessInstanceWorkitem > listWork = [Select Id,ProcessInstanceId, OriginalActorId, CreatedDate, CreatedById, ActorId FROM ProcessInstanceWorkitem WHERE ProcessInstance.TargetObjectId =: obj.Id ORDER BY CreatedDate desc limit 1];
ProcessInstanceWorkitem lWorkItem;
lWorkItem = listWork[0];
Approval.ProcessWorkitemRequest req = new Approval.ProcessWorkitemRequest();
req.setComments( obj.Justificativa__c );
req.setAction('Approve');
req.setWorkitemId( lWorkItem.Id );
Approval.ProcessResult result = Approval.process( req );
After invoke this method the record was approved BUT no one Approve Action was called.
Somebody knows why?

You should use ProcessSubmitRequest class, instead of ProcessWorkitemRequest class.

Related

Validation Rule salesforce

I would love to have someone assist me with this task:
In the standard "Account" object, I need to create a Validation Rule that allows user to
change "Type" to "Customer – Direct" only if the account has at least 1 child
Opportunity in stage "Closed Won" (I can create whatever help fields/values
I need for this purpose).
thanks
Try the following code:
trigger AccountTrigger on Account (before update){
for(Account Acc: Trigger.New)
{
Opportunity opportunityData = [select id, AccountId, StageName from
Opportunity where StageName ='Closed Won'
And AccountId =:Acc.Id limit 1];
if(Acc.Type == 'Customer - Direct' && opportunityData == null)
{
Acc.addError('Enter Your Error Message');
}
}
}

Update Parent Object Field in Apex Trigger

I have three objects
1)Truck__c
2)Booking__C
3)Payment___C.
Truck and Booking has master detail relationship where Truckk is master and Booking is detail.
Booking and payment has lookup relationship where Booking is parent and payment is child.
I want to update a field present isBooked(checkbox) in Truck based on the value present in a field remainingAmount in payment object. I have added trigger on Payment object like below
trigger TestTrigger on Payment__c (after insert) {
if(Trigger.isAfter && Trigger.isUpdate){
for (Payment__c pay:Trigger.New)
{
payId.add(pay.id);
paidAmount =Integer.valueOf(pay.Paid_Amount__c);
}
Map <id,Booking__c> bookingMap = new Map <id,Booking__c> ();
for (Booking__c obj: [Select Id, Booking_ID__c from Booking__c where Booking_ID__c in:payId])
{
bookingMap.put(obj.Booking_ID__c, obj);
}
for(Booking__c objBooking:matchingIdsMap){
Truck__c truckObj = [Select id,Price__c from Truck__c where Truck__c.id = objBooking.Truck__c.id];
//Integer paidAmount = Payment__c.Paid_Amount__c;
Integer totalAmount = Integer.valueOf(truckObj.Price__c);
Integer remainingAmount = totalAmount-paidAmount;
If(remainingAmount == 0){
truckObj.Booked__c = true
}
update truckObj;
}
}
}
Here first I am getting payment ID's and based on that I am fetching Booking objects which is lookup parent of payment. After this I am trying to fetch the truck object which is master of Booking. But I don't know how to query on this as where clause in query giving error
Truck__c truckObj = [Select id,Price__c from Truck__c where Truck__c.id = objBooking.Truck__c.id];
Please note there is no direct relationship between Truck and Payment
How can I fetch truck object
Thanks in Advance
Short answer: while referring to parent fields, you should use the relationship name, so Truck__r instead of Truck__c.
Anyway it is not the only problem with that code.
Long answer:
your trigger is in after insert, but you check for an after update event: if(Trigger.isAfter && Trigger.isUpdate). Probably you want to run this trigger in both after insert and after update.
You never declared payId nor paidAmount which you use in your first for-loop. Anyway paidAmount would just hold the last value, which probably you won't need.
[Select Id, Booking_ID__c from Booking__c where Booking_ID__c in:payId] this query should return an empty list because in payId you've stored the ids of Payment__c, that is a child of Booking__c, while in the first loop you should have stored the ids of parents Booking__c
[Select id,Price__c from Truck__c where Truck__c.id = objBooking.Truck__c.id] Here there is no reason to write where Truck__c.id It should be just WHERE Id = :objBooking.Truck__c.
Beware: putting a SOQL in a loop you will easily hit the Governor Limit about SOQL, which will raise a System.LimitException: Too many SOQL queries: 101.
The same goes by putting a DML in a loop.
I'm going to assume that the API Name of the lookup fields is the same of the parent object, so that a Booking__c field exists on Payment__c object and a Truck__c exists on Booking__c object.
If I got the logic right about how setting the flag on Truck object, this should be the trigger code.
trigger TestTrigger on Payment__c (after insert, after update) {
if(Trigger.isAfter && (Trigger.isInsert || Trigger.isUpdate)) {
Map<Id, List<Payment__c>> mapBookingIdPaymentList = new Map<Id, List<Payment__c>>();
for (Payment__c pay : Trigger.New) {
List<Payment__c> paymentList = mapBookingIdPaymentList.get(pay.Booking__c);
if (paymentList == null) {
paymentList = new List<Payment__c>();
mapBookingIdPaymentList.put(pay.Booking__c, paymentList);
}
paymentList.add(pay);
}
Map<Id, Decimal> mapTruckPrice = new Map<Id, Decimal>();
Map<Id, Integer> mapTruckRemainingAmount = new Map<Id, Integer>();
for (Booking__c booking: [SELECT Id, Truck__c, Truck__r.Price__c FROM Booking__c WHERE Id IN :mapBookingIdPaymentList.keySet()]) {
mapTruckPrice.put(booking.Truck__c, booking.Truck__r.Price__c);
Integer sumOfRemainingAmount = mapTruckRemainingAmount.containsKey(booking.Truck__c) ? mapTruckRemainingAmount.get(booking.Truck__c) : 0;
for (Payment__c pay : mapBookingIdPaymentList.get(booking.Id)) {
sumOfRemainingAmount += pay.Paid_Amount__c != null ? pay.Paid_Amount__c.intValue() : 0;
}
mapTruckRemainingAmount.put(booking.Truck__c, sumOfRemainingAmount);
}
List<Truck__c> trucksToUpdate = new List<Truck__c>();
for (Id truckId : mapTruckPrice.keySet()) {
// There is no need to query a record just to update it if you already have its Id.
Truck__c truck = new Truck__c(Id = truckId);
truck.Booked__c = mapTruckPrice.get(truckId) - mapTruckRemainingAmount.get(truckId) == 0;
trucksToUpdate.add(truck);
}
update trucksToUpdate; // dml outside the loop
}
}
By the way, you should move the logic in an handler class, following the best practices.

Entity framework query to get array of role names for user

I have been trying to right a single query that can retrieve an array of the current users role names. I have gotten really close sadly my code doesn't return an array. I am fairly new to the entity framework and very confused on joins and inner queries within this language. If I was working in standard sql I would right a sub query to return all roles names where from roles where roleid is in user.roles.
Existing Code:
var user = from obj in db.Users
join obj2 in db.Roles on obj.Id equals obj2.Id
where obj.UserName == name select new {
FirstName =obj.FirstName,
LastName =obj.LastName,
Email =obj.Email,
JoinDate =obj.JoinDate,
ProfilePic =obj.ProfileSettings.ProfilePicture,
Roles = ""
};
I don't want to use the current claims because I want to ensure that when getUser is called the most accurate roles are returned not the ones stored inside the access_token.
A solution is doing a group join like this
var user = from obj in db.Users
join obj2 in db.Roles on obj.Id equals obj2.Id into roles
where obj.UserName == name
select new {
FirstName =obj.FirstName,
LastName =obj.LastName,
Email =obj.Email,
JoinDate =obj.JoinDate,
ProfilePic =obj.ProfileSettings.ProfilePicture,
Roles = roles.Select(e=>e.Name)
};
Update
If you have Roles navigation property from User entity then you could do this:
var user = db.Users.Where(e=>e.UserName == name)
.Select(obj=>new {FirstName =obj.FirstName,
LastName =obj.LastName,
Email =obj.Email,
JoinDate =obj.JoinDate,
ProfilePic =obj.ProfileSettings.ProfilePicture,
Roles = obj.Roles.Select(e=>e.Name)
});
I used what I understand about actual SQL and that is I would do a sub query to get this data. This works as I wanted.
Code:
var user = from obj in db.Users
where obj.UserName == name
select new
{
ID1 = obj.Id,
FirstName = obj.FirstName,
LastName = obj.LastName,
Email = obj.Email,
JoinDate = obj.JoinDate,
ProfilePic = obj.ProfileSettings.ProfilePicture,
Roles = (from info in obj.Roles
from allData in db.Roles
where allData.Id == info.RoleId
select allData.Name).ToList()
};

Need Help in displaying Error Message on Same page

I have craeted a trigger which will Fire on update on Field on campaign and restrict the user from leaving the Comments field blank upon rejecting the record.
Here is my trigger code:
trigger RequireRejectionComment on Campaign (before update)
{
Map<Id, Campaign > rejectedStatements
= new Map<Id, Campaign>{};
for(Campaign inv: trigger.new)
{
Campaign oldInv = System.Trigger.oldMap.get(inv.Id);
if ((oldInv.BR_ApprovalStatusRegulatory__c != 'Reprovado'
&& inv.BR_ApprovalStatusRegulatory__c == 'Reprovado')||
(oldInv.BR_ApprovalStatusLegal__c!= 'Reprovado' &&
inv.BR_ApprovalStatusLegal__c== 'Reprovado') )
{
rejectedStatements.put(inv.Id, inv);
}
}
if (!rejectedStatements.isEmpty())
{
List<Id> processInstanceIds = new List<Id>{};
for (Campaign invs : [SELECT (SELECT ID
FROM ProcessInstances
ORDER BY CreatedDate DESC
LIMIT 1)
FROM Campaign
WHERE ID IN :rejectedStatements.keySet()])
{
processInstanceIds.add(invs.ProcessInstances[0].Id);
}
// Now that we have the most recent process instances, we can check
// the most recent process steps for comments.
for (ProcessInstance pi : [SELECT TargetObjectId,
(SELECT Id, StepStatus, Comments
FROM Steps
ORDER BY CreatedDate DESC
LIMIT 1 )
FROM ProcessInstance
WHERE Id IN :processInstanceIds
ORDER BY CreatedDate DESC])
{
if ((pi.Steps[0].Comments == null ||
pi.Steps[0].Comments.trim().length() == 0))
{
Trigger.new[0].parentId.addError(' My error Message ');
//rejectedStatements.get(pi.TargetObjectId).addError(
// ' My error Message');
}
}
}
}
This trigger works fine but it displays an error message on new page..
My requirement: Error message should appear on record or the same page, while rejecting the record.
Please suggest,thanks..
Have you tried creating the validation within the apex page itself?
You can set the page item to have a validation that doesn't allow the page to be submitted if a specified page item is NULL.
Look for the validations section within the page-processing section when editing your page.
Here is a link to documentation regarding validations:
https://docs.oracle.com/database/121/HTMDB/bldr_validate.htm#HTMDB28931

Initialise object in apex with related data

I require a separate object which contains the related fields of a child object.
Currently I do it like this:
Opportunity opp = [SELECT Id, Name, Account.Id, Account.Name FROM Opportunity LIMIT 1];
Account acc = new Account(
Id = opp.Account.Id,
Name = opp.Account.Name
);
When working with a large related object I have to initialise many more fields than this and the script becomes very large and ugly.
What is the quickest way to initialise the related field data into a separate object?
You must define the all fields in your SOQL query (mor info here).
But it is not necessary if you want to clone the object:
Opportunity opp = [SELECT Account.Id, Account.Name
FROM Opportunity
LIMIT 1];
Account acc = opp.Account;
Example with Custom Object:
Contract__c c = [ Select Account__r.FirstName
From Contract__c
Where Account__r.FirstName != null
Limit 1];
Account a = c.Account__r;

Resources