function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Glen.ax1034Glen.ax1034 

APEX - Create Case from Contract Activation and Link Back to Contract

I am trying to create a case whenever the contract is activated and have the case link back to the contract. I've been perusing the forum for a few days and haven't posted this until I decided that I knew enough to even know i needed help.

 

the code i have is below.. the two comments in the middle are what i am trying to do.. and where it is erroring.

 

unfortunately.. there is no ContractId for a case like there is an AccountId for a case. that's where I got confused.

 

I've created two additional fields that i thought would help but i cannot populate them:

 

 Contract

Contract__c

Lookup(Contract)

 

Contract Number

Contract_Number__c

Lookup(Contract)

 

I can't pass the contract number by string or by reference:

 

string:

There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger ActivateContract caused an unexpected exception, contact your administrator: ActivateContract: execution of BeforeUpdate caused by: System.StringException: Invalid id: 2011061331: Trigger.ActivateContract: line 14, column 6"

 

reference:

There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger ActivateContract caused an unexpected exception, contact your administrator: ActivateContract: execution of BeforeUpdate caused by: System.DmlException: Upsert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, Account ID: id value of incorrect type: 800T0000000XtfjIAC: [AccountId]: Trigger.ActivateContract: line 22, column 4". 

 

Code:

 

trigger ActivateContract on Contract (before update) {

 // Create a list of accounts to update
 List<Account> acctList = new List<Account>();

 for (Contract contract : Trigger.new) {

  // If the contract has been activated...
  if (contract.Status == 'Activated Signed') {
   if(contract.Major_Product_Line__c == 'Background (BSG)') {
 	 	Case c = new Case(AccountId = contract.Id);
  	 	//c.Contract_Number__c = contract.ContractNumber;
  //	 	c.Contract_Number__c = contract.Id;

	  upsert c;
   }
  }
  // update the database with the account status changes
  update acctList;
 }
}

 Any Ideas?

 

Best Answer chosen by Admin (Salesforce Developers) 
Glen.ax1034Glen.ax1034

this is what works

 

trigger ActivateContract on Contract (before update) {

  //create List for Contract ID's
  List<Id> idList = new List<Id>();
  for (Contract contract:Trigger.new){
    idList.add(contract.Id);
  }

  //Create map to link Contract ID's to Case Account ID's
//  Map<Id, Id> IdToAccountId = new Map<Id, Id>();
//  for(id eyeD: idList) {
//    IdToAccountId.put(eyeD, eyeD);
//  }
   
  //Use a for loop to run through The trigger Contracts and assign for every Case.AccountId a unique Contract.Id from the map
  List<Case> Cases = new List<Case>();
  for (Contract contract:Trigger.new){
   if (contract.Status == 'Activated Signed') {
    if(contract.Major_Product_Line__c == 'Background (BSG)') {
     Case CaseAdd = new Case ();
      CaseAdd.AccountId = contract.AccountId;
      CaseAdd.Contract__c = contract.Id;
     Cases.add(CaseAdd);
    }
   } else {
   	Case CaseAdd = new Case (Account__c = contract.Status);
   	Cases.add(CaseAdd);
   }
  }
  
  
  upsert Cases;
}

 

All Answers

Ray DehlerRay Dehler

A few things:

 

First you shouldn't do an explicit upsert of your variable c inside of a for loop.  See http://techblog.appirio.com/2009/08/writing-bulk-triggers-for-salesforcecom.html (and other results from the google search "bulk trigger salesforce")

 

Next, it looks like the issue is complaining on this line

  Case c = new Case(AccountId = contract.Id);

 

You're setting AccountId to a Contract's Id, which results in your Field Integrity exception.  An Account reference must be set to an Account Id.  I'm guessing you meant

  Case c = new Case(AccountId = contract.AccountId);

 

Finally, Contract.ContractNumber is of type String(30), so your Case.Contract_Number__c field should also be of type String(30), unless you want to do some conversion.  Most likely a better way to handle this field would be a formula field which looks up to the Case's field.

Glen.ax1034Glen.ax1034

Thanks Ray. the issue is either of these lines -- i commented them out because they are the two ways i thought it would work.. and it threw the two errors described:

 

     //c.Contract_Number__c = contract.ContractNumber;
  // c.Contract_Number__c = contract.Id;

that said, now i'm looking at bulk triggers... i'll have to rewrite using those, the learning curve i'm sure is steeper than it appears.

 

sets and maps, here i come.

Glen.ax1034Glen.ax1034

ray, i thought that these were formula fields in "Case" that look up the Contract... my issue is that presently, users need to type them in manually. i'm trying to get apex to prepopulate them.

 

Formula: Lookup(Contract)

Name:  Contract

Name in Apex: Contract__c

 

Formula:             Lookup(Contract) 

Name:                 Contract Number

Name in Apex:  Contract_Number__c

 

apparently in the apex editor they pass by reference.

 

still building in the bulk stuff. It's fun being the newb, completely unfamiliar with salesforce, and being tasked with learning apex because nobody else knows how to do it.

 

how long have you been with appirio, also looks like you run your own salesforce blog. among other things, it looks like you've developed an interest in poker, do you play online?

Glen.ax1034Glen.ax1034

found this: which i think is relevant for anyone following my stupidity.

 

http://boards.developerforce.com/t5/Apex-Code-Development/update-a-lookup-field/m-p/219503

 

i used to be a good programmer.. i swear! just new to apex... new to the whole syntax.

Glen.ax1034Glen.ax1034

lol.. it's sad how little progress i made today.

 

trigger ActivateContract on Contract (before insert) {

  //create List for Contract ID's
  List<Id> idList = new List<Id>();
  for (Contract contract:Trigger.new){
    idList.add(contract.Id);
  }

  //create a list of case stuff Id's and names for Id's in Contracts passed through triggers.
  List<Case> caseList = [SELECT Id, Name FROM Case WHERE Id in :idList];

  //put name and id to map.
  Map<String, Id> IdToAccountId = new Map<String, Id>();
  for(Case c: caseList) {
    IdToAccountId.put(c.Name, c.Id);
  }

  for (Contract c:Trigger.new){
    c.AccountId = nameToId.get(c.Id);
  }

 // Create a list of accounts to update
// List<Account> acctList = new List<Account>();
 
 // create a set of all the unique contracts
// List<Contract> contList = new List<Contract>();
 
 // create a set of all the unique Id's --- not sure why.
// List<Id> idList = new List<Id>();

 //for all of the contracts in the bulk trigger. add their iD to the list baby!
// for (Contract contract : Trigger.new) {
//  idList.add(contract.Id);
// }
 
/// Map<Id, Case> cases = new Map<Id, Case>([Select Id from Contract Where Id in :idList]);
 
// Map<Id>
// for(Contract c : contactList)
//  ContractIdToCaseId.put(c.Id);
  
 // query all of the user records for the unique userIds in the contract records
 // create a map for a lookup / hash table for the user info
  // If the contract has been activated...
//  if (contract.Status == 'Activated Signed') {
//   if(contract.Major_Product_Line__c == 'Background (BSG)') {
  	//if(contract.Recordtype == 'Application' || contract.Recordtype == 'Supporting Documentation' || contract.Recordtype == 'MSA - Master Service Agreement' || contract.Recordtype == 'Amendment' || contract.Recordtype == 'Standalone Agreement' || contract.Recordtype == 'Addendum') {
  	 //if(contract.Services_Included__c includes ('SAS - Background Services')) {
///  	 	Case c = new Case(AccountId = contract.Id);
//  	 	cases.get()
  	 //	c.Contract_Number__c = contract.ContractNumber;
  	 //	c.Contract_Number__c = contract.Id;
  	 //	c Contract = contract.Id;

//c.AccountId

      //Account a = new Account(Id = contract.AccountId);
      // ... set the associated Account as active
//c Account = "test";
///	  upsert c;
      //acctList.add ( a );
  	// }
  	//}

  // update the database with the account status changes
//  update acctList;
 }

 

Glen.ax1034Glen.ax1034

this is what works

 

trigger ActivateContract on Contract (before update) {

  //create List for Contract ID's
  List<Id> idList = new List<Id>();
  for (Contract contract:Trigger.new){
    idList.add(contract.Id);
  }

  //Create map to link Contract ID's to Case Account ID's
//  Map<Id, Id> IdToAccountId = new Map<Id, Id>();
//  for(id eyeD: idList) {
//    IdToAccountId.put(eyeD, eyeD);
//  }
   
  //Use a for loop to run through The trigger Contracts and assign for every Case.AccountId a unique Contract.Id from the map
  List<Case> Cases = new List<Case>();
  for (Contract contract:Trigger.new){
   if (contract.Status == 'Activated Signed') {
    if(contract.Major_Product_Line__c == 'Background (BSG)') {
     Case CaseAdd = new Case ();
      CaseAdd.AccountId = contract.AccountId;
      CaseAdd.Contract__c = contract.Id;
     Cases.add(CaseAdd);
    }
   } else {
   	Case CaseAdd = new Case (Account__c = contract.Status);
   	Cases.add(CaseAdd);
   }
  }
  
  
  upsert Cases;
}

 

This was selected as the best answer