• Mander
  • NEWBIE
  • 0 Points
  • Member since 2013

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 5
    Questions
  • 10
    Replies
Hi!  I outsourced a request that was over my head, but there's an issue we didn't consider that our partner wants to charge a lot to fix.  I'd like to do it myself, but they're recommending against it.  Can someone help me understand if their reason makes sense?  
 
We use Cases as Product RMAs.  Each RMA Case has at least one custom object Return Line Item (RLI) related to it.  The RLI contains the product information (part number, quantity sold, qty returning, qty received, etc).  Our problem was that large customers would only return part of the product they requested an RMA for.  Because RMA cases had to be processed in full, credit would be delayed and inventory would be incorrect.  We asked our vendor to create a process that would create a second case for anything that had been returned and update the original case to show only what was pending return.

So for example:
Original Case
Line 1 has qty 3 expected and nothing has been received
Line 2 has qty 2 expected and 1 has been received
Line 3 has qty 4 expected and 4 have been received
 
Press Button.
 
Line 1 for qty 3 stays on the original case
Line 2 for qty 1 stays on the original case
 
Line 2 for qty 1 moves to the cloned case
Line 3 for qty 4 moves to the cloned case
  
Our issue is that from the example above Line 3 still exists on the original case and the qty expected is now 0.  It’s causing confusion in our process and I want to delete that RLI from the original case.  I created the following code to do so, but when I asked the opinion of the person who created the original process he said “There is the issue of doing DML in a trigger, and doing a query in a for loop is never a good idea, especially with how many transactions your trigger structure currently processes.”  What does he mean?  Is it really a concern since only one case would be updated at a time?
 
trigger DeleteZeroQtyReturn on Return_Line_Item__c (after update) {

List<Id> lstId = new List<Id>();
 
for(Return_Line_Item__c RLI: Trigger.old){
        List<Return_Line_Item__c> existRLIList = [Select Id from Return_Line_Item__c where QTY_Returned__c = 0 and Split_with_Button__c=true];
        delete existRLIList;
    }

}

 
  • December 02, 2014
  • Like
  • 0

I've been working on this trigger for days and I'm stuck.  

 

It's supposed to add the number of hours from a new budget to the hours that already exist on a project.  The first version worked, but testing was throwing Too many SOQL queries: 101 error.

 

So I tried to add the lists in and now I'm getting the following message and the trigger doesn't work.   

      System.DmlException: Insert failed. First exception on row 0; first error:      

      CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, SumChangeHours: execution of AfterInsert

      caused by: System.ListException: List index out of bounds: 0

      Trigger.SumChangeHours: line 49, column 1: []

 

Can someone help me, please?

 

Version 1

trigger SumChangeHours on pse__Budget__c (after insert, after update ,after delete) {
List<pse__Proj__c> listProjToUpdate = new List<pse__Proj__c>();
    Set<ID> setProjIds = new Set<ID>();
    List<Database.SaveResult> dmlResults;
    
if(trigger.isInsert || trigger.isUpdate){
        for(pse__Budget__c B : trigger.new){
            if(B.pse__Project__c != null) {
                setProjIds.add(B.pse__Project__c);
            }
        }
    }    

    if(trigger.isDelete){ 
        for(pse__Budget__c B : trigger.old){  
            if(B.pse__Project__c != null ){ 
                setProjIds.add(B.pse__Project__c);            
            }
        }
    }
    
System.debug('##########setProjIds:'+setProjIds);

   for(pse__Proj__c proj : [Select Id, Total_Installation_Hours_Sold__c, Total_CAD_Hours_Sold__c, Total_Commissioning_Hours_Sold__c, Total_Network_Engineer_Hours_Sold__c, Total_Programming_Hours_Sold__c, Total_Pro_Services_Hours_Sold__c, 
       (Select Id, pse__Project__c, CAD_Hours__c, Commissioning_Hours__c, Installation_Hours__c, Network_Engineer_Hours__c, Programming_Hours__c, Pro_Services_Hours__c From pse__Budgets__r) 
       From pse__Proj__c Where Id IN :setProjIds]){       

    proj.Total_CAD_Hours_Sold__c=0;
    proj.Total_Commissioning_Hours_Sold__c=0;
    proj.Total_Installation_Hours_Sold__c=0;
    proj.Total_Network_Engineer_Hours_Sold__c=0;
    proj.Total_Programming_Hours_Sold__c=0;
    proj.Total_Pro_Services_Hours_Sold__c=0;


    for(pse__Budget__c B : proj.pse__Budgets__r){

        if( B.CAD_Hours__c != null){
            proj.Total_CAD_Hours_Sold__c+= B.CAD_Hours__c;}
        
        if(B.Pro_Services_Hours__c != null){
            proj.Total_Pro_Services_Hours_Sold__c += B.Pro_Services_Hours__c;}

        if(B.Programming_Hours__c!= null){
             proj.Total_Programming_Hours_Sold__c += B.Programming_Hours__c;}
            
        if(B.Installation_Hours__c != null){
            proj.Total_Installation_Hours_Sold__c += B.Installation_Hours__c;}

        if(B.Network_Engineer_Hours__c != null){
            proj.Total_Network_Engineer_Hours_Sold__c += B.Network_Engineer_Hours__c;}    

      }
      listProjToUpdate.add(proj);
    }


//Update Project Records
  dmlResults = Database.update(listProjToUpdate,false);
  //Process the Update results.
  addErrorMsgs(dmlResults);
  
  public void addErrorMsgs(List<Database.SaveResult> results){
    for(Database.SaveResult result : results){
      if( !result.isSuccess() ){
        
        for(Database.Error DbError : result.getErrors()){
          // Check if the error is related to trival access level.
          // Access levels equal or more permissive than the object's default
          // access level are not allowed.
          // These sharing records are not required and thus an insert exception is acceptable.
          if(DbError.getStatusCode() == StatusCode.FIELD_INTEGRITY_EXCEPTION &&
          DbError.getMessage().contains('AccessLevel')){
          // Indicates success.
            continue;
          }else{
            System.debug('##Error:'+DbError.getMessage());
            
            if(trigger.isInsert || trigger.isUpdate)
              trigger.new[0].addError(DbError.getMessage());
            
            if(trigger.isDelete)
              trigger.old[0].addError(DbError.getMessage());
          }
        }
      }
    }
  }

}

 Version 2

trigger SumChangeHours on pse__Budget__c (after insert, after update ,after delete) {

List<pse__Proj__c> listProjToUpdate = new List<pse__Proj__c>();

    //set of ids for triggered budgets
    set<ID> setBudgetIds= new set<ID>();
    
    // set of project ids for triggered transaction line items. 
    set<ID> setProjectIds=new set<ID>(); 

    //Map from Project.Id to Project object
    map<ID,pse__Proj__c> mapProjIdToProject = new map<ID,pse__Proj__c>();

    //temp project for updating
    pse__Proj__c oTmpProject;

List<Database.SaveResult> dmlResults;

    //when budget is added or updated
    if(trigger.isInsert|| trigger.isUpdate){

        //adding budget ids from trigger.new
        for(pse__Budget__c OB : Trigger.new){
            setBudgetIds.add(OB.id);
            }
        }

    //when budget is deleted
    if(trigger.isDelete){
        //adding budget ids from trigger.old
        for(pse__Budget__c OB : Trigger.old){
            setBudgetIds.add(OB.id);
            }
        }

    //making map of projects for updating
    List<pse__Proj__c> proj = [Select Id, Total_Installation_Hours_Sold__c, Total_CAD_Hours_Sold__c, Total_Commissioning_Hours_Sold__c, Total_Network_Engineer_Hours_Sold__c, Total_Programming_Hours_Sold__c, Total_Pro_Services_Hours_Sold__c, 
       (Select Id, pse__Project__c, CAD_Hours__c, Commissioning_Hours__c, Installation_Hours__c, Network_Engineer_Hours__c, Programming_Hours__c, Pro_Services_Hours__c From pse__Budgets__r) 
       From pse__Proj__c Where Id IN :setProjectIds];{   

    //clearing out the older values for project's specific fields
    proj[0].Total_CAD_Hours_Sold__c=0;
    proj[0].Total_Commissioning_Hours_Sold__c=0;
    proj[0].Total_Installation_Hours_Sold__c=0;
    proj[0].Total_Network_Engineer_Hours_Sold__c=0;
    proj[0].Total_Programming_Hours_Sold__c=0;
    proj[0].Total_Pro_Services_Hours_Sold__c=0;
    
    //adding to map projects
    mapProjIdToProject.put(proj[0].Id, Proj[0]);
    
    //Making set of all related budget ids.
    for(pse__Budget__c OBH : Proj[0].pse__Budgets__r){
        setBudgetIds.add(OBH.id);
        }

    //updates project's fields to new value
    oTmpProject = mapProjIdToProject.get(proj[0].id);
    for(pse__Budget__c OB : proj[0].pse__Budgets__r){

        if(OB.CAD_Hours__c != null){
            oTmpProject.Total_CAD_Hours_Sold__c+= OB.CAD_Hours__c;}
        
        if(OB.Pro_Services_Hours__c != null){
            oTmpProject.Total_Pro_Services_Hours_Sold__c += OB.Pro_Services_Hours__c;}

        if(OB.Programming_Hours__c!= null){
             oTmpProject.Total_Programming_Hours_Sold__c += OB.Programming_Hours__c;}
            
        if(OB.Installation_Hours__c != null){
            oTmpProject.Total_Installation_Hours_Sold__c += OB.Installation_Hours__c;}

        if(OB.Network_Engineer_Hours__c != null){
            oTmpProject.Total_Network_Engineer_Hours_Sold__c += OB.Network_Engineer_Hours__c;} 

        }
        }

    //Update Project Records
    dmlResults = Database.update(mapProjIdToProject.values(),false);
    //Process the Update results.
    addErrorMsgs(dmlResults);

public void addErrorMsgs(List<Database.SaveResult> results){
    for(Database.SaveResult result : results){
      if( !result.isSuccess() ){
        
        for(Database.Error DbError : result.getErrors()){
          // Check if the error is related to trival access level.
          // Access levels equal or more permissive than the object's default
          // access level are not allowed.
          // These sharing records are not required and thus an insert exception is acceptable.
          if(DbError.getStatusCode() == StatusCode.FIELD_INTEGRITY_EXCEPTION &&
          DbError.getMessage().contains('AccessLevel')){
          // Indicates success.
            continue;
          }else{
            System.debug('##Error:'+DbError.getMessage());
            
            if(trigger.isInsert || trigger.isUpdate)
              trigger.new[0].addError(DbError.getMessage());
            
            if(trigger.isDelete)
              trigger.old[0].addError(DbError.getMessage());  
          }
        }
      }
    }
  }

  
}

 Thanks!

Is that even a real relationship? Great-parent?!?  :P

 

I'm trying to cause an update of an object that isn't directly related to another.  In this case, Project>Case>Return Line Item.  If there's a change in the Actual Unit Credit to Customer on the Return Line Item, I need the new amount to update on the project.

 

I can make this work if I add a lookup for the Project to the Return Line Item, but I don't want to.  This would be a huge training issue for us as we use this information for financial reporting.

 

Works with:  rli.Project__c, but not with rli.RMA_Case__r.Project__c.  Any ideas?

trigger RLIOverrideValue on Return_Line_Item__c (after update) {
    set<id> projectIDs = new set<id>();

    If(trigger.isUpdate){
        for (Return_Line_Item__c rli: Trigger.new){
        try{
                if(rli.RMA_Case__r.Project__c != null && rli.Actual_Unit_Credit_to_Customer__c != trigger.oldMap.get(rli.ID).Actual_Unit_Credit_to_Customer__c){
                    projectIDs.add(rli.RMA_Case__r.Project__c);
            }
        }catch(exception e){
            projectIDs.add(rli.RMA_Case__r.Project__c);
            }
        }
        if(projectIDs.size() >0){
        rli_Handler.updateProjectPendingRMA(projectIDs);
        }
    }
    
}

 ~Mander

A few years ago we had someone create task templates and the trigger to create tasks on a custom object we call projects.  It worked well at the time, but I need to make it more flexible.  

 

Right now, it creates a task and assigns it to the Project Manager.  I'd like for it to look at a Task category (or something like it) field to determine what type of task it is and then assign it to the user assign to that role.  For example, we need to generate a task to the CAD Tech.  I'd like the trigger to look for the category: CAD and find the CAD Tech assigned (a lookup contact field on the project) to the project and assign the task to that person.  

 

Additionally, the current Task Template trigger makes the due date of the task = Start Date of the project.  I'd like it to be more flexible like tasks are if they're created by workflows: Trigger Date + 15, etc.  

 

Does anyone know how I could do that?

 

 

/*********************************************************************************
Name : createTasksForProjects 
Created Date : 7 Jan 2010
modified Date : 25 Jan 2010
Usages : If Create task is set to true 
         1)Then we need to fetch Task Templates having the region and project type.
         2)Create task for all the templates having same values for projects.
*********************************************************************************/
trigger createTasksForProjects on pse__Proj__c (After insert) {
   
    Set<String> projectRecordType = new Set<String>();
    Set<String> projectId = new Set<String>();
    List<pse__Proj__c> projectList = new List<pse__Proj__c>();
    //Create set of Region and Project Type.
    List<pse__proj__c> newProjectList = [Select Id ,Name ,CreateTask__c,RecordTypeId,RecordType.Name,pse__Project_Manager__c,CAD_Tech__c,Programmer__c,Lead_Tech__c,CAD_Hours__c,pse__Start_Date__c from pse__proj__c where id in: Trigger.New];
    For(pse__Proj__c proj : newProjectList){
       if(proj.CreateTask__c == true){
         System.Debug('Record Type :'+proj.RecordTypeId);
         if(proj.RecordTypeId!=null){
            System.Debug('Record Type Name:'+proj.RecordType.Name);
            projectRecordType.add(proj.RecordType.Name);
         }
       }
    }
    List<Task> tasksToCreate = new List<Task>();
    //If region and project type exists.
    if(projectRecordType.size() > 0){
        
        //Fetch all task templates which holds same region and Project Type.
        For(List<Task_Template__c> taskTemplates : [Select id,Order__c,Project_Type__c,Assigned__c,Region_del__c,Subject__c,Name,Project_Record_Type__c From  Task_Template__c Where Project_Record_Type__c in : projectRecordType ]){
            For(Task_Template__c taskTemp : taskTemplates ){
                For(pse__Proj__c proj :newProjectList){
                    System.Debug('project Record Type '+proj.RecordType.Name+'\n Template project type'+taskTemp.Project_Record_Type__c);
                   //Create Task.
                   if(proj.RecordTypeId!=null && proj.RecordType.Name == taskTemp.Project_Record_Type__c){
                        if(proj.CreateTask__c == true && proj.pse__Project_Manager__c != null){
                            Task task = new Task();
                            task.Subject = taskTemp.name; 
                            task.WhoID = proj.pse__Project_Manager__c;                  
                            task.ActivityDate = proj.pse__Start_Date__c;
                            task.WhatID = proj.id;
                            task.Order__c = taskTemp.Order__c;
                            task.type = 'Other';
                            tasksToCreate.Add(task);
                            //If size more then 998 then need to insert list and clear it as it can hold only 1000 records.
                            if(tasksToCreate.size()== 999){
                                insert tasksToCreate;
                                tasksToCreate.clear();
                            }
                            projectId.add(proj.Id);                             
                        }
                    }
                }
            }            
        }
        //If size greater then 0 then insert task.
        if(tasksToCreate.size()> 0){
            insert tasksToCreate;
        }
        for(pse__Proj__c proj:Trigger.New){
            if(projectId.contains(proj.Id)){
                pse__Proj__c projObj = new pse__Proj__c(Id=proj.Id);
                projObj.alreadyCreateTaskFlag__c = true;
                projectList.add(projObj);
                if(projectList.size()== 999){
                       update projectList;
                       projectList.clear();
                }
            }
        }
        if(projectList.size()>0){
            update projectList;
        }
    }

}

Current fields on the Task Template object are:

Field Label                       API Name                             Data Type

Assigned                         Assigned__c                        Lookup(User)

Order                                Order__c                               Number(3, 0)

Project Record Type     Project_Record_Type__c   Picklist

Project Type                    Project_Type__c                  Picklist

Region                             Region_del__c                    Lookup(Region)

Subject                            Subject__c                            Text(100)

 

Thanks!

Mander

I'm really tired of getting requests to change the account ownership and would like to write some sort of Apex trigger to do the update.  I can't find an example of anyone ever doing this and I'm new to Apex code.  Will this work and if so, do you have something I can start with?

 

Ideally, it would work almost like the Request Update button with some additional adjustments.   The user would click the button and it would check to see of the current owner is active.  If not, the ownership will change to the current user.  If the owner is active, it will send an email requesting ownership and the current owner can either approve or deny.  If approved the ownership would change, if denied, a rejection email would be sent back to the requester.  

 

Am I dreaming to big?  I'd really appreciate any help.

  • January 30, 2013
  • Like
  • 0
Hi!  I outsourced a request that was over my head, but there's an issue we didn't consider that our partner wants to charge a lot to fix.  I'd like to do it myself, but they're recommending against it.  Can someone help me understand if their reason makes sense?  
 
We use Cases as Product RMAs.  Each RMA Case has at least one custom object Return Line Item (RLI) related to it.  The RLI contains the product information (part number, quantity sold, qty returning, qty received, etc).  Our problem was that large customers would only return part of the product they requested an RMA for.  Because RMA cases had to be processed in full, credit would be delayed and inventory would be incorrect.  We asked our vendor to create a process that would create a second case for anything that had been returned and update the original case to show only what was pending return.

So for example:
Original Case
Line 1 has qty 3 expected and nothing has been received
Line 2 has qty 2 expected and 1 has been received
Line 3 has qty 4 expected and 4 have been received
 
Press Button.
 
Line 1 for qty 3 stays on the original case
Line 2 for qty 1 stays on the original case
 
Line 2 for qty 1 moves to the cloned case
Line 3 for qty 4 moves to the cloned case
  
Our issue is that from the example above Line 3 still exists on the original case and the qty expected is now 0.  It’s causing confusion in our process and I want to delete that RLI from the original case.  I created the following code to do so, but when I asked the opinion of the person who created the original process he said “There is the issue of doing DML in a trigger, and doing a query in a for loop is never a good idea, especially with how many transactions your trigger structure currently processes.”  What does he mean?  Is it really a concern since only one case would be updated at a time?
 
trigger DeleteZeroQtyReturn on Return_Line_Item__c (after update) {

List<Id> lstId = new List<Id>();
 
for(Return_Line_Item__c RLI: Trigger.old){
        List<Return_Line_Item__c> existRLIList = [Select Id from Return_Line_Item__c where QTY_Returned__c = 0 and Split_with_Button__c=true];
        delete existRLIList;
    }

}

 
  • December 02, 2014
  • Like
  • 0

I've been working on this trigger for days and I'm stuck.  

 

It's supposed to add the number of hours from a new budget to the hours that already exist on a project.  The first version worked, but testing was throwing Too many SOQL queries: 101 error.

 

So I tried to add the lists in and now I'm getting the following message and the trigger doesn't work.   

      System.DmlException: Insert failed. First exception on row 0; first error:      

      CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, SumChangeHours: execution of AfterInsert

      caused by: System.ListException: List index out of bounds: 0

      Trigger.SumChangeHours: line 49, column 1: []

 

Can someone help me, please?

 

Version 1

trigger SumChangeHours on pse__Budget__c (after insert, after update ,after delete) {
List<pse__Proj__c> listProjToUpdate = new List<pse__Proj__c>();
    Set<ID> setProjIds = new Set<ID>();
    List<Database.SaveResult> dmlResults;
    
if(trigger.isInsert || trigger.isUpdate){
        for(pse__Budget__c B : trigger.new){
            if(B.pse__Project__c != null) {
                setProjIds.add(B.pse__Project__c);
            }
        }
    }    

    if(trigger.isDelete){ 
        for(pse__Budget__c B : trigger.old){  
            if(B.pse__Project__c != null ){ 
                setProjIds.add(B.pse__Project__c);            
            }
        }
    }
    
System.debug('##########setProjIds:'+setProjIds);

   for(pse__Proj__c proj : [Select Id, Total_Installation_Hours_Sold__c, Total_CAD_Hours_Sold__c, Total_Commissioning_Hours_Sold__c, Total_Network_Engineer_Hours_Sold__c, Total_Programming_Hours_Sold__c, Total_Pro_Services_Hours_Sold__c, 
       (Select Id, pse__Project__c, CAD_Hours__c, Commissioning_Hours__c, Installation_Hours__c, Network_Engineer_Hours__c, Programming_Hours__c, Pro_Services_Hours__c From pse__Budgets__r) 
       From pse__Proj__c Where Id IN :setProjIds]){       

    proj.Total_CAD_Hours_Sold__c=0;
    proj.Total_Commissioning_Hours_Sold__c=0;
    proj.Total_Installation_Hours_Sold__c=0;
    proj.Total_Network_Engineer_Hours_Sold__c=0;
    proj.Total_Programming_Hours_Sold__c=0;
    proj.Total_Pro_Services_Hours_Sold__c=0;


    for(pse__Budget__c B : proj.pse__Budgets__r){

        if( B.CAD_Hours__c != null){
            proj.Total_CAD_Hours_Sold__c+= B.CAD_Hours__c;}
        
        if(B.Pro_Services_Hours__c != null){
            proj.Total_Pro_Services_Hours_Sold__c += B.Pro_Services_Hours__c;}

        if(B.Programming_Hours__c!= null){
             proj.Total_Programming_Hours_Sold__c += B.Programming_Hours__c;}
            
        if(B.Installation_Hours__c != null){
            proj.Total_Installation_Hours_Sold__c += B.Installation_Hours__c;}

        if(B.Network_Engineer_Hours__c != null){
            proj.Total_Network_Engineer_Hours_Sold__c += B.Network_Engineer_Hours__c;}    

      }
      listProjToUpdate.add(proj);
    }


//Update Project Records
  dmlResults = Database.update(listProjToUpdate,false);
  //Process the Update results.
  addErrorMsgs(dmlResults);
  
  public void addErrorMsgs(List<Database.SaveResult> results){
    for(Database.SaveResult result : results){
      if( !result.isSuccess() ){
        
        for(Database.Error DbError : result.getErrors()){
          // Check if the error is related to trival access level.
          // Access levels equal or more permissive than the object's default
          // access level are not allowed.
          // These sharing records are not required and thus an insert exception is acceptable.
          if(DbError.getStatusCode() == StatusCode.FIELD_INTEGRITY_EXCEPTION &&
          DbError.getMessage().contains('AccessLevel')){
          // Indicates success.
            continue;
          }else{
            System.debug('##Error:'+DbError.getMessage());
            
            if(trigger.isInsert || trigger.isUpdate)
              trigger.new[0].addError(DbError.getMessage());
            
            if(trigger.isDelete)
              trigger.old[0].addError(DbError.getMessage());
          }
        }
      }
    }
  }

}

 Version 2

trigger SumChangeHours on pse__Budget__c (after insert, after update ,after delete) {

List<pse__Proj__c> listProjToUpdate = new List<pse__Proj__c>();

    //set of ids for triggered budgets
    set<ID> setBudgetIds= new set<ID>();
    
    // set of project ids for triggered transaction line items. 
    set<ID> setProjectIds=new set<ID>(); 

    //Map from Project.Id to Project object
    map<ID,pse__Proj__c> mapProjIdToProject = new map<ID,pse__Proj__c>();

    //temp project for updating
    pse__Proj__c oTmpProject;

List<Database.SaveResult> dmlResults;

    //when budget is added or updated
    if(trigger.isInsert|| trigger.isUpdate){

        //adding budget ids from trigger.new
        for(pse__Budget__c OB : Trigger.new){
            setBudgetIds.add(OB.id);
            }
        }

    //when budget is deleted
    if(trigger.isDelete){
        //adding budget ids from trigger.old
        for(pse__Budget__c OB : Trigger.old){
            setBudgetIds.add(OB.id);
            }
        }

    //making map of projects for updating
    List<pse__Proj__c> proj = [Select Id, Total_Installation_Hours_Sold__c, Total_CAD_Hours_Sold__c, Total_Commissioning_Hours_Sold__c, Total_Network_Engineer_Hours_Sold__c, Total_Programming_Hours_Sold__c, Total_Pro_Services_Hours_Sold__c, 
       (Select Id, pse__Project__c, CAD_Hours__c, Commissioning_Hours__c, Installation_Hours__c, Network_Engineer_Hours__c, Programming_Hours__c, Pro_Services_Hours__c From pse__Budgets__r) 
       From pse__Proj__c Where Id IN :setProjectIds];{   

    //clearing out the older values for project's specific fields
    proj[0].Total_CAD_Hours_Sold__c=0;
    proj[0].Total_Commissioning_Hours_Sold__c=0;
    proj[0].Total_Installation_Hours_Sold__c=0;
    proj[0].Total_Network_Engineer_Hours_Sold__c=0;
    proj[0].Total_Programming_Hours_Sold__c=0;
    proj[0].Total_Pro_Services_Hours_Sold__c=0;
    
    //adding to map projects
    mapProjIdToProject.put(proj[0].Id, Proj[0]);
    
    //Making set of all related budget ids.
    for(pse__Budget__c OBH : Proj[0].pse__Budgets__r){
        setBudgetIds.add(OBH.id);
        }

    //updates project's fields to new value
    oTmpProject = mapProjIdToProject.get(proj[0].id);
    for(pse__Budget__c OB : proj[0].pse__Budgets__r){

        if(OB.CAD_Hours__c != null){
            oTmpProject.Total_CAD_Hours_Sold__c+= OB.CAD_Hours__c;}
        
        if(OB.Pro_Services_Hours__c != null){
            oTmpProject.Total_Pro_Services_Hours_Sold__c += OB.Pro_Services_Hours__c;}

        if(OB.Programming_Hours__c!= null){
             oTmpProject.Total_Programming_Hours_Sold__c += OB.Programming_Hours__c;}
            
        if(OB.Installation_Hours__c != null){
            oTmpProject.Total_Installation_Hours_Sold__c += OB.Installation_Hours__c;}

        if(OB.Network_Engineer_Hours__c != null){
            oTmpProject.Total_Network_Engineer_Hours_Sold__c += OB.Network_Engineer_Hours__c;} 

        }
        }

    //Update Project Records
    dmlResults = Database.update(mapProjIdToProject.values(),false);
    //Process the Update results.
    addErrorMsgs(dmlResults);

public void addErrorMsgs(List<Database.SaveResult> results){
    for(Database.SaveResult result : results){
      if( !result.isSuccess() ){
        
        for(Database.Error DbError : result.getErrors()){
          // Check if the error is related to trival access level.
          // Access levels equal or more permissive than the object's default
          // access level are not allowed.
          // These sharing records are not required and thus an insert exception is acceptable.
          if(DbError.getStatusCode() == StatusCode.FIELD_INTEGRITY_EXCEPTION &&
          DbError.getMessage().contains('AccessLevel')){
          // Indicates success.
            continue;
          }else{
            System.debug('##Error:'+DbError.getMessage());
            
            if(trigger.isInsert || trigger.isUpdate)
              trigger.new[0].addError(DbError.getMessage());
            
            if(trigger.isDelete)
              trigger.old[0].addError(DbError.getMessage());  
          }
        }
      }
    }
  }

  
}

 Thanks!

Is that even a real relationship? Great-parent?!?  :P

 

I'm trying to cause an update of an object that isn't directly related to another.  In this case, Project>Case>Return Line Item.  If there's a change in the Actual Unit Credit to Customer on the Return Line Item, I need the new amount to update on the project.

 

I can make this work if I add a lookup for the Project to the Return Line Item, but I don't want to.  This would be a huge training issue for us as we use this information for financial reporting.

 

Works with:  rli.Project__c, but not with rli.RMA_Case__r.Project__c.  Any ideas?

trigger RLIOverrideValue on Return_Line_Item__c (after update) {
    set<id> projectIDs = new set<id>();

    If(trigger.isUpdate){
        for (Return_Line_Item__c rli: Trigger.new){
        try{
                if(rli.RMA_Case__r.Project__c != null && rli.Actual_Unit_Credit_to_Customer__c != trigger.oldMap.get(rli.ID).Actual_Unit_Credit_to_Customer__c){
                    projectIDs.add(rli.RMA_Case__r.Project__c);
            }
        }catch(exception e){
            projectIDs.add(rli.RMA_Case__r.Project__c);
            }
        }
        if(projectIDs.size() >0){
        rli_Handler.updateProjectPendingRMA(projectIDs);
        }
    }
    
}

 ~Mander

A few years ago we had someone create task templates and the trigger to create tasks on a custom object we call projects.  It worked well at the time, but I need to make it more flexible.  

 

Right now, it creates a task and assigns it to the Project Manager.  I'd like for it to look at a Task category (or something like it) field to determine what type of task it is and then assign it to the user assign to that role.  For example, we need to generate a task to the CAD Tech.  I'd like the trigger to look for the category: CAD and find the CAD Tech assigned (a lookup contact field on the project) to the project and assign the task to that person.  

 

Additionally, the current Task Template trigger makes the due date of the task = Start Date of the project.  I'd like it to be more flexible like tasks are if they're created by workflows: Trigger Date + 15, etc.  

 

Does anyone know how I could do that?

 

 

/*********************************************************************************
Name : createTasksForProjects 
Created Date : 7 Jan 2010
modified Date : 25 Jan 2010
Usages : If Create task is set to true 
         1)Then we need to fetch Task Templates having the region and project type.
         2)Create task for all the templates having same values for projects.
*********************************************************************************/
trigger createTasksForProjects on pse__Proj__c (After insert) {
   
    Set<String> projectRecordType = new Set<String>();
    Set<String> projectId = new Set<String>();
    List<pse__Proj__c> projectList = new List<pse__Proj__c>();
    //Create set of Region and Project Type.
    List<pse__proj__c> newProjectList = [Select Id ,Name ,CreateTask__c,RecordTypeId,RecordType.Name,pse__Project_Manager__c,CAD_Tech__c,Programmer__c,Lead_Tech__c,CAD_Hours__c,pse__Start_Date__c from pse__proj__c where id in: Trigger.New];
    For(pse__Proj__c proj : newProjectList){
       if(proj.CreateTask__c == true){
         System.Debug('Record Type :'+proj.RecordTypeId);
         if(proj.RecordTypeId!=null){
            System.Debug('Record Type Name:'+proj.RecordType.Name);
            projectRecordType.add(proj.RecordType.Name);
         }
       }
    }
    List<Task> tasksToCreate = new List<Task>();
    //If region and project type exists.
    if(projectRecordType.size() > 0){
        
        //Fetch all task templates which holds same region and Project Type.
        For(List<Task_Template__c> taskTemplates : [Select id,Order__c,Project_Type__c,Assigned__c,Region_del__c,Subject__c,Name,Project_Record_Type__c From  Task_Template__c Where Project_Record_Type__c in : projectRecordType ]){
            For(Task_Template__c taskTemp : taskTemplates ){
                For(pse__Proj__c proj :newProjectList){
                    System.Debug('project Record Type '+proj.RecordType.Name+'\n Template project type'+taskTemp.Project_Record_Type__c);
                   //Create Task.
                   if(proj.RecordTypeId!=null && proj.RecordType.Name == taskTemp.Project_Record_Type__c){
                        if(proj.CreateTask__c == true && proj.pse__Project_Manager__c != null){
                            Task task = new Task();
                            task.Subject = taskTemp.name; 
                            task.WhoID = proj.pse__Project_Manager__c;                  
                            task.ActivityDate = proj.pse__Start_Date__c;
                            task.WhatID = proj.id;
                            task.Order__c = taskTemp.Order__c;
                            task.type = 'Other';
                            tasksToCreate.Add(task);
                            //If size more then 998 then need to insert list and clear it as it can hold only 1000 records.
                            if(tasksToCreate.size()== 999){
                                insert tasksToCreate;
                                tasksToCreate.clear();
                            }
                            projectId.add(proj.Id);                             
                        }
                    }
                }
            }            
        }
        //If size greater then 0 then insert task.
        if(tasksToCreate.size()> 0){
            insert tasksToCreate;
        }
        for(pse__Proj__c proj:Trigger.New){
            if(projectId.contains(proj.Id)){
                pse__Proj__c projObj = new pse__Proj__c(Id=proj.Id);
                projObj.alreadyCreateTaskFlag__c = true;
                projectList.add(projObj);
                if(projectList.size()== 999){
                       update projectList;
                       projectList.clear();
                }
            }
        }
        if(projectList.size()>0){
            update projectList;
        }
    }

}

Current fields on the Task Template object are:

Field Label                       API Name                             Data Type

Assigned                         Assigned__c                        Lookup(User)

Order                                Order__c                               Number(3, 0)

Project Record Type     Project_Record_Type__c   Picklist

Project Type                    Project_Type__c                  Picklist

Region                             Region_del__c                    Lookup(Region)

Subject                            Subject__c                            Text(100)

 

Thanks!

Mander

I'm really tired of getting requests to change the account ownership and would like to write some sort of Apex trigger to do the update.  I can't find an example of anyone ever doing this and I'm new to Apex code.  Will this work and if so, do you have something I can start with?

 

Ideally, it would work almost like the Request Update button with some additional adjustments.   The user would click the button and it would check to see of the current owner is active.  If not, the ownership will change to the current user.  If the owner is active, it will send an email requesting ownership and the current owner can either approve or deny.  If approved the ownership would change, if denied, a rejection email would be sent back to the requester.  

 

Am I dreaming to big?  I'd really appreciate any help.

  • January 30, 2013
  • Like
  • 0