I have custom obj "A" and Standard obj Case. Case standard obj has lookup to custom obj "A". there is a field between the two objects called Customer_ID__c. I wrote a Trigger (before Insert, Before Update) to associated the case record to the correct existing custom obj "A" record if "Case.Custom_Id__c" match the one in the Custom obj "A". Unfortunate it is not happening and I'm not sure where to look.
trigger IAACaseRelateASAP on Case (before insert, before update) {
Id recordtypes = [Select Id, name
From RecordType
Where SobjectType = 'Case'
AND Name = 'I Buy'
LIMIT 1].Id;
Set<String> casId = new Set<String>();
for(Case cs : Trigger.new)
{
if(cs.RecordtypeId == recordtypes && cs.Type == 'Contact Me')
{
if(cs.custm_Obj_A_Name__lookupfield__c == null && (cs.Customer_ID__c != null || cs.Customer_ID__c !='0'))
{
casId.add(cs.Customer_ID__c);
}
}
}
system.debug('Case Set Ids' + casId);
List<A__c> aList = [Select Customer_ID__c, Id
From A__c
Where Customer_ID__c IN: casId
AND
A__c != 'Provider'];
System.Debug('equals' + aList);
Map<String, A__c> aMapId = new Map<String, A__c>();
for(A__c aAcct : aList)
{
aMapId.put(aAcct.Customer_ID__c, aAcct);
}
for(Case cas : Trigger.new)
{
if(cas.RecordtypeId == recordtypes && cas.Type == 'Contact Me')
{
if(cas.custm_Obj_A_Name__lookupfield__c == null && (cas.Customer_ID__c != null || cas.Customer_ID__c !='0'))
{
if(aMapId.containsKey(cas.Customer_ID__c))
{
A__c aAcct = aMapId.get(cas.Customer_ID__c);
System.Debug('Case IAA ASAP Account value: ' + asapAcct);
}
}
}
}
}
It might be best when looping through your cases to build your set of Customer_ID__c ids to also build a List of cases with customer ids so that you don't have to loop through the entire new list a second time. There are a couple other issues with the trigger in general but I'll ignore those and just focus on what you asked. Think your issue is that you don't actually set the case field in this area:
if(aMapId.containsKey(cas.Customer_ID__c))
{
A__c aAcct = aMapId.get(cas.Customer_ID__c);
System.Debug('Case IAA ASAP Account value: ' + asapAcct);
}
It should be :
if(aMapId.containsKey(cas.Customer_ID__c))
{
cas.custm_Obj_A_Name__lookupfield__c = aMapId.get(cas.Customer_ID__c).Id;
}
Related
I have created two different rules, which belong to two different agenda-groups.
First one:
rule "32-30-33.32"
dialect "java"
salience 0
agenda-group "32-30"
when
map : Map((this["Product Name"].toUpperCase().contains("PREMIUM ADPRODUCT")) && ((this["Size Length"] != 5) || (this["Size"].toUpperCase() not contains "300X600") || (this["Size"].toUpperCase() not contains "280X130") || (this["Size"].toUpperCase() not contains "300X250") || (this["Size"].toUpperCase() not contains "970X250") || (this["Size"].toUpperCase() not contains "320X50")));
then
JSONObject jObject = new JSONObject("{\"error34\":\"Premium Adproduct doesn't contain required Creative size!\"}");
Iterator<?> keys = jObject.keys();
while(keys.hasNext()) {
String key = (String)keys.next();
Object value = jObject.get(key);
map.put(key, value);
}
debug(drools);
end
Another rule, in another agenda group:
rule "47-37-1.0"
dialect "java"
salience 0
agenda-group "47-37"
when
map : Map((this["OrderName"] == null));
then
JSONObject jObject = new JSONObject("{\"error1\":\"OrderName should not be null \"}");
Iterator<?> keys = jObject.keys();
while(keys.hasNext()) {
String key = (String)keys.next();
Object value = jObject.get(key);
map.put(key, value);
}
debug(drools);
end
After this, I set focus to the group "47-37",
kieSession.getAgenda().getAgendaGroup("47-37").setFocus();
All rules within the group "32-30" are also getting evaluated. I'm using Drools 7.0.0. How can I control execution of rules only within the focused group?
In salesforce Apex, I have a below String and facing issues how we can iterate over two maps at a time ?? Can somebody please guide me ... how we can do this ?
String values = 'Auth Group:true,HR Group:false';
Auth Group:true,HR Group:false
I have two Maps
// Map of GroupId and GroupName
Map<Id, String> mapGrpIdAndName = new Map<Id, String>();
mapGrpIdAndName.put('Auth Group','111');
mapGrpIdAndName.put('HR Group','222');
// Map of GroupName and Indicator
Map<String, String> mapGrpNameAndIndicator = new Map<String, String>();
mapGrpNameAndIndicator.put('Auth Group','false');
mapGrpNameAndIndicator.put('HR Group','true');
Assume I am in for loop of case already
for(payment_2__c mysi2 : newSI2){
Boolean f_indicator = // True or False ==> This value is dynamic........
if(caseMap.get(mysi2.Case__c).RecordType.DeveloperName != 'ELC_DraftCase'){
if(caseMap.get(mysi2.Case__c).OwnerId != mysi2.OwnerId){
if(caseMap.get(mysi2.Case__c).RecordType.DeveloperName == 'AAA_HR'){
for(Id grpId : mapGrpIdAndName.keySet()){
//// HERE I need to check dynamicallt if value of
/// if f_indicator == false and Auth Group == false, then only give apex sharing
// How to iterate over two map at a time ???????
////
ELC_Service_Information_2__Share gsiShare2 = new ELC_Service_Information_2__Share();
gsiShare2.ParentId = mysi2.Id;
gsiShare2.RowCause = 'Manual';
gsiShare2.AccessLevel = 'Edit';
gsiShare2.UserOrGroupId = grpId;
si_2ShareList.add(gsiShare2);
}
}
}
}
}
Does this compile? Your first Map (mapGrpIdAndName) is instantiated to store an Id and a String; however, you are storing two Strings in it.
Also, if you are looping through the cases already, you don't need to be retrieving the values from caseMap.
It's difficult to understand why you are creating a map only to store two true/false values. I guess you're omitting the real code so we don't use it.
This is how you can do it without looping through the second map:
for(Id grpId : mapGrpIdAndName.keySet()){
if(f_indicator == false && mapGrpNameAndIndicator.get(mapGrpIdAndName.get(grpId)) == 'false'){
//do whatever
}
}
Since Group is an sObject, you can use something like this instead:
Map<Id, Group> mpGroups = new Map<Id, Group>([SELECT Id, Name FROM Group]);
for(Id grpId : mpGroups.keySet()){
if(f_indicator == false && mpGroups.get(grpId).Indicator__c == 'false'){
//do whatever
}
}
Or:
Map<Id, Group> mpGroups = new Map<Id, Group>([SELECT Id, Name FROM Group]);
for(Group grp : mpGroups.values()){
if(f_indicator == false && grp.Indicator__c == 'false'){
//do whatever
}
}
I'm trying to create trigger if record type is Revenue Risk then amount should be saved in negative value, Here's my code in which I'm having error, I tried it two ways, second is in comments.. none of them is working
public with sharing class amountValidator {
//pull data of Opportunity in list
public static void validateAmount (list<Opportunity> oppList){
oppList = [Select amount FROM Opportunity WHERE RecordType.Name IN ('Revenue Risk')];
for(Opportunity opportunities : oppList){
if(oppList.amount >= '0'){
oppList.amount = oppList.amount * '-1';
}
}
/*Map<String,Schema.RecordTypeInfo> rtMapByName = d.getRecordTypeInfosByName();
Schema.RecordTypeInfo rtByName = rtMapByName.get('Revenue Risk');
for(Opportunity each : oppList){
if(rtByName.size == 0){
}
else{
if(oppList.Amount >= 0){
oppList.Amount = oppList.Amount*-1;
}
}
}*/
The error is very clear:
if(oppList.amount >= '0'){ // THIS LINE WILL THROW AN ERROR: 'Comparison arguments must be compatible types: Integer (or Double), String
oppList.amount = oppList.amount * '-1'; // THIS ONE TOO: 'Arithmetic expressions must use numeric arguments'
}
Your second code snippet is also wrong (same for first one).
if(oppList.Amount >= 0){
oppList.Amount = oppList.Amount*-1;
// MUST BE each.Amount = each.Amount * - 1; Please try not to use reserved words as variable names
}
You may want to take a look at a previous post describing strongly typed programming languages: Strongly Typed
Since we can't add comments just yet, we're going to add a new answer:
You're not updating/inserting the updated amount for your opportunity.
The correct way of doing this is to create a separate List of Opportunities (i.e. List oppsToUpdate) and add the updated opportunities to this list.
public static void validateAmount (list<Opportunity> oppList){
oppList = [Select amount FROM Opportunity WHERE RecordType.Name IN ('Revenue Risk')]; // Why are you requerying the Opportunity if you already have it??
List<Opportunity> oppsToUpdate = new List<Opportunity>();
for(Opportunity opportunities : oppList){
if(opportunities.amount > 0){
opportunities.amount = opportunities.amount * -1;
oppsToUpdate.add(opportunities);
}
}
upsert opportunities;
}
Remember to enclose your function with try-catch statements with system debugs to see what's going on with your code.
And this is the link to the input parameter modifications and why this is bad practice: Input Parameters
Working Code:
trigger Risk_NegativeQuantity on OpportunityLineItem (before insert) {
set<id> oppid = new set<id>();
for (OpportunityLineItem oli : trigger.new)
{
oppid.add(oli.opportunityid);
}
Id RevenueRisk= Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('Revenue Risk').getRecordTypeId();
list<opportunity> opplist = [select id, recordtype.name,recordtypeid from opportunity where id in : oppid ];
for (OpportunityLineItem oli : trigger.new)
{
for (opportunity opp: opplist)
{
if (oli.opportunityid == opp.id)
{
if(opp.recordtype.name == 'Revenue Risk')
{
if(oli.Quantity > 0)
{
oli.Quantity = oli.Quantity * -1;
}
}
}
}
}
}
I cant figure out why this trigger is sometimes updating records that dont match the criteria. The idea is that when an account goes from 'on-hold' to an active service, any cancelled assignments are returned to pending. I cant figure out whats triggering it, but it seems everyone in a while, assignments are un-cancelled for accounts that have no change in service. Heres the code:
trigger cancelAssignments on Account (before update) {
List<Assignment__c> masterListA = [select Id, Status__c, Practice__c from Assignment__c where Practice__c IN :Trigger.newMap.keySet() and type_of_work__c != 'a0Qa000000G1WmVEAV' AND (status__c = 'Feedback Needed' OR status__c = 'Pending Review' OR status__c = 'Accepted')];
List<Assignment__c> masterListB = [select Id, Status__c, Practice__c from Assignment__c where Practice__c IN :Trigger.newMap.keySet() and type_of_work__c != 'a0Qa000000G1WmVEAV' AND (status__c = 'Canceled')];
for (Account oAccount : trigger.new) {
if (oAccount.current_services__c == null || oAccount.current_services__c == 'Hold'){
for (Account oAcct : trigger.old){
if (oAcct.current_services__c != null && oAcct.current_services__c != 'Hold'){
List<Assignment__c> assignmentsToUpdate = new List<Assignment__c>();
for (Assignment__c rd : masterListA){
if (rd.practice__c == oAccount.id){
rd.Status__c = 'Canceled';
assignmentsToUpdate.add(rd);
}
}update assignmentsToUpdate;
}
}
}
else if (oAccount.current_services__c != 'Hold' && oAccount.current_services__c != null ){
for (Account oAcctB : trigger.old){
if (oAcctB.current_services__c == 'Hold'){
List<Assignment__c> assignmentsToUpdateB = new List<Assignment__c>();
for (Assignment__c rdB : masterListB){
if (rdB.practice__c == oAccount.id){
rdB.Status__c = 'Pending Review';
assignmentsToUpdateB.add(rdB);
}
}update assignmentsToUpdateB;
}
}
}
}
}
The problem may be as follows:
masterListB grabs assignments for more than one account
The code in the for (Account oAcctB : trigger.old) loop never checks to see whether old account that's in "Hold" status is the same account
One solution may be to make the edit below:
/* Old condition replaced:
if (oAcctB.current_services__c == 'Hold') { */
if (oAcctB.current_services__c == 'Hold' and oAcctB.Id == oAccount.Id) {
To prove whether this is the right solution, I suggest creating a unit test that works like this:
Create two Accounts, "Alpha Corp" and "Beta Corp"
Set Alpha Corp's Current Services to "Hold"
Set Beta Corp's Current Services to "Active"
Add a related Assignment to Alpha Corp with Status "Canceled"
Add a related Assignment to Beta Corp with Status "Canceled"
Update both accounts in a single DML operation, doing something trivial like changing the Billing Country from "US" to "United States"
Assert that the related Assignment for Alpha Corp remains "Canceled"
I suspect that the code you shared will not pass the unit test, in which case you'll be able to zero in on the problem and fix it.
While Marty's code answered the question I asked, I also ran into some 'Too Many Code Statements' errors. Here is the final code that seems to resolve that:
trigger cancelAssignments on Account (before update) {
List<account> quitingAccounts = new List<account>();
List<account> returningAccounts = new List<account>();
List<Assignment__c> assignmentsToCancel;
List<Assignment__c> assignmentsToReturn;
for (Account oAccount : trigger.new)
{
if (oAccount.current_services__c == null || oAccount.current_services__c == 'Hold')
{
for (Account oAcct : trigger.old)
{
if (oAcct.current_services__c != null && oAcct.current_services__c != 'Hold' && oAcct.Id == oAccount.Id)
{
quitingAccounts.add(oAcct);
}
}
}
else if (oAccount.current_services__c != 'Hold' && oAccount.current_services__c != null )
{
for (Account oAcctB : trigger.old)
{
if (oAcctB.current_services__c == 'Hold' && oAcctB.Id == oAccount.Id)
{
returningAccounts.add(oAcctB);
}
}
}
}
assignmentsToCancel = [select Id, Status__c, Practice__c from Assignment__c where Practice__c IN :quitingAccounts and type_of_work__c != 'a0Qa000000G1WmVEAV' AND (status__c = 'Feedback Needed' OR status__c = 'Pending Review' OR status__c = 'Accepted')];
assignmentsToReturn = [select Id, Status__c, Practice__c from Assignment__c where Practice__c IN :returningAccounts and type_of_work__c != 'a0Qa000000G1WmVEAV' AND status__c = 'Canceled'];
for (Assignment__c rd : assignmentsToCancel)
{
rd.Status__c = 'Canceled';
}
for (Assignment__c rd : assignmentsToReturn)
{
rd.Status__c = 'Pending Review';
}
update assignmentsToCancel;
update assignmentsToReturn;
}
I have a query as follows:
var query = from x in context.Employees
where (x.Salary > 0 && x.DeptId == 5) || x.DeptId == 2
order by x.Surname
select x;
The above is the original query and returns let's say 1000 employee entities.
I would now like to use the first query to deconstruct it and recreate a new query that would look like this:
var query = from x in context.Employees
where ((x.Salary > 0 && x.DeptId == 5) || x.DeptId == 2) && (x,i) i % 10 == 0
order by x.Surname
select x.Surname;
This query would return 100 surnames.
The syntax is probably incorrect, but what I need to do is attach an additional where clause and modify the select to a single field.
I've been looking into the ExpressionVisitor but I'm not entirely sure how to create a new query based on an existing query.
Any guidance would be appreciated. Thanks you.
In an expression visitor you would override the method call. Check if the method is Queryable.Where, and if so, the methods second parameter is a quoted expression of type lambda expression. Fish it out and you can screw with it.
static void Main()
{
IQueryable<int> queryable = new List<int>(Enumerable.Range(0, 10)).AsQueryable();
IQueryable<string> queryable2 = queryable
.Where(integer => integer % 2 == 0)
.OrderBy(x => x)
.Select(x => x.ToString());
var expression = Rewrite(queryable2.Expression);
}
private static Expression Rewrite(Expression expression)
{
var visitor = new AddToWhere();
return visitor.Visit(expression);
}
class AddToWhere : ExpressionVisitor
{
protected override Expression VisitMethodCall(MethodCallExpression node)
{
ParameterExpression parameter;
LambdaExpression lambdaExpression;
if (node.Method.DeclaringType != typeof(Queryable) ||
node.Method.Name != "Where" ||
(lambdaExpression = ((UnaryExpression)node.Arguments[1]).Operand as LambdaExpression).Parameters.Count != 1 ||
(parameter = lambdaExpression.Parameters[0]).Type != typeof(int))
{
return base.VisitMethodCall(node);
}
return Expression.Call(
node.Object,
node.Method,
this.Visit(node.Arguments[0]),
Expression.Quote(
Expression.Lambda(
lambdaExpression.Type,
Expression.AndAlso(
lambdaExpression.Body,
Expression.Equal(
Expression.Modulo(
parameter,
Expression.Constant(
4
)
),
Expression.Constant(
0
)
)
),
lambdaExpression.Parameters
)
)
);
}
}
}