• ilewi121
  • NEWBIE
  • 54 Points
  • Member since 2013
  • Senior CRM Administrator
  • AFS


  • Chatter
    Feed
  • 1
    Best Answers
  • 10
    Likes Received
  • 1
    Likes Given
  • 16
    Questions
  • 30
    Replies
I attempted to save an apex test class in our sandbox, but received the following error message:
 
An unexpected error has occurred. 1453659855-92905 (-2090026019) for deploymentId=1dre0000001FXv9AAG If this persists, please contact customer support.

Attempted Solutions: I found a similar issue, but I am unable to test their suggestion of refreshing my sandbox:
https://developer.salesforce.com/forums/?id=906F0000000AXfsIAG

Has anyone else come across this and found a solution other than wiping their sandbox?
Use Case:
When a user creates a case, an email response is delivered to a customer. This email should complete a "first response" milestone.

Technical Issue:
Trigger logic on the Case or EmailMessage objects cannot access CaseMilestones because they are created later asynchronously. I tried @Future calls, but CaseMilestone records still do not exist. A combo of Batch Apex Jobs scheduled from Triggers will successfully update CaseMilestones, but this is far from ideal.

Has anyone come across a solution to the need for immediate access to CaseMilestone records? (Some other use cases come to mind: Auto-complete "resolution" milestone if case is closed on create.)
 
I'm unable to open logs in the developer console. Every time I try to open a log, I receive the following error message:

Unable to Access Page
You are missing information needed by the page you have attempted to access. If you believe this is an error, please refresh your screen. If the error persists, please report it to our Customer Support team and provide the URL of the page you were requesting as well as any other related information. 

Error message screenshot

This issue is similar to this forum post (https://developer.salesforce.com/forums?id=906F0000000AtUNIA0), but I have attempted its solution and receive the same results.

Logs aren't showing in the "Logs" tab.
Double-clicking test logs from the "tests" tab produces the above error message.
 
Goal:
For cases created from Salesforce for Outlook (i.e. non-service personnel), we want to track entitlements based on when an email was received, not when it was logged into Salesforce.

Sample Use Case:
A sales rep receives an email from a customer about an issue. They create a case from the email, but the case is logged 24 hours after it was received. Salesforce shows the email as received on the date/time the sales rep enters it into salesforce, not when they received the email. Furthermore, there is no way to extract the original date/time of when it entered their inbox.

Attempts:
  • "Create Cases" Button in Salesforce for Outlook (Sets email date/time to date created in Salesforce, not date received)
  • Global "New Case" Action in Salesforce for Outlook (Brings email body, but not header, into case description)
  • "Add Email" button on Case listed in Salesforce for Outlook (Again, timestamp is on moment created and only places email body in description, not timestamp)
Anyone have a suggestion (apart from voting for the idea)?
 
When I make a chatter content post via desktop, Process Builder can access that post's FeedItem.Id field.
However, when I make the same post via mobile, Process Builder is unable to access the FeedItem.Id field.

Create flow in Process Builder:
  • Object: FeedItem
  • Logic: FeedItem.Type = ContentPost
  • Result: Post to user's wall in Chatter containing FeedItem.Id
Test On Desktop:
  • Use “file” publisher action on case feed to upload a document and comment.
  • Process makes post on user's wall with FeedItem.Id
Test On Mobile:
  • Use “file” publisher action on case to upload a document and comment.
  • Process does not make post on user's wall because it can't access FeedItem.Id.
Does anyone know what's happening here and how I can get consistent behavior between mobile and desktop?
I am building an email with Messaging.SingleEmailMessage. The email should include TXT, HTML, and ICS versions and be received by an Outlook recipient as a calendar invite (not as an email with an attachment). The key is in setting the ICS attachment as an option in the same "content-type: multipart/alternative" section as the TXT and HTML versions. However, when I build the email with setPlainTextBody, setHtmlBody, and setFileAttachments, it sets the ICS attachment in its own "content-type" section.

How can I write my code to bring the .ICS file into the "Content-type: multipart/alternative" block with the TXT & HTML?

My current code:
public static void sendEventInviteICS(String bodyTXT, String bodyHTML, String subject, String fromAddress, String displayName, List<String> toAddress, List<String> ccAddress){
    //Create Message
    Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
    msg.setReplyTo(fromAddress);
    msg.setSenderDisplayName(displayName);
    msg.setToAddresses(toAddress);
    msg.setCcAddresses(ccAddress);
    msg.setSubject(subject);
    //Create TXT Version
    msg.setPlainTextBody(bodyTXT);
    //Create HTML Version
    msg.setHTMLBody(bodyHTML);
    //Create ICS Attachment
    Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
    efa.setFileName('Meeting Invite.ics');
    efa.setContentType('text/calendar');
    Blob b = buildICSAttachment();
    efa.setBody(b);
    msg.setFileAttachments(new Messaging.EmailFileAttachment[]{efa});
    //Send the Email
    Messaging.sendEmail(new Messaging.SingleEmailMessage[]{msg});
}
MIME result from current code:
Date: Tue, 9 Dec 2014 21:16:26 +0000
From: Isaac Lewis <ilewis@afs.net>
Reply-To: <djillumine@gmail.com>
To: "ilewis@afs.net" <ilewis@afs.net>
Subject: Sandbox: This is the subject
MIME-Version: 1.0
Content-type: multipart/mixed;
	boundary="B_3500983009_1157947"

> This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

--B_3500983009_1157947
Content-type: multipart/alternative;
	boundary="B_3500983009_1123381"


--B_3500983009_1123381
Content-type: text/plain;
	charset="US-ASCII"
Content-transfer-encoding: 7bit

This is the text body


--B_3500983009_1123381
Content-type: text/html;
	charset="US-ASCII"
Content-transfer-encoding: quoted-printable

<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8">
</head>
<body>
<i>This is the html body</i>
</body>
</html>


--B_3500983009_1123381--


--B_3500983009_1157947
Content-type: text/calendar; name="Attachment Name.ics"
Content-disposition: attachment;
	filename="Attachment Name.ics"
Content-transfer-encoding: base64

QkVHSU46VkNBTEVOREFSDQpNRVRIT0Q6UkVRVUVTVA0KUFJPRElEOk1pY3Jvc29mdCBFeGNo=

--B_3500983009_1157947--
Desired MIME Result (boundaries around ICS have been moved to be part of the "Content-type: multipart/alternative" block):
Date: Tue, 9 Dec 2014 21:16:26 +0000
From: Isaac Lewis <ilewis@afs.net>
Reply-To: <djillumine@gmail.com>
To: "ilewis@afs.net" <ilewis@afs.net>
Subject: Sandbox: This is the subject
MIME-Version: 1.0
Content-type: multipart/mixed;
	boundary="B_3500983009_1157947"

> This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

--B_3500983009_1157947
Content-type: multipart/alternative;
	boundary="B_3500983009_1123381"


--B_3500983009_1123381
Content-type: text/plain;
	charset="US-ASCII"
Content-transfer-encoding: 7bit

This is the text body


--B_3500983009_1123381
Content-type: text/html;
	charset="US-ASCII"
Content-transfer-encoding: quoted-printable

<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8">
</head>
<body>
<i>This is the html body</i>
</body>
</html>

--B_3500983009_1123381
Content-type: text/calendar; name="Attachment Name.ics"
Content-disposition: attachment;
	filename="Attachment Name.ics"
Content-transfer-encoding: base64

QkVHSU46VkNBTEVOREFSDQpNRVRIT0Q6UkVRVUVTVA0KUFJPRElEOk1pY3Jvc29mdCBFeGNo=

--B_3500983009_1123381--

--B_3500983009_1157947--




 

I'm trying to prevent multiple SOQL queries in my method by creating a static list outside of the method.
The list is pulling from custom settings, so they should be static when the class runs.
Unfortunately, when I run the test for this class, the debug log shows nothing.
Am I putting this list in the wrong place?

Class
public class modeRanges{

    public static List<ModeRange__c> ModeRanges = [SELECT Mode_Type__c, Spend_Picklist_Value__c, Volume_Picklist_Value__c FROM ModeRange__c];

    public static void setSpendRangeFromVolumeRange(List<Mode__c> Modes){
	System.debug('ModeRanges: ' + ModeRanges);
        for(Mode__c m :Modes){
            for(ModeRange__c r: ModeRanges){
                if(m.Type__c == r.Mode_Type__c && m.Est_Volume__c == r.Volume_Picklist_Value__c){
                    m.Est_Spend__c = r.Spend_Picklist_Value__c;
                }
            }
        }
    }    
}

Debug Log
15:45:01:042 USER_DEBUG [12]|DEBUG|ModeRanges: ()

I have tested this trigger multiple times in the Sandbox, and it produces the proper results. However, when I deploy the changes to production, it comes out with different results. Does anyone know how I could trace what is producing the different results in production? I checked workflows and validation rules but couldn't find anything.
Is it possible to keep an opportunity team in place when ownership of an account or opportunity takes place WITHOUT checking the box? Would any of you have a trigger or suggestion for this kind of function?

I am building a trigger to automatically associate a custom Account child object with a custom Opportunity child object. My trigger works fine and tests perfectly, except when I went to upload a bunch of records to the new object, I received the following error on every item:

System.LimitException: Apex CPU time limit exceeded

I found a helpful article here:
http://salesforce.stackexchange.com/questions/22223/how-to-code-more-efficient-to-avoid-apex-cpu-time-limit-exceeded

But I'm still not sure what I'm doing wrong. Does anyone have any ideas?

Here is the trigger code:

<pre>
trigger associateOppChildtoAccChild on OppChild__c (before insert, before update) {

    Set<Id> OppSet = new Set<Id>();
    for(OppChild__c OppChild :Trigger.new){
        OppSet.add(OppChild.Opportunity__c);
    }
   
    Map<ID,ID> OPP_ACC = new Map<ID,ID>();
    Set<Id> AccSet = new Set<Id>();
    for(Opportunity OPP:[SELECT Id, AccountId from Opportunity where Id in :OppSet]){
        OPP_ACC.put(OPP.Id, OPP.AccountId);
        AccSet.add(OPP.AccountId);       
    }

    Map<ID,ID> ACC_OppChild = new Map<ID,ID>();
    for(OppChild__c OppChild :Trigger.new){
        for(ID OPP :OPP_ACC.keyset()){
            if(OPP == OppChild.Opportunity__c){
                ACC_OppChild.put(OPP_ACC.get(OPP), OppChild.Id);
            }
        }
    }
   
    List<AccChild__c> AccChildList = [SELECT Id, Account__c, Type__c, Annual_Spend__c, Number_of_Shipment_Transactions__c FROM AccChild__c WHERE Account__c in :AccSet];
   
    for(OppChild__c OppChild :Trigger.new){
        for(AccChild__c m: AccChildList){
            if(m.Type__c == OppChild.AccChild_Type__c){
                for(ID ACC :ACC_OppChild.keyset()){
                    if(ACC == m.Account__c){
                        OppChild.AccChild__c = m.Id;
                        System.debug('OppChild AccChild = ' + OppChild.AccChild__c);
                        OppChild.Annual_Spend__c = m.Annual_Spend__c;
                        OppChild.Number_of_Shipment_Transactions__c = m.Number_of_Shipment_Transactions__c;
                    } else {
                        OppChild.adderror(OppChild.AccChild_Type__c + ' AccChild must exist on Account to add OppChild');
                    }
                }
            }
        }
    }  
}
</pre>

I run the tests and my set and map both come back null. Can anyone spot what I'm missing here?

<pre>
trigger associatePMRtoMode on PMR__c (before insert, before update) {

    Set<ID> AccountIds = new Set<ID>();
    Map<ID,ID> ACC_PMR = new Map<ID,ID>();
   
    for (PMR__c PMR :Trigger.new){
        AccountIds.add(PMR.Opportunity__r.AccountId);
        ACC_PMR.put(PMR.Opportunity__r.AccountId, PMR.Id);
    }

    System.debug('AccountIds = ' + AccountIds);
    System.debug('ACC_PMR = ' + ACC_PMR);
}
</pre>

I have written a piece of code to create several custom objects when a lead converts. It works, but I don't know how to test the code. How do I write the queries to confirm the custom object was created automatically?

Here is the trigger:

trigger createModefromLead on Lead (after update) {

    List<Mode__c> UpdateModes = new List<Mode__c>();
    List<Mode__c> InsertModes = new List<Mode__c>();
    Set<Id> AccountIds = new Set<ID>();
   
    for (Lead l :Trigger.new){
        if(l.IsConverted){
            AccountIds.add(l.ConvertedAccountId);
        }
    }

List<Mode__c> ModeList = [SELECT Id, Account__c, Name, Mode_Type__c, Est_Shipping_Spend__c, Est_Shipping_Volume__c FROM Mode__c WHERE Account__c in :AccountIds];

    for (Lead l :Trigger.new){
        if(l.IsConverted){

   //Parcel Mode
            if(l.HasParcel__c == TRUE){
                Set<Id> ParcelModeCount = new Set<Id>();
                for (Mode__c m: ModeList){
                    if(m.Account__c == l.ConvertedAccountId && m.Mode_Type__c =='Parcel'){
                     m.Est_Shipping_Spend__c = l.Spend_Annual_Parcel__c;
                        m.Est_Shipping_Volume__c = l.Count_Daily_Parcel__c;
                        ParcelModeCount.add(m.Id);
                        UpdateModes.add(m);
                    }
                }
                if(ParcelModeCount.size() == 0){
                    Mode__c Parcel = new Mode__c(
                        Name = 'Parcel',
                        Mode_Type__c = 'Parcel',
                        Account__c = l.ConvertedAccountId,
                        Est_Shipping_Spend__c = l.Spend_Annual_Parcel__c,
                        Est_Shipping_Volume__c = l.Count_Daily_Parcel__c);
                    InsertModes.add(Parcel);
                }
            }
        }
        if(UpdateModes.size()>0){
            Update Updatemodes;
        }
        if(InsertModes.size()>0){
            Insert InsertModes;
        }
}  
}

And Here is the start of the test:
 
@isTest

private class createModefromLead_TestClass{

    public static testmethod void Convert_NewAcc_CreateMode(){

        //Insert Lead
        Lead LD1 = new Lead(
            LastName = 'LD1',
            Email = 'LD1@LCA.com',
            Company = 'LCA',
            Status = 'Closed - Qualified'
        );
        Insert LD1;
       
        //Convert Lead
        Database.LeadConvert lc = new database.LeadConvert();
        lc.setLeadId(LD1.id);
        lc.setConvertedStatus('Closed - Qualified');
       
        //Verify LD1 Convert
        Database.LeadConvertResult lcr = Database.convertLead(lc);
        System.assert(lcr.isSuccess());

        //Verify LD1 Creates Mode object on Account
       
    }
}


 
I am adding a trigger to default a Contact owner to the Account owner. It works fine and passes the test I wrote for it. HOWEVER, it fails a test from another piece of apex, telling me:

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, reassignCtOwnerToAcOwner: data changed by trigger for field Owner ID: owner cannot be blank: []

Here is the trigger I'm trying to deploy:

trigger reassignCtOwnerToAcOwner on Contact (before insert, before update) {

    List<Id> accountIds = new List<Id>();
    Map<Id, Id> accountOwnerIdMap = new Map<Id, Id>();

    // all the accounts whose owner ids to look up
    for ( Contact c : Trigger.new ) {
        accountIds.add( c.accountId );
    }
   
    // look up each account owner id
    for ( Account acct : [ SELECT id, ownerId FROM account WHERE id IN :accountIds ] ) {
        accountOwnerIdMap.put( acct.id, acct.ownerId );
    }
   
    // change contact owner to its account owner
    for ( Contact c : Trigger.new ) {
        c.ownerId = accountOwnerIdMap.get( c.accountId );
    }
}

Here is the test class for the OTHER trigger that fails when I try to insert a contact:

public static testMethod void validateContactCountsAndActivities() {

        //Create Account
  Account ac = new Account(
   Name='Test Account',
   Initial_Lead_Source__c='Cold Call',
   Initial_Lead_Source_Detail__c='Cold Call',
   Account_Type__c='Prospect',
   Account_Status__c='Not Contacted'   );
  insert ac;

        //Create Contact
        Contact ct = new Contact(
                LastName='Test Contact',
                Email='testcontact@email.com',
                Account= ac);
        insert ct;




I am working on an apex trigger/class to display the next activity subject & date on the account object. The code works fine, and a manual test will work, but when I run my apex tests, it says something isn't working. Have I written my test code wrong?

Here is the method:

public static void updateAcCountsAndActivities(Set<ID> accountIds){

     //Query all records and related activities
     List<Account> Accounts = [SELECT
   Id,
   TP_NextActivityDate__c,
   TP_NextActivitySubject__c,
         (SELECT Id, Subject, ActivityDate FROM OpenActivities WHERE ActivityDate >= TODAY AND ActivityDate <> NULL order by ActivityDate Desc LIMIT 1)
         FROM Account WHERE ID IN :AccountIds];

     List<Account> updateAccounts = new List<Account>();

     for (Account a : Accounts) {

   //Prepare comparison variables
   String NextActivitySubject = a.TP_NextActivitySubject__c;
   Date NextActivityDate = a.TP_NextActivityDate__c;

   //Compare variables with record
         if (a.OpenActivities.size() > 0) {
             for (OpenActivity act : a.OpenActivities) {
      NextActivityDate = act.ActivityDate;
      NextActivitySubject = act.Subject;
    }
   } else {
    NextActivityDate = null;
    NextActivitySubject = null;
   }

   //Update fields to match variables
         if ( a.TP_NextActivityDate__c != NextActivityDate || a.TP_NextActivitySubject__c != NextActivitySubject){
                 a.TP_NextActivityDate__c = NextActivityDate;
                 a.TP_NextActivitySubject__c = NextActivitySubject;
                 updateAccounts.add(a);
    }
     }

     //Commit the changes
     if(updateAccounts.size()>0) {
         try{
             update updateAccounts;
         }
             catch (Exception e) {
         }
     }
}

Here is a failing test:

public static testMethod void validateAccountCountsAndActivities() {

        //Create Account
  Account ac = new Account(
   Name='Test Account',
   Initial_Lead_Source__c='Cold Call',
   Initial_Lead_Source_Detail__c='Cold Call',
   Account_Type__c='Prospect',
   Account_Status__c='Not Contacted'
   );
  insert ac;

        //Create Contact
        Contact ct = new Contact(
                LastName='Test Contact',
                Email='testcontact@email.com',
                Account= ac
    );
        insert ct;

  // Verify
  ac = [SELECT ID, TP_NextActivityDate__c FROM Account Where ID = :ac.id];
        System.assertEquals(null,ac.TP_NextActivityDate__c);

  //Insert E1
        Event e1 = new Event(
            subject='Event One',
            whoId = ct.id,
            whatId = ac.id,
            startDateTime = Datetime.now().adddays(2),
            endDateTime = Datetime.now().adddays(2)
   );
        insert e1;

  // Verify
  ac = [SELECT ID, TP_NextActivityDate__c FROM Account Where ID = :ac.id];
        System.assertEquals(date.newinstance(e1.EndDateTime.year(),e1.EndDateTime.month(),e1.EndDateTime.day()),ac.TP_NextActivityDate__c);

    }

Error Message:
System.AssertException: Assertion Failed: Expected: 2014-01-24 00:00:00, Actual: null
I have created two triggers, one on the Lead object, the other on a related custom object called 'LeadCompany__c.' When a lead is edited, it should update the related LeadCompany__c object, and when the LeadCompany__c object is updated, it should update all related leads.

My problem is that I am consistently running into the infamous "Attempt to de-reference a null object" error. For example, when I update the Lead "Company" field, it should update the LeadCompany__c.Name field, but it gives the following error: "Attempt to de-reference a null object Trigger.LD_Update_LC: line 82, column 1: []: Trigger.LC_Update_LD: line 93, column 1"

Here is the code for your review. Does anyone see how I can fix this?

//--------------------------------------------------------------------------------------------------------//
// LeadCompany__c Trigger
//--------------------------------------------------------------------------------------------------------//

trigger LC_Update_LD on LeadCompany__c (before insert, before update, after update){

List<Lead> ldList = [SELECT Id, OwnerID, Company, LC_Lead_Company__c, Status, IsConverted FROM Lead WHERE LC_Lead_Company__C in :Trigger.new];
List<Lead> ldUpdate = new List<Lead>();
    List<Database.LeadConvert> leadConversions = new List<database.LeadConvert>();
LeadStatus convertStatus = [SELECT Id, MasterLabel, IsConverted FROM LeadStatus WHERE IsConverted=true limit 1];

Map<String, Integer> status_value = new Map<String, Integer>{
     'Open - Not Contacted' => 2,
     'Working - Contacted' => 3,
     'Working - Initial Meeting Scheduled' => 4,
     'Closed - Qualified' => 5,
     'Closed - Unqualified' =>1,
     null => 0
};

Map<Integer, String> status_name = new Map<Integer, String>{
     2 => 'Open - Not Contacted',
     3 => 'Working - Contacted',
     4 => 'Working - Initial Meeting Scheduled',
     5 => 'Closed - Qualified',
     1 => 'Closed - Unqualified',
     0 => null
};

//Updates Lead Count & Status
if(Trigger.isBefore){
  for (LeadCompany__c lc: Trigger.new){
   lc.Lead_Count__c = 0;
   Integer LC_Stat_Val = status_value.get(lc.Status__c);
   Integer LD_Stat_Vals = 0;
  
   for(Lead ld: ldList){
    if(ld.lc_Lead_Company__c == lc.Id){
     //Add to Lead Count
     Trigger.newMap.get(ld.LC_Lead_Company__c).Lead_Count__c++;
     //Compare Lead Status
     Integer LD_Stat_Value = status_value.get(ld.Status);
     if(LD_Stat_Value > LD_Stat_Vals){
      LD_Stat_Vals = LD_Stat_Value;
     }
    }
   }

   //Set Company Status
   if(LC_Stat_Val != LD_Stat_Vals){
    lc.Status__c = status_name.get(LD_Stat_Vals);
   }
  }
}

if(Trigger.isAfter){
  for (LeadCompany__c lc: Trigger.new) {
         LeadCompany__c oldLC = Trigger.oldMap.get(LC.ID);

            if(LC.Lead_Count__c != null){
    if(lc.ConvertedAccountId__c != null){
                   
                    for(Lead ld: LdList){
      if(ld.isConverted == False){
       Database.LeadConvert ldc = new Database.LeadConvert();
       ldc.setLeadId(ld.id);
       ldc.setAccountId(lc.ConvertedAccountId__c);
       ldc.setDoNotCreateOpportunity(TRUE);
                ldc.setConvertedStatus(convertStatus.MasterLabel);                   
       leadconversions.add(ldc);
      }
     }
    }

          if(LC.OwnerID != oldLC.OwnerID || LC.Name != oldLC.Name) {
              for(Lead ld: LdList){
            // Update Lead Owners
      if(ld.OwnerId != lc.OwnerId){
       ld.OwnerID = LC.OwnerID;
      }
            // Update Lead Company Names
      if(ld.Company != lc.Name){
                      ld.Company = LC.Name;
      }
      ldUpdate.add(ld);      
              }
          }
   }
  }
}

if(leadConversions.size()>0){
        List<Database.LeadConvertResult> results = Database.convertLead(leadConversions);
}
if(ldUpdate.size()>0){
  Update ldUpdate;
}
}

//--------------------------------------------------------------------------------------------------------//
// Lead Trigger
//--------------------------------------------------------------------------------------------------------//

trigger LD_Update_LC on Lead (before insert, before update, after delete, after insert, after update){

//Initialization
Map<Id, LeadCompany__c> updateCompanies = new Map<Id, LeadCompany__c>{};
List<Lead> associateLeads = new List<Lead>{};
List<Lead> convertLeads = new List<Lead>{};

List<Blacklist_Domain__c> Blacklist = [SELECT Name FROM Blacklist_Domain__c];
set<string> Blackset = new set<string>();
for (Blacklist_Domain__c bl: Blacklist){
  Blackset.add(bl.name);
}

Map<String, Integer> status_value = new Map<String, Integer>{
     'Open - Not Contacted' => 2,
     'Working - Contacted' => 3,
     'Working - Initial Meeting Scheduled' => 4,
     'Closed - Qualified' => 5,
     'Closed - Unqualified' =>1,
     null => 0
};

Map<Integer, String> status_name = new Map<Integer, String>{
     2 => 'Open - Not Contacted',
     3 => 'Working - Contacted',
     4 => 'Working - Initial Meeting Scheduled',
     5 => 'Closed - Qualified',
     1 => 'Closed - Unqualified',
     0 => null
};

//Start Trigger
if(Trigger.isBefore){

  //Isolate leads to associate
  if(Trigger.isInsert){
   for (Lead ld: Trigger.new){
    associateLeads.add(ld);
   }
  }
  if(Trigger.isUpdate){
   for (Lead ld: Trigger.new){
    Lead oldLd = Trigger.oldMap.get(ld.Id);
    if(oldLd.LC_Email_Domain__c != Ld.LC_Email_Domain__c){
     associateLeads.add(ld);
     if(oldLd.LC_Lead_Company__c != null){
      updateCompanies.put(oldLd.LC_Lead_Company__c, new LeadCompany__c(Id=oldLd.LC_Lead_Company__c));
     }
    }
   }
  }
}

if(Trigger.isAfter){

  //Update Company after Lead delete
  if(Trigger.isDelete){
   for (Lead ld: Trigger.old){
    if(ld.LC_Lead_Company__c != null){
     updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
    }
   }
  }

  if(Trigger.isUpdate){
   for (Lead ld: Trigger.new){
    //Convert all Company leads
    if(Ld.IsConverted == True && ld.LC_Lead_Company__c != null){
     ld.LC_Lead_Company__r.ConvertedAccountId__c = ld.ConvertedAccountId;
     updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
    }
    //Check for Lead value changes
    else {
     Lead oldLd = Trigger.oldMap.get(Ld.ID);
     //Set LC OwnerId
     if(Ld.OwnerID != oldLd.OwnerID){
      ld.LC_Lead_Company__r.OwnerId = Ld.OwnerId;
      updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
     }
     //Set LC Name
     if(Ld.Company != oldLd.Company){
      ld.LC_Lead_Company__r.Name = Ld.Company;
      updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
     }
     //Set LC Status
     if(Ld.Status != oldLd.Status){
      if(Ld.Status != Ld.LC_Status__c){
       Integer LC_Stat_Value = status_value.get(ld.LC_Lead_Company__r.Status__c);
       Integer LD_Stat_Value = status_value.get(ld.Status);

          if(LD_Stat_Value > LC_Stat_Value){
        ld.LC_Lead_Company__r.Status__c = status_name.get(LD_Stat_Value);
        updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
          }
      }
     }
    }
   }
  }
}

//Perform Updates

//Associate Leads to Companies
if(associateLeads.size()>0){
  for (Lead ld: associateLeads){
   //Validate Email
   if (ld.LC_Email_Domain__c != null && Blackset.contains(ld.LC_Email_Domain__c) == FALSE){
    //Search for existing company
    List<LeadCompany__c> lcMatch = [SELECT Id, OwnerId FROM LeadCompany__c WHERE Domain__c = :ld.LC_Email_Domain__c];
    // If existing, associate lead
    if (lcMatch.size() >0) {
     for( LeadCompany__c lc :lcMatch){
      // Associate Lead to Company
      ld.LC_Lead_Company__c = lc.Id;
      // Change Lead Owner to Company Owner
      ld.OwnerID = lc.ownerid;
      updateCompanies.put(lc.Id, new LeadCompany__C(Id=lc.Id));
     }
    }
    // If no existing, create new
    else {
     // Create new company
        LeadCompany__c nlc = new LeadCompany__c (
            Domain__c = ld.LC_Email_Domain__c,
            Name = ld.Company,
            OwnerId = ld.OwnerId,
            Status__c = ld.Status
        );
        insert nlc;

     // Associate new lead to new company
        ld.LC_Lead_Company__c = nlc.id;
     updateCompanies.put(nlc.Id, new LeadCompany__c(Id=nlc.Id));
    }
   }
   //Remove association
   else {
    ld.LC_Lead_Company__c = null;
   }
  }
}

//Trigger New & Old Company Updates (Owner, Name, Count Status etc)
if(updateCompanies.size()>0){
  Update updateCompanies.values();
}
}

Working on a trigger to update the lead object. The field displays a count of activities completed within 30 days from the Lead record's CreatedDate.

 

I can't find a clean way to limit my SOQL subquery based on the parent object's CreatedDate field.

 

Any ideas?

 

    public static String ldPrefix =  Lead.sObjectType.getDescribe().getKeyPrefix();
    public static void updateLeadCounts30days(Set<ID> leadIds) {

        List<Lead> Leads = [SELECT ID, CreatedDate, TP_First_30_Days__c, (SELECT ID, ActivityDate FROM Tasks), (SELECT ID, ActivityDate FROM Events) FROM Lead WHERE ID IN :leadIds];
        List<Lead> updateLeads = new List<Lead>();

        for (Lead l : Leads) {

		Date InitDate = l.CreatedDate;
		Date InitDate30 = l.CreatedDate + 30;

		Integer ThirtyTaskCount = [SELECT COUNT() FROM Tasks WHERE ActivityDate <= :InitDate30];            	
		Integer ThirtyEventCount = [SELECT COUNT() FROM Events WHERE ActivityDate <= :InitDate30];
		Integer FirstThirtyDays = ThirtyTaskCount + ThirtyEventCount;

		if (l.TP_First_30_Days__c != FirstThirtyDays) {
			l.TP_First_30_Days__c = FirstThirtyDays;
		}	
		updateLeads.add(l);
	}

 

I attempted to save an apex test class in our sandbox, but received the following error message:
 
An unexpected error has occurred. 1453659855-92905 (-2090026019) for deploymentId=1dre0000001FXv9AAG If this persists, please contact customer support.

Attempted Solutions: I found a similar issue, but I am unable to test their suggestion of refreshing my sandbox:
https://developer.salesforce.com/forums/?id=906F0000000AXfsIAG

Has anyone else come across this and found a solution other than wiping their sandbox?
Use Case:
When a user creates a case, an email response is delivered to a customer. This email should complete a "first response" milestone.

Technical Issue:
Trigger logic on the Case or EmailMessage objects cannot access CaseMilestones because they are created later asynchronously. I tried @Future calls, but CaseMilestone records still do not exist. A combo of Batch Apex Jobs scheduled from Triggers will successfully update CaseMilestones, but this is far from ideal.

Has anyone come across a solution to the need for immediate access to CaseMilestone records? (Some other use cases come to mind: Auto-complete "resolution" milestone if case is closed on create.)
 
I'm unable to open logs in the developer console. Every time I try to open a log, I receive the following error message:

Unable to Access Page
You are missing information needed by the page you have attempted to access. If you believe this is an error, please refresh your screen. If the error persists, please report it to our Customer Support team and provide the URL of the page you were requesting as well as any other related information. 

Error message screenshot

This issue is similar to this forum post (https://developer.salesforce.com/forums?id=906F0000000AtUNIA0), but I have attempted its solution and receive the same results.

Logs aren't showing in the "Logs" tab.
Double-clicking test logs from the "tests" tab produces the above error message.
 
Goal:
For cases created from Salesforce for Outlook (i.e. non-service personnel), we want to track entitlements based on when an email was received, not when it was logged into Salesforce.

Sample Use Case:
A sales rep receives an email from a customer about an issue. They create a case from the email, but the case is logged 24 hours after it was received. Salesforce shows the email as received on the date/time the sales rep enters it into salesforce, not when they received the email. Furthermore, there is no way to extract the original date/time of when it entered their inbox.

Attempts:
  • "Create Cases" Button in Salesforce for Outlook (Sets email date/time to date created in Salesforce, not date received)
  • Global "New Case" Action in Salesforce for Outlook (Brings email body, but not header, into case description)
  • "Add Email" button on Case listed in Salesforce for Outlook (Again, timestamp is on moment created and only places email body in description, not timestamp)
Anyone have a suggestion (apart from voting for the idea)?
 
When I make a chatter content post via desktop, Process Builder can access that post's FeedItem.Id field.
However, when I make the same post via mobile, Process Builder is unable to access the FeedItem.Id field.

Create flow in Process Builder:
  • Object: FeedItem
  • Logic: FeedItem.Type = ContentPost
  • Result: Post to user's wall in Chatter containing FeedItem.Id
Test On Desktop:
  • Use “file” publisher action on case feed to upload a document and comment.
  • Process makes post on user's wall with FeedItem.Id
Test On Mobile:
  • Use “file” publisher action on case to upload a document and comment.
  • Process does not make post on user's wall because it can't access FeedItem.Id.
Does anyone know what's happening here and how I can get consistent behavior between mobile and desktop?
I am building an email with Messaging.SingleEmailMessage. The email should include TXT, HTML, and ICS versions and be received by an Outlook recipient as a calendar invite (not as an email with an attachment). The key is in setting the ICS attachment as an option in the same "content-type: multipart/alternative" section as the TXT and HTML versions. However, when I build the email with setPlainTextBody, setHtmlBody, and setFileAttachments, it sets the ICS attachment in its own "content-type" section.

How can I write my code to bring the .ICS file into the "Content-type: multipart/alternative" block with the TXT & HTML?

My current code:
public static void sendEventInviteICS(String bodyTXT, String bodyHTML, String subject, String fromAddress, String displayName, List<String> toAddress, List<String> ccAddress){
    //Create Message
    Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
    msg.setReplyTo(fromAddress);
    msg.setSenderDisplayName(displayName);
    msg.setToAddresses(toAddress);
    msg.setCcAddresses(ccAddress);
    msg.setSubject(subject);
    //Create TXT Version
    msg.setPlainTextBody(bodyTXT);
    //Create HTML Version
    msg.setHTMLBody(bodyHTML);
    //Create ICS Attachment
    Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
    efa.setFileName('Meeting Invite.ics');
    efa.setContentType('text/calendar');
    Blob b = buildICSAttachment();
    efa.setBody(b);
    msg.setFileAttachments(new Messaging.EmailFileAttachment[]{efa});
    //Send the Email
    Messaging.sendEmail(new Messaging.SingleEmailMessage[]{msg});
}
MIME result from current code:
Date: Tue, 9 Dec 2014 21:16:26 +0000
From: Isaac Lewis <ilewis@afs.net>
Reply-To: <djillumine@gmail.com>
To: "ilewis@afs.net" <ilewis@afs.net>
Subject: Sandbox: This is the subject
MIME-Version: 1.0
Content-type: multipart/mixed;
	boundary="B_3500983009_1157947"

> This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

--B_3500983009_1157947
Content-type: multipart/alternative;
	boundary="B_3500983009_1123381"


--B_3500983009_1123381
Content-type: text/plain;
	charset="US-ASCII"
Content-transfer-encoding: 7bit

This is the text body


--B_3500983009_1123381
Content-type: text/html;
	charset="US-ASCII"
Content-transfer-encoding: quoted-printable

<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8">
</head>
<body>
<i>This is the html body</i>
</body>
</html>


--B_3500983009_1123381--


--B_3500983009_1157947
Content-type: text/calendar; name="Attachment Name.ics"
Content-disposition: attachment;
	filename="Attachment Name.ics"
Content-transfer-encoding: base64

QkVHSU46VkNBTEVOREFSDQpNRVRIT0Q6UkVRVUVTVA0KUFJPRElEOk1pY3Jvc29mdCBFeGNo=

--B_3500983009_1157947--
Desired MIME Result (boundaries around ICS have been moved to be part of the "Content-type: multipart/alternative" block):
Date: Tue, 9 Dec 2014 21:16:26 +0000
From: Isaac Lewis <ilewis@afs.net>
Reply-To: <djillumine@gmail.com>
To: "ilewis@afs.net" <ilewis@afs.net>
Subject: Sandbox: This is the subject
MIME-Version: 1.0
Content-type: multipart/mixed;
	boundary="B_3500983009_1157947"

> This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

--B_3500983009_1157947
Content-type: multipart/alternative;
	boundary="B_3500983009_1123381"


--B_3500983009_1123381
Content-type: text/plain;
	charset="US-ASCII"
Content-transfer-encoding: 7bit

This is the text body


--B_3500983009_1123381
Content-type: text/html;
	charset="US-ASCII"
Content-transfer-encoding: quoted-printable

<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8">
</head>
<body>
<i>This is the html body</i>
</body>
</html>

--B_3500983009_1123381
Content-type: text/calendar; name="Attachment Name.ics"
Content-disposition: attachment;
	filename="Attachment Name.ics"
Content-transfer-encoding: base64

QkVHSU46VkNBTEVOREFSDQpNRVRIT0Q6UkVRVUVTVA0KUFJPRElEOk1pY3Jvc29mdCBFeGNo=

--B_3500983009_1123381--

--B_3500983009_1157947--




 

I'm trying to prevent multiple SOQL queries in my method by creating a static list outside of the method.
The list is pulling from custom settings, so they should be static when the class runs.
Unfortunately, when I run the test for this class, the debug log shows nothing.
Am I putting this list in the wrong place?

Class
public class modeRanges{

    public static List<ModeRange__c> ModeRanges = [SELECT Mode_Type__c, Spend_Picklist_Value__c, Volume_Picklist_Value__c FROM ModeRange__c];

    public static void setSpendRangeFromVolumeRange(List<Mode__c> Modes){
	System.debug('ModeRanges: ' + ModeRanges);
        for(Mode__c m :Modes){
            for(ModeRange__c r: ModeRanges){
                if(m.Type__c == r.Mode_Type__c && m.Est_Volume__c == r.Volume_Picklist_Value__c){
                    m.Est_Spend__c = r.Spend_Picklist_Value__c;
                }
            }
        }
    }    
}

Debug Log
15:45:01:042 USER_DEBUG [12]|DEBUG|ModeRanges: ()

I have tested this trigger multiple times in the Sandbox, and it produces the proper results. However, when I deploy the changes to production, it comes out with different results. Does anyone know how I could trace what is producing the different results in production? I checked workflows and validation rules but couldn't find anything.
Is it possible to keep an opportunity team in place when ownership of an account or opportunity takes place WITHOUT checking the box? Would any of you have a trigger or suggestion for this kind of function?

I am building a trigger to automatically associate a custom Account child object with a custom Opportunity child object. My trigger works fine and tests perfectly, except when I went to upload a bunch of records to the new object, I received the following error on every item:

System.LimitException: Apex CPU time limit exceeded

I found a helpful article here:
http://salesforce.stackexchange.com/questions/22223/how-to-code-more-efficient-to-avoid-apex-cpu-time-limit-exceeded

But I'm still not sure what I'm doing wrong. Does anyone have any ideas?

Here is the trigger code:

<pre>
trigger associateOppChildtoAccChild on OppChild__c (before insert, before update) {

    Set<Id> OppSet = new Set<Id>();
    for(OppChild__c OppChild :Trigger.new){
        OppSet.add(OppChild.Opportunity__c);
    }
   
    Map<ID,ID> OPP_ACC = new Map<ID,ID>();
    Set<Id> AccSet = new Set<Id>();
    for(Opportunity OPP:[SELECT Id, AccountId from Opportunity where Id in :OppSet]){
        OPP_ACC.put(OPP.Id, OPP.AccountId);
        AccSet.add(OPP.AccountId);       
    }

    Map<ID,ID> ACC_OppChild = new Map<ID,ID>();
    for(OppChild__c OppChild :Trigger.new){
        for(ID OPP :OPP_ACC.keyset()){
            if(OPP == OppChild.Opportunity__c){
                ACC_OppChild.put(OPP_ACC.get(OPP), OppChild.Id);
            }
        }
    }
   
    List<AccChild__c> AccChildList = [SELECT Id, Account__c, Type__c, Annual_Spend__c, Number_of_Shipment_Transactions__c FROM AccChild__c WHERE Account__c in :AccSet];
   
    for(OppChild__c OppChild :Trigger.new){
        for(AccChild__c m: AccChildList){
            if(m.Type__c == OppChild.AccChild_Type__c){
                for(ID ACC :ACC_OppChild.keyset()){
                    if(ACC == m.Account__c){
                        OppChild.AccChild__c = m.Id;
                        System.debug('OppChild AccChild = ' + OppChild.AccChild__c);
                        OppChild.Annual_Spend__c = m.Annual_Spend__c;
                        OppChild.Number_of_Shipment_Transactions__c = m.Number_of_Shipment_Transactions__c;
                    } else {
                        OppChild.adderror(OppChild.AccChild_Type__c + ' AccChild must exist on Account to add OppChild');
                    }
                }
            }
        }
    }  
}
</pre>

I run the tests and my set and map both come back null. Can anyone spot what I'm missing here?

<pre>
trigger associatePMRtoMode on PMR__c (before insert, before update) {

    Set<ID> AccountIds = new Set<ID>();
    Map<ID,ID> ACC_PMR = new Map<ID,ID>();
   
    for (PMR__c PMR :Trigger.new){
        AccountIds.add(PMR.Opportunity__r.AccountId);
        ACC_PMR.put(PMR.Opportunity__r.AccountId, PMR.Id);
    }

    System.debug('AccountIds = ' + AccountIds);
    System.debug('ACC_PMR = ' + ACC_PMR);
}
</pre>

I have written a piece of code to create several custom objects when a lead converts. It works, but I don't know how to test the code. How do I write the queries to confirm the custom object was created automatically?

Here is the trigger:

trigger createModefromLead on Lead (after update) {

    List<Mode__c> UpdateModes = new List<Mode__c>();
    List<Mode__c> InsertModes = new List<Mode__c>();
    Set<Id> AccountIds = new Set<ID>();
   
    for (Lead l :Trigger.new){
        if(l.IsConverted){
            AccountIds.add(l.ConvertedAccountId);
        }
    }

List<Mode__c> ModeList = [SELECT Id, Account__c, Name, Mode_Type__c, Est_Shipping_Spend__c, Est_Shipping_Volume__c FROM Mode__c WHERE Account__c in :AccountIds];

    for (Lead l :Trigger.new){
        if(l.IsConverted){

   //Parcel Mode
            if(l.HasParcel__c == TRUE){
                Set<Id> ParcelModeCount = new Set<Id>();
                for (Mode__c m: ModeList){
                    if(m.Account__c == l.ConvertedAccountId && m.Mode_Type__c =='Parcel'){
                     m.Est_Shipping_Spend__c = l.Spend_Annual_Parcel__c;
                        m.Est_Shipping_Volume__c = l.Count_Daily_Parcel__c;
                        ParcelModeCount.add(m.Id);
                        UpdateModes.add(m);
                    }
                }
                if(ParcelModeCount.size() == 0){
                    Mode__c Parcel = new Mode__c(
                        Name = 'Parcel',
                        Mode_Type__c = 'Parcel',
                        Account__c = l.ConvertedAccountId,
                        Est_Shipping_Spend__c = l.Spend_Annual_Parcel__c,
                        Est_Shipping_Volume__c = l.Count_Daily_Parcel__c);
                    InsertModes.add(Parcel);
                }
            }
        }
        if(UpdateModes.size()>0){
            Update Updatemodes;
        }
        if(InsertModes.size()>0){
            Insert InsertModes;
        }
}  
}

And Here is the start of the test:
 
@isTest

private class createModefromLead_TestClass{

    public static testmethod void Convert_NewAcc_CreateMode(){

        //Insert Lead
        Lead LD1 = new Lead(
            LastName = 'LD1',
            Email = 'LD1@LCA.com',
            Company = 'LCA',
            Status = 'Closed - Qualified'
        );
        Insert LD1;
       
        //Convert Lead
        Database.LeadConvert lc = new database.LeadConvert();
        lc.setLeadId(LD1.id);
        lc.setConvertedStatus('Closed - Qualified');
       
        //Verify LD1 Convert
        Database.LeadConvertResult lcr = Database.convertLead(lc);
        System.assert(lcr.isSuccess());

        //Verify LD1 Creates Mode object on Account
       
    }
}


 
I am adding a trigger to default a Contact owner to the Account owner. It works fine and passes the test I wrote for it. HOWEVER, it fails a test from another piece of apex, telling me:

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, reassignCtOwnerToAcOwner: data changed by trigger for field Owner ID: owner cannot be blank: []

Here is the trigger I'm trying to deploy:

trigger reassignCtOwnerToAcOwner on Contact (before insert, before update) {

    List<Id> accountIds = new List<Id>();
    Map<Id, Id> accountOwnerIdMap = new Map<Id, Id>();

    // all the accounts whose owner ids to look up
    for ( Contact c : Trigger.new ) {
        accountIds.add( c.accountId );
    }
   
    // look up each account owner id
    for ( Account acct : [ SELECT id, ownerId FROM account WHERE id IN :accountIds ] ) {
        accountOwnerIdMap.put( acct.id, acct.ownerId );
    }
   
    // change contact owner to its account owner
    for ( Contact c : Trigger.new ) {
        c.ownerId = accountOwnerIdMap.get( c.accountId );
    }
}

Here is the test class for the OTHER trigger that fails when I try to insert a contact:

public static testMethod void validateContactCountsAndActivities() {

        //Create Account
  Account ac = new Account(
   Name='Test Account',
   Initial_Lead_Source__c='Cold Call',
   Initial_Lead_Source_Detail__c='Cold Call',
   Account_Type__c='Prospect',
   Account_Status__c='Not Contacted'   );
  insert ac;

        //Create Contact
        Contact ct = new Contact(
                LastName='Test Contact',
                Email='testcontact@email.com',
                Account= ac);
        insert ct;




I am working on an apex trigger/class to display the next activity subject & date on the account object. The code works fine, and a manual test will work, but when I run my apex tests, it says something isn't working. Have I written my test code wrong?

Here is the method:

public static void updateAcCountsAndActivities(Set<ID> accountIds){

     //Query all records and related activities
     List<Account> Accounts = [SELECT
   Id,
   TP_NextActivityDate__c,
   TP_NextActivitySubject__c,
         (SELECT Id, Subject, ActivityDate FROM OpenActivities WHERE ActivityDate >= TODAY AND ActivityDate <> NULL order by ActivityDate Desc LIMIT 1)
         FROM Account WHERE ID IN :AccountIds];

     List<Account> updateAccounts = new List<Account>();

     for (Account a : Accounts) {

   //Prepare comparison variables
   String NextActivitySubject = a.TP_NextActivitySubject__c;
   Date NextActivityDate = a.TP_NextActivityDate__c;

   //Compare variables with record
         if (a.OpenActivities.size() > 0) {
             for (OpenActivity act : a.OpenActivities) {
      NextActivityDate = act.ActivityDate;
      NextActivitySubject = act.Subject;
    }
   } else {
    NextActivityDate = null;
    NextActivitySubject = null;
   }

   //Update fields to match variables
         if ( a.TP_NextActivityDate__c != NextActivityDate || a.TP_NextActivitySubject__c != NextActivitySubject){
                 a.TP_NextActivityDate__c = NextActivityDate;
                 a.TP_NextActivitySubject__c = NextActivitySubject;
                 updateAccounts.add(a);
    }
     }

     //Commit the changes
     if(updateAccounts.size()>0) {
         try{
             update updateAccounts;
         }
             catch (Exception e) {
         }
     }
}

Here is a failing test:

public static testMethod void validateAccountCountsAndActivities() {

        //Create Account
  Account ac = new Account(
   Name='Test Account',
   Initial_Lead_Source__c='Cold Call',
   Initial_Lead_Source_Detail__c='Cold Call',
   Account_Type__c='Prospect',
   Account_Status__c='Not Contacted'
   );
  insert ac;

        //Create Contact
        Contact ct = new Contact(
                LastName='Test Contact',
                Email='testcontact@email.com',
                Account= ac
    );
        insert ct;

  // Verify
  ac = [SELECT ID, TP_NextActivityDate__c FROM Account Where ID = :ac.id];
        System.assertEquals(null,ac.TP_NextActivityDate__c);

  //Insert E1
        Event e1 = new Event(
            subject='Event One',
            whoId = ct.id,
            whatId = ac.id,
            startDateTime = Datetime.now().adddays(2),
            endDateTime = Datetime.now().adddays(2)
   );
        insert e1;

  // Verify
  ac = [SELECT ID, TP_NextActivityDate__c FROM Account Where ID = :ac.id];
        System.assertEquals(date.newinstance(e1.EndDateTime.year(),e1.EndDateTime.month(),e1.EndDateTime.day()),ac.TP_NextActivityDate__c);

    }

Error Message:
System.AssertException: Assertion Failed: Expected: 2014-01-24 00:00:00, Actual: null
I have created two triggers, one on the Lead object, the other on a related custom object called 'LeadCompany__c.' When a lead is edited, it should update the related LeadCompany__c object, and when the LeadCompany__c object is updated, it should update all related leads.

My problem is that I am consistently running into the infamous "Attempt to de-reference a null object" error. For example, when I update the Lead "Company" field, it should update the LeadCompany__c.Name field, but it gives the following error: "Attempt to de-reference a null object Trigger.LD_Update_LC: line 82, column 1: []: Trigger.LC_Update_LD: line 93, column 1"

Here is the code for your review. Does anyone see how I can fix this?

//--------------------------------------------------------------------------------------------------------//
// LeadCompany__c Trigger
//--------------------------------------------------------------------------------------------------------//

trigger LC_Update_LD on LeadCompany__c (before insert, before update, after update){

List<Lead> ldList = [SELECT Id, OwnerID, Company, LC_Lead_Company__c, Status, IsConverted FROM Lead WHERE LC_Lead_Company__C in :Trigger.new];
List<Lead> ldUpdate = new List<Lead>();
    List<Database.LeadConvert> leadConversions = new List<database.LeadConvert>();
LeadStatus convertStatus = [SELECT Id, MasterLabel, IsConverted FROM LeadStatus WHERE IsConverted=true limit 1];

Map<String, Integer> status_value = new Map<String, Integer>{
     'Open - Not Contacted' => 2,
     'Working - Contacted' => 3,
     'Working - Initial Meeting Scheduled' => 4,
     'Closed - Qualified' => 5,
     'Closed - Unqualified' =>1,
     null => 0
};

Map<Integer, String> status_name = new Map<Integer, String>{
     2 => 'Open - Not Contacted',
     3 => 'Working - Contacted',
     4 => 'Working - Initial Meeting Scheduled',
     5 => 'Closed - Qualified',
     1 => 'Closed - Unqualified',
     0 => null
};

//Updates Lead Count & Status
if(Trigger.isBefore){
  for (LeadCompany__c lc: Trigger.new){
   lc.Lead_Count__c = 0;
   Integer LC_Stat_Val = status_value.get(lc.Status__c);
   Integer LD_Stat_Vals = 0;
  
   for(Lead ld: ldList){
    if(ld.lc_Lead_Company__c == lc.Id){
     //Add to Lead Count
     Trigger.newMap.get(ld.LC_Lead_Company__c).Lead_Count__c++;
     //Compare Lead Status
     Integer LD_Stat_Value = status_value.get(ld.Status);
     if(LD_Stat_Value > LD_Stat_Vals){
      LD_Stat_Vals = LD_Stat_Value;
     }
    }
   }

   //Set Company Status
   if(LC_Stat_Val != LD_Stat_Vals){
    lc.Status__c = status_name.get(LD_Stat_Vals);
   }
  }
}

if(Trigger.isAfter){
  for (LeadCompany__c lc: Trigger.new) {
         LeadCompany__c oldLC = Trigger.oldMap.get(LC.ID);

            if(LC.Lead_Count__c != null){
    if(lc.ConvertedAccountId__c != null){
                   
                    for(Lead ld: LdList){
      if(ld.isConverted == False){
       Database.LeadConvert ldc = new Database.LeadConvert();
       ldc.setLeadId(ld.id);
       ldc.setAccountId(lc.ConvertedAccountId__c);
       ldc.setDoNotCreateOpportunity(TRUE);
                ldc.setConvertedStatus(convertStatus.MasterLabel);                   
       leadconversions.add(ldc);
      }
     }
    }

          if(LC.OwnerID != oldLC.OwnerID || LC.Name != oldLC.Name) {
              for(Lead ld: LdList){
            // Update Lead Owners
      if(ld.OwnerId != lc.OwnerId){
       ld.OwnerID = LC.OwnerID;
      }
            // Update Lead Company Names
      if(ld.Company != lc.Name){
                      ld.Company = LC.Name;
      }
      ldUpdate.add(ld);      
              }
          }
   }
  }
}

if(leadConversions.size()>0){
        List<Database.LeadConvertResult> results = Database.convertLead(leadConversions);
}
if(ldUpdate.size()>0){
  Update ldUpdate;
}
}

//--------------------------------------------------------------------------------------------------------//
// Lead Trigger
//--------------------------------------------------------------------------------------------------------//

trigger LD_Update_LC on Lead (before insert, before update, after delete, after insert, after update){

//Initialization
Map<Id, LeadCompany__c> updateCompanies = new Map<Id, LeadCompany__c>{};
List<Lead> associateLeads = new List<Lead>{};
List<Lead> convertLeads = new List<Lead>{};

List<Blacklist_Domain__c> Blacklist = [SELECT Name FROM Blacklist_Domain__c];
set<string> Blackset = new set<string>();
for (Blacklist_Domain__c bl: Blacklist){
  Blackset.add(bl.name);
}

Map<String, Integer> status_value = new Map<String, Integer>{
     'Open - Not Contacted' => 2,
     'Working - Contacted' => 3,
     'Working - Initial Meeting Scheduled' => 4,
     'Closed - Qualified' => 5,
     'Closed - Unqualified' =>1,
     null => 0
};

Map<Integer, String> status_name = new Map<Integer, String>{
     2 => 'Open - Not Contacted',
     3 => 'Working - Contacted',
     4 => 'Working - Initial Meeting Scheduled',
     5 => 'Closed - Qualified',
     1 => 'Closed - Unqualified',
     0 => null
};

//Start Trigger
if(Trigger.isBefore){

  //Isolate leads to associate
  if(Trigger.isInsert){
   for (Lead ld: Trigger.new){
    associateLeads.add(ld);
   }
  }
  if(Trigger.isUpdate){
   for (Lead ld: Trigger.new){
    Lead oldLd = Trigger.oldMap.get(ld.Id);
    if(oldLd.LC_Email_Domain__c != Ld.LC_Email_Domain__c){
     associateLeads.add(ld);
     if(oldLd.LC_Lead_Company__c != null){
      updateCompanies.put(oldLd.LC_Lead_Company__c, new LeadCompany__c(Id=oldLd.LC_Lead_Company__c));
     }
    }
   }
  }
}

if(Trigger.isAfter){

  //Update Company after Lead delete
  if(Trigger.isDelete){
   for (Lead ld: Trigger.old){
    if(ld.LC_Lead_Company__c != null){
     updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
    }
   }
  }

  if(Trigger.isUpdate){
   for (Lead ld: Trigger.new){
    //Convert all Company leads
    if(Ld.IsConverted == True && ld.LC_Lead_Company__c != null){
     ld.LC_Lead_Company__r.ConvertedAccountId__c = ld.ConvertedAccountId;
     updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
    }
    //Check for Lead value changes
    else {
     Lead oldLd = Trigger.oldMap.get(Ld.ID);
     //Set LC OwnerId
     if(Ld.OwnerID != oldLd.OwnerID){
      ld.LC_Lead_Company__r.OwnerId = Ld.OwnerId;
      updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
     }
     //Set LC Name
     if(Ld.Company != oldLd.Company){
      ld.LC_Lead_Company__r.Name = Ld.Company;
      updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
     }
     //Set LC Status
     if(Ld.Status != oldLd.Status){
      if(Ld.Status != Ld.LC_Status__c){
       Integer LC_Stat_Value = status_value.get(ld.LC_Lead_Company__r.Status__c);
       Integer LD_Stat_Value = status_value.get(ld.Status);

          if(LD_Stat_Value > LC_Stat_Value){
        ld.LC_Lead_Company__r.Status__c = status_name.get(LD_Stat_Value);
        updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
          }
      }
     }
    }
   }
  }
}

//Perform Updates

//Associate Leads to Companies
if(associateLeads.size()>0){
  for (Lead ld: associateLeads){
   //Validate Email
   if (ld.LC_Email_Domain__c != null && Blackset.contains(ld.LC_Email_Domain__c) == FALSE){
    //Search for existing company
    List<LeadCompany__c> lcMatch = [SELECT Id, OwnerId FROM LeadCompany__c WHERE Domain__c = :ld.LC_Email_Domain__c];
    // If existing, associate lead
    if (lcMatch.size() >0) {
     for( LeadCompany__c lc :lcMatch){
      // Associate Lead to Company
      ld.LC_Lead_Company__c = lc.Id;
      // Change Lead Owner to Company Owner
      ld.OwnerID = lc.ownerid;
      updateCompanies.put(lc.Id, new LeadCompany__C(Id=lc.Id));
     }
    }
    // If no existing, create new
    else {
     // Create new company
        LeadCompany__c nlc = new LeadCompany__c (
            Domain__c = ld.LC_Email_Domain__c,
            Name = ld.Company,
            OwnerId = ld.OwnerId,
            Status__c = ld.Status
        );
        insert nlc;

     // Associate new lead to new company
        ld.LC_Lead_Company__c = nlc.id;
     updateCompanies.put(nlc.Id, new LeadCompany__c(Id=nlc.Id));
    }
   }
   //Remove association
   else {
    ld.LC_Lead_Company__c = null;
   }
  }
}

//Trigger New & Old Company Updates (Owner, Name, Count Status etc)
if(updateCompanies.size()>0){
  Update updateCompanies.values();
}
}

Working on a trigger to update the lead object. The field displays a count of activities completed within 30 days from the Lead record's CreatedDate.

 

I can't find a clean way to limit my SOQL subquery based on the parent object's CreatedDate field.

 

Any ideas?

 

    public static String ldPrefix =  Lead.sObjectType.getDescribe().getKeyPrefix();
    public static void updateLeadCounts30days(Set<ID> leadIds) {

        List<Lead> Leads = [SELECT ID, CreatedDate, TP_First_30_Days__c, (SELECT ID, ActivityDate FROM Tasks), (SELECT ID, ActivityDate FROM Events) FROM Lead WHERE ID IN :leadIds];
        List<Lead> updateLeads = new List<Lead>();

        for (Lead l : Leads) {

		Date InitDate = l.CreatedDate;
		Date InitDate30 = l.CreatedDate + 30;

		Integer ThirtyTaskCount = [SELECT COUNT() FROM Tasks WHERE ActivityDate <= :InitDate30];            	
		Integer ThirtyEventCount = [SELECT COUNT() FROM Events WHERE ActivityDate <= :InitDate30];
		Integer FirstThirtyDays = ThirtyTaskCount + ThirtyEventCount;

		if (l.TP_First_30_Days__c != FirstThirtyDays) {
			l.TP_First_30_Days__c = FirstThirtyDays;
		}	
		updateLeads.add(l);
	}

 

I attempted to save an apex test class in our sandbox, but received the following error message:
 
An unexpected error has occurred. 1453659855-92905 (-2090026019) for deploymentId=1dre0000001FXv9AAG If this persists, please contact customer support.

Attempted Solutions: I found a similar issue, but I am unable to test their suggestion of refreshing my sandbox:
https://developer.salesforce.com/forums/?id=906F0000000AXfsIAG

Has anyone else come across this and found a solution other than wiping their sandbox?
I'm unable to open logs in the developer console. Every time I try to open a log, I receive the following error message:

Unable to Access Page
You are missing information needed by the page you have attempted to access. If you believe this is an error, please refresh your screen. If the error persists, please report it to our Customer Support team and provide the URL of the page you were requesting as well as any other related information. 

Error message screenshot

This issue is similar to this forum post (https://developer.salesforce.com/forums?id=906F0000000AtUNIA0), but I have attempted its solution and receive the same results.

Logs aren't showing in the "Logs" tab.
Double-clicking test logs from the "tests" tab produces the above error message.
 
Hi

I'm trying to write a trigger for Case that will reopen or uncomplete the Final Milestone in the Entitlement Process for that Case. I have run up against getting an error
FIELD_INTEGRITY_EXCEPTION, You can’t change the completion date on a case milestone that’s already exited an entitlement process.
I am using a method expanded from the milestoneUtils code found here:
https://developer.salesforce.com/page/Case_Milestones_Utilities_Class

I tried adding @future against the method and while the error no longer occurs it does not uncomplete the Milestone going from Status 'Closed' to 'Open' the first time around.
However if I close the Case and then reopen subsequent times, it then does work.

Can anyone offer any insight into how I may correctly use the @future annotation so that it would work first time? Or any other way of dealing with this sequence of events?

This is my Trigger:
trigger openMilestoneOnReopenCase on Case (after update) {

    String finalMilestone = 'Solution Time';
    DateTime CompletionDate = NULL;
    List<Id> cases = new List<Id>();

    for(Case c:Trigger.new){

        //Get the prior update Case states
        Case oldCaseState = Trigger.oldMap.get(c.Id);

        // Checking if this is a Case being reopend from Closed
        if(c.Status == 'Open' && oldCaseState.Status == 'Closed'){
        
            // Get the Case Milestone List
            List<CaseMilestone> caseMilestones = [Select MilestoneTypeId, IsCompleted from CaseMilestone cm where cm.MilestoneType.Name=:finalMilestone AND cm.CaseId=:c.Id];
            
            //Iterate the Case Milestone List
            for(CaseMilestone caseMilestone:caseMilestones){
                
                //Check the Solution Time state isCompleted and add the Case to the Case List
                if(caseMilestone.isCompleted == true){
                    cases.add(c.Id);
                }
            }

            // Call the milestoneUtils Method
            if(!cases.isEmpty()){
                milestoneUtils.reopenMilestone(cases, finalMilestone, completionDate);
            }
        
        }
    }
}
This is the milestonesUtil Class I am calling the method from:
public class milestoneUtils {
    @future
    public static void reopenMilestone(List<Id> caseIds, String milestoneName, DateTime complDate) {
        System.debug('ASPD DEBUG: milestoneUtils: DateTime for completeMilestone is ' + string.valueOfGMT(complDate));

        List<CaseMilestone> cmsToUpdate = [select Id, completionDate from CaseMilestone cm where caseId in :caseIds and cm.MilestoneType.Name=:milestoneName and completionDate != null limit 1];
        if (cmsToUpdate.isEmpty() == false){
            for (CaseMilestone cm : cmsToUpdate){
                cm.completionDate = complDate;
            }
            update cmsToUpdate;
        }
    }
}

Thanks
Patrick
When I make a chatter content post via desktop, Process Builder can access that post's FeedItem.Id field.
However, when I make the same post via mobile, Process Builder is unable to access the FeedItem.Id field.

Create flow in Process Builder:
  • Object: FeedItem
  • Logic: FeedItem.Type = ContentPost
  • Result: Post to user's wall in Chatter containing FeedItem.Id
Test On Desktop:
  • Use “file” publisher action on case feed to upload a document and comment.
  • Process makes post on user's wall with FeedItem.Id
Test On Mobile:
  • Use “file” publisher action on case to upload a document and comment.
  • Process does not make post on user's wall because it can't access FeedItem.Id.
Does anyone know what's happening here and how I can get consistent behavior between mobile and desktop?
I am building an email with Messaging.SingleEmailMessage. The email should include TXT, HTML, and ICS versions and be received by an Outlook recipient as a calendar invite (not as an email with an attachment). The key is in setting the ICS attachment as an option in the same "content-type: multipart/alternative" section as the TXT and HTML versions. However, when I build the email with setPlainTextBody, setHtmlBody, and setFileAttachments, it sets the ICS attachment in its own "content-type" section.

How can I write my code to bring the .ICS file into the "Content-type: multipart/alternative" block with the TXT & HTML?

My current code:
public static void sendEventInviteICS(String bodyTXT, String bodyHTML, String subject, String fromAddress, String displayName, List<String> toAddress, List<String> ccAddress){
    //Create Message
    Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
    msg.setReplyTo(fromAddress);
    msg.setSenderDisplayName(displayName);
    msg.setToAddresses(toAddress);
    msg.setCcAddresses(ccAddress);
    msg.setSubject(subject);
    //Create TXT Version
    msg.setPlainTextBody(bodyTXT);
    //Create HTML Version
    msg.setHTMLBody(bodyHTML);
    //Create ICS Attachment
    Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
    efa.setFileName('Meeting Invite.ics');
    efa.setContentType('text/calendar');
    Blob b = buildICSAttachment();
    efa.setBody(b);
    msg.setFileAttachments(new Messaging.EmailFileAttachment[]{efa});
    //Send the Email
    Messaging.sendEmail(new Messaging.SingleEmailMessage[]{msg});
}
MIME result from current code:
Date: Tue, 9 Dec 2014 21:16:26 +0000
From: Isaac Lewis <ilewis@afs.net>
Reply-To: <djillumine@gmail.com>
To: "ilewis@afs.net" <ilewis@afs.net>
Subject: Sandbox: This is the subject
MIME-Version: 1.0
Content-type: multipart/mixed;
	boundary="B_3500983009_1157947"

> This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

--B_3500983009_1157947
Content-type: multipart/alternative;
	boundary="B_3500983009_1123381"


--B_3500983009_1123381
Content-type: text/plain;
	charset="US-ASCII"
Content-transfer-encoding: 7bit

This is the text body


--B_3500983009_1123381
Content-type: text/html;
	charset="US-ASCII"
Content-transfer-encoding: quoted-printable

<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8">
</head>
<body>
<i>This is the html body</i>
</body>
</html>


--B_3500983009_1123381--


--B_3500983009_1157947
Content-type: text/calendar; name="Attachment Name.ics"
Content-disposition: attachment;
	filename="Attachment Name.ics"
Content-transfer-encoding: base64

QkVHSU46VkNBTEVOREFSDQpNRVRIT0Q6UkVRVUVTVA0KUFJPRElEOk1pY3Jvc29mdCBFeGNo=

--B_3500983009_1157947--
Desired MIME Result (boundaries around ICS have been moved to be part of the "Content-type: multipart/alternative" block):
Date: Tue, 9 Dec 2014 21:16:26 +0000
From: Isaac Lewis <ilewis@afs.net>
Reply-To: <djillumine@gmail.com>
To: "ilewis@afs.net" <ilewis@afs.net>
Subject: Sandbox: This is the subject
MIME-Version: 1.0
Content-type: multipart/mixed;
	boundary="B_3500983009_1157947"

> This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

--B_3500983009_1157947
Content-type: multipart/alternative;
	boundary="B_3500983009_1123381"


--B_3500983009_1123381
Content-type: text/plain;
	charset="US-ASCII"
Content-transfer-encoding: 7bit

This is the text body


--B_3500983009_1123381
Content-type: text/html;
	charset="US-ASCII"
Content-transfer-encoding: quoted-printable

<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8">
</head>
<body>
<i>This is the html body</i>
</body>
</html>

--B_3500983009_1123381
Content-type: text/calendar; name="Attachment Name.ics"
Content-disposition: attachment;
	filename="Attachment Name.ics"
Content-transfer-encoding: base64

QkVHSU46VkNBTEVOREFSDQpNRVRIT0Q6UkVRVUVTVA0KUFJPRElEOk1pY3Jvc29mdCBFeGNo=

--B_3500983009_1123381--

--B_3500983009_1157947--




 
Hello everyone,

I need quick help from you guys regarding Service Console application.

I have created a console app as well as a custom app. Both of these apps are assigned to one of my custom profile, called Customer Support profile where I have set console app as a default app.

What I am facing is that when any of the user logs into the system, then they see Service Console app as deault app, Home page layout as default layout, but "Back to Service Console" tab as the only single tab.

When I click on this tab, it redirects me to the actual Home tab of Console app.

I want actual Home tab as a default tab, as it should be.

If I select another application (another custom application assigned to this profile), and come back to this Console app, then it is showing me actual home tab. I am expecting the same behavior for all users when they logged into the system.

Both of the snapshots are attached. (Issue / requirement)

Please help!!


User-added image

User-added image

I'm trying to prevent multiple SOQL queries in my method by creating a static list outside of the method.
The list is pulling from custom settings, so they should be static when the class runs.
Unfortunately, when I run the test for this class, the debug log shows nothing.
Am I putting this list in the wrong place?

Class
public class modeRanges{

    public static List<ModeRange__c> ModeRanges = [SELECT Mode_Type__c, Spend_Picklist_Value__c, Volume_Picklist_Value__c FROM ModeRange__c];

    public static void setSpendRangeFromVolumeRange(List<Mode__c> Modes){
	System.debug('ModeRanges: ' + ModeRanges);
        for(Mode__c m :Modes){
            for(ModeRange__c r: ModeRanges){
                if(m.Type__c == r.Mode_Type__c && m.Est_Volume__c == r.Volume_Picklist_Value__c){
                    m.Est_Spend__c = r.Spend_Picklist_Value__c;
                }
            }
        }
    }    
}

Debug Log
15:45:01:042 USER_DEBUG [12]|DEBUG|ModeRanges: ()

I have tested this trigger multiple times in the Sandbox, and it produces the proper results. However, when I deploy the changes to production, it comes out with different results. Does anyone know how I could trace what is producing the different results in production? I checked workflows and validation rules but couldn't find anything.
I am adding a trigger to default a Contact owner to the Account owner. It works fine and passes the test I wrote for it. HOWEVER, it fails a test from another piece of apex, telling me:

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, reassignCtOwnerToAcOwner: data changed by trigger for field Owner ID: owner cannot be blank: []

Here is the trigger I'm trying to deploy:

trigger reassignCtOwnerToAcOwner on Contact (before insert, before update) {

    List<Id> accountIds = new List<Id>();
    Map<Id, Id> accountOwnerIdMap = new Map<Id, Id>();

    // all the accounts whose owner ids to look up
    for ( Contact c : Trigger.new ) {
        accountIds.add( c.accountId );
    }
   
    // look up each account owner id
    for ( Account acct : [ SELECT id, ownerId FROM account WHERE id IN :accountIds ] ) {
        accountOwnerIdMap.put( acct.id, acct.ownerId );
    }
   
    // change contact owner to its account owner
    for ( Contact c : Trigger.new ) {
        c.ownerId = accountOwnerIdMap.get( c.accountId );
    }
}

Here is the test class for the OTHER trigger that fails when I try to insert a contact:

public static testMethod void validateContactCountsAndActivities() {

        //Create Account
  Account ac = new Account(
   Name='Test Account',
   Initial_Lead_Source__c='Cold Call',
   Initial_Lead_Source_Detail__c='Cold Call',
   Account_Type__c='Prospect',
   Account_Status__c='Not Contacted'   );
  insert ac;

        //Create Contact
        Contact ct = new Contact(
                LastName='Test Contact',
                Email='testcontact@email.com',
                Account= ac);
        insert ct;



Hello,

 

I'm a new user with a devil of a problem - I need to create a bit of code that wil allow me to send meeting requests to non-Salesforce users that will put my Salesforce meetings in their diaries, Outlook or other.

 

I put full details of my request on the General board, thinking it could be done from within the custom HTML email templates.  I now realise it's more of an Apex issue.  

 

Would you be so kind as to take a look?  The thread is http://boards.developerforce.com/t5/General-Development/sending-an-ICS-Outlook-compatible-calendar-request-with-workflow/td-p/658603.

 

Best regards,

 

Alex.

Of course for Primary Campaign, we have the field "Opportunity.Campaign", which is a lookup(Campaign) field on Opportunity. But there is also a related list for the Opportunity record detail page called "Campaign Influence", which can be populated in a couple of ways, including manual button-click to "Add" an Opportunity Campaign Influence record. This appears to be like a many-to-many relationship, implying that any opportunity can be linked to any campaign, non-exclusively so. That seems to imply a junction object.

 

I suspected something like OpportunityCampaign or something, but no such object exists.

 

Where are these relationships stored? How can they be created/modified via API or Apex (or even workflow)?

 

 

  • September 07, 2011
  • Like
  • 1

I can't deploy my trigger because there is an error in an Apex class and its corresponding test class. Actually it may just be in the test class.  In fact, I can't deploy anything but I want to change the test class so that it won't get an error!

 

I have been using the Eclpse IDE to deploy.  This really isn't a matter of deploying from the "sandbox" to the Production environment since this already exits in Production.  I am not sure where to begin.

I was wondering if anyone has had experience with this one. Is there a way to set the MIME type of an email sent via APEX? Additionally, I'll want to generate and attach an ICS file with meeting invite details. The ICS file is pretty much a txt file so that shouldn't be that tricky. Has anyone tried this before?
  • June 05, 2009
  • Like
  • 1
Hi

I'm trying to write a trigger for Case that will reopen or uncomplete the Final Milestone in the Entitlement Process for that Case. I have run up against getting an error
FIELD_INTEGRITY_EXCEPTION, You can’t change the completion date on a case milestone that’s already exited an entitlement process.
I am using a method expanded from the milestoneUtils code found here:
https://developer.salesforce.com/page/Case_Milestones_Utilities_Class

I tried adding @future against the method and while the error no longer occurs it does not uncomplete the Milestone going from Status 'Closed' to 'Open' the first time around.
However if I close the Case and then reopen subsequent times, it then does work.

Can anyone offer any insight into how I may correctly use the @future annotation so that it would work first time? Or any other way of dealing with this sequence of events?

This is my Trigger:
trigger openMilestoneOnReopenCase on Case (after update) {

    String finalMilestone = 'Solution Time';
    DateTime CompletionDate = NULL;
    List<Id> cases = new List<Id>();

    for(Case c:Trigger.new){

        //Get the prior update Case states
        Case oldCaseState = Trigger.oldMap.get(c.Id);

        // Checking if this is a Case being reopend from Closed
        if(c.Status == 'Open' && oldCaseState.Status == 'Closed'){
        
            // Get the Case Milestone List
            List<CaseMilestone> caseMilestones = [Select MilestoneTypeId, IsCompleted from CaseMilestone cm where cm.MilestoneType.Name=:finalMilestone AND cm.CaseId=:c.Id];
            
            //Iterate the Case Milestone List
            for(CaseMilestone caseMilestone:caseMilestones){
                
                //Check the Solution Time state isCompleted and add the Case to the Case List
                if(caseMilestone.isCompleted == true){
                    cases.add(c.Id);
                }
            }

            // Call the milestoneUtils Method
            if(!cases.isEmpty()){
                milestoneUtils.reopenMilestone(cases, finalMilestone, completionDate);
            }
        
        }
    }
}
This is the milestonesUtil Class I am calling the method from:
public class milestoneUtils {
    @future
    public static void reopenMilestone(List<Id> caseIds, String milestoneName, DateTime complDate) {
        System.debug('ASPD DEBUG: milestoneUtils: DateTime for completeMilestone is ' + string.valueOfGMT(complDate));

        List<CaseMilestone> cmsToUpdate = [select Id, completionDate from CaseMilestone cm where caseId in :caseIds and cm.MilestoneType.Name=:milestoneName and completionDate != null limit 1];
        if (cmsToUpdate.isEmpty() == false){
            for (CaseMilestone cm : cmsToUpdate){
                cm.completionDate = complDate;
            }
            update cmsToUpdate;
        }
    }
}

Thanks
Patrick