• Collin Edl
  • NEWBIE
  • 25 Points
  • Member since 2016


  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 4
    Questions
  • 2
    Replies
We have a standard support email that creates a case in Salesforce. Oftentimes a client will email someone, CC our support account and then those two people will email each other back and forth, every time having the support email CC'd, thus creating duplicate cases for the same issue. Looking for a way to have it where if the email has the same subject line, then all those interactions will be on the same case and no new case created.

Found some code online, tweaked it a little but it doesn't seem to be working in the sandbox. Any advise on where it could be failing?

CaseEmailInBoundUtilities
public with sharing class CaseEmailInBoundUtilities {

private Static Boolean TRACE = true;

protected Case theCase = null;
protected Messaging.InboundEmail inboundEmail;
protected String defaultCaseOwnerId;

public CaseEmailInBoundUtilities() {
 Group[] queues = [select Id, Name from Group where Name = 'Client Relations Queue'];
 this.defaultCaseOwnerId = queues[0].Id;  
}

public Messaging.InboundEmailResult processInboundEmail(Messaging.InboundEmail email)
{
 Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
 result.success = true;
 this.inboundEmail = email;
 

 String caseNumber = extractRef(email.subject);
 if(caseNumber != null)
 {  
  if(TRACE)system.debug(Logginglevel.ERROR,'CaseEmailInBoundUtilities.  extracted case number: "' + caseNumber + '"');
  this.theCase = locateByCaseNumberAsString(caseNumber);
  if(this.theCase == null) {
   // TODO email error message to SysAdmin
   system.debug(Logginglevel.ERROR,'CaseEmailInBoundUtilities.  Create a new case.  Could not find case number: "' + caseNumber + '"');
  }
 } else {
  // try to match subject
  String mainSubject = extractMainSubject(email.subject);
  Case[] matchingCases = [Select Id, CaseNumber, Subject, Description from Case where Subject = :mainSubject
   and CreatedDate = LAST_N_DAYS:5];
  if(matchingCases.size() == 1) {
   this.theCase = matchingCases[0];
  } else 
  {
   system.debug(Logginglevel.ERROR,'CaseEmailInBoundUtilities.  Create a new case because we found '+matchingCases.size() + ' cases with the subject: "' + mainSubject + '"');
  }
 }
 if(this.theCase == null) {
  // else create a new Case
  this.theCase = new Case();
  theCase.SuppliedEmail = email.fromAddress;
  theCase.SuppliedName = email.fromName;
  theCase.Status = 'New';
  theCase.Priority = 'Low';
  theCase.OwnerId = this.defaultCaseOwnerId;
        theCase.Origin = 'Inbound Email';
  theCase.Subject = email.Subject;
  theCase.Description = email.plainTextBody;
  
  Contact[] contacts = [SELECT Id, Name, AccountId, Email FROM Contact WHERE Email = :email.fromAddress];
  if(contacts.size() >0) 
  {
   Contact theContact = contacts[0];
   theCase.ContactId = theContact.Id;
   theCase.AccountId = theContact.AccountId;   
   if(contacts.size() > 1) {
    // Could-Should create a new Case here to get CS to resolve this....
    theCase.Description = 'Note: there is more than on Contact with this email address. Fix this. ' + theCase.Description;
   }
  }
  insertSObject(this.theCase);
 }

 createEmailMessage(theCase,email);
 handleAttachments(theCase, email);

  // send success notification. This can be disabled once we know the code is stable.
 // if(result.success)
 // {
 //  String successMessage = 'Successful processing of inbound email  \n'+ noteBody;
 //  TriggerErrorNotification.reportInfo(messagePrefix+ ' success ',successMessage);      
 // }
 return result;
}

// Save attachments, if any
private void handleAttachments(Case theCase, Messaging.InboundEmail email) {
 if(email.textAttachments!=null && email.textAttachments.size() >0) {
  for (Messaging.Inboundemail.TextAttachment tAttachment : email.textAttachments) {
    Attachment attachment = new Attachment();  
    attachment.Name = tAttachment.fileName;
    attachment.Body = Blob.valueOf(tAttachment.body);
    attachment.ParentId = theCase.Id;
    insertSObject(attachment);
  }
 }
 
 if(email.binaryAttachments!=null && email.binaryAttachments.size() >0) {
  for (Messaging.Inboundemail.BinaryAttachment bAttachment : email.binaryAttachments) {
    Attachment attachment = new Attachment();
    attachment.Name = bAttachment.fileName;
    attachment.Body = bAttachment.body;
    attachment.ParentId = theCase.Id;
    insertSObject(attachment);
  }
 } 
}

private void insertSObject(sObject obj) {
 try {insert obj;} catch (System.DmlException e) {handleError(e, 'Could not insert obj '+ obj);}
}

private String limitLength(String input, Integer maxLength)
{
 String results;
 if(input != null && input.length() > maxLength)
  results = input.substring(0,maxLength);
 else 
  results = input;
 return results;
}

private void createEmailMessage(Case theCase, Messaging.InboundEmail email) {
 String value;
 Integer maxlength;
 EmailMessage theEmail = new EmailMessage();
 theEmail.ParentId = theCase.Id;
 theEmail.Incoming = true;
 theEmail.Status = '1'; //set to new
 Schema.DescribeFieldResult F = EmailMessage.HtmlBody.getDescribe();
 //.HtmlBody.getDescribe();
 maxlength = F.getLength();
 theEmail.Subject = limitLength(email.Subject, EmailMessage.Subject.getDescribe().getLength());
 theEmail.MessageDate = datetime.now();
 theEmail.HtmlBody = limitLength(email.htmlBody,EmailMessage.HtmlBody.getDescribe().getLength());  
 theEmail.TextBody = limitLength(email.plainTextBody,EmailMessage.TextBody.getDescribe().getLength());

 /* **** To */
 value = '';
 if(email.toAddresses != null) {
  Boolean seenOne= false;
  for(String to : email.toAddresses) {
   if(seenOne) {
    value += ';\n';
   }
   to  = extractAddress(to);
   system.debug('ToAddress: ' + to);
   value += to;
   seenOne = true;
  }
 }
 theEmail.ToAddress = limitLength(value,EmailMessage.ToAddress.getDescribe().getLength());
 
 /* **** From */
 theEmail.FromName = email.fromName;
 theEmail.FromAddress = email.fromAddress;
 
 /* **** CC */
 value = '';
 if(email.ccAddresses != null) {
  Boolean seenOne= false;
  for(String cc : email.ccAddresses) {
   if(seenOne) {
    value += ';\n';
   }
   cc  = extractAddress(cc);
   system.debug('CcAddress: ' + cc);
   value += cc;
   seenOne = true;
  }
 }
 theEmail.CcAddress = limitLength(value,EmailMessage.CcAddress.getDescribe().getLength()); 
 insertSObject(theEmail);
}



private void handleError(System.DmlException e,  String message){
 String baseURL = URL.getSalesforceBaseUrl().toExternalForm() + '/';
 if(TRACE)system.debug(baseURL);
 String caseURL;  
 String msg = message + '\n';
 if(this.theCase != null)
 {
  caseURL = baseURL + theCase.Id;
  msg += '\n';
  msg += 'Originating Case Number: ' + theCase.CaseNumber + '  '+ caseURL+'\n';   
 }
 if(this.inboundEmail != null) {
  msg += '\nEmail:';
  msg += '  subject: ' + inboundEmail.Subject + '\n'; 
  msg += '  from: ' + inboundEmail.FromName + '\n'; 
  msg += '  address: ' + inboundEmail.FromAddress + '\n'; 
 }
 if(e != null) { // compose the DmlException message on one line to minimize the number of untested lines.  AFAIK easy to instantiate a DmlException in a unit test. 
  msg += '\n';
  msg += 'EXCEPTION:\n  Error: ' + e.getMessage() + '\n  Type: ' + e.getTypeName() + '\n  Line Number: ' + e.getLineNumber() + '\n  Trace:\n' + e.getStackTraceString() + '\n(end stack trace)\n';
 }

 Case errCase = new Case();
 errCase.OwnerId = this.defaultCaseOwnerId;
 errCase.Status = 'New';
 errCase.Priority = 'Low';
    errCase.Origin = 'Email';
 errCase.Subject = 'Error processing incoming email';
 errCase.Description = limitLength(msg,Case.Description.getDescribe().getLength());
 insert errCase;
 errCase = [Select Id, CaseNumber from Case where Id = :errCase.Id limit 1];  

 caseURL = baseURL + errCase.Id;
 msg += '\n\n';
 msg += 'Created new Case number ' + errCase.CaseNumber + ' for this error.  See: ' + caseURL +'\n'; 

//TriggerErrorNotification.reportError('CaseEmailInBoundUtilities', msg); 

}


/*
Given a case number such as 8144 find the exact case that use this number. Note that CaseNumber is a string field 
that may have any number of leading zeros. 
*/
private Case locateByCaseNumberAsString(String caseNumberStr){
 Integer target = Integer.valueOf(caseNumberStr);
 Case theResult = null;
 String caseNumber = '%' + String.valueOf(target);
 Case[] matchingCases = [Select Id, CaseNumber, Subject, Description from Case where CaseNumber like :caseNumber];
 for(Case aCase: matchingCases) {
  Integer cnum = Integer.valueOf(aCase.CaseNumber);
  if(cnum == target) {
  theResult = aCase;
  break;
  }
 }
 return theResult;
}

/*
Look for the case reference in the email subject line.  First search for a case reference using the
standard Salesforce method of creating that complicated and non-user-friendly reference.  Do this first
so it takes precedence.

But, also search for the case number itself. This is user-friendly!
*/

private String extractRef(String emailSubject)
{
 String itemRef = null;
// add test for null
 if(emailSubject == null)
  return null;
 String target = emailSubject.toLowerCase();
 String patternString;
 Pattern thePattern;
 Matcher matcher;
 
/*  Take the text between the period and ":ref"  For example in the ref [ ref:00D7JFzw.5007H3Rh8:ref ] extract 5007H3Rh8
 Take that text and remove the 5007. For example H3Rh8 
 Append H3Rh8 to https://na5.salesforce.com/5007000000  to produce https://na5.salesforce.com/5007000000H3Rh8.   This is your link to get to the case.
*/  
 patternString = '.*ref:(.{8}).(.{4})(.+):ref.*';
 thePattern = Pattern.compile(patternString);
 matcher = thePattern.matcher(emailSubject); // do not change to lower case for this test because Id's are case sensitive
  
 if (matcher.matches()) {
  String caseId = matcher.group(2) + '000000' + matcher.group(3);
  if(TRACE) system.debug(Logginglevel.ERROR,'extractRef "' + caseId + '"');    
  Case[] matchingCases = [Select CaseNumber from Case where Id = :caseId];
  if(matchingCases.size() == 1) {
   Case theCase = matchingCases[0];
   itemRef = theCase.CaseNumber;
  }    
 }  
 if(itemRef == null) {
  // extract the Case Number from the email Subject
  // Re: Test two numbers Case: 30088 and Case: 30089'
  // returns 30089, the last pattern matched
// Change the pattern to allow for more variations:
  patternString = '.*case\\s*[;:=#]?\\s*([0-9]+).*';
  thePattern = Pattern.compile(patternString);
  matcher = thePattern.matcher(target);
  
  if (matcher.matches()) {
   itemRef = matcher.group(1);
   if(TRACE) system.debug('Extracted case number ' + itemRef); 
  }
 }

 return itemRef; 
}

private String extractMainSubject(String emailSubject)
{
 if(emailSubject == null || emailSubject.length() < 3)
  return emailSubject;
 String[] prefixes = new String[] {'fw:','re:', 'automatic reply:', 'out of office autoreply:', 'out of office'};  
 String target = emailSubject.toLowerCase();
 for(String prefix: prefixes) {
  Integer index = target.indexOf(prefix); 
  if(index == 0 ){
   String mainSubject = emailSubject.substring(prefix.length(),emailSubject.length());
   return mainSubject.trim();
  }  
 }
 return emailSubject; 
}

private String extractAddress(String inAddress)
{
 String address;
 String patternString;
 Pattern thePattern;
 Matcher matcher;
 patternString = '.*<(.*)>.*';
 thePattern = Pattern.compile(patternString);
 matcher = thePattern.matcher(inAddress);
 if (matcher.matches()) {
  address = matcher.group(1);
  system.debug('Extracted address ' + address); 
 }
 else
 {
  address = inAddress;
  system.debug('Did not match angle-address ' + address);   
 }
 return address;
}
}

CaseEmailInBoundHandler
global class CaseEmailInBoundHandler implements Messaging.InboundEmailHandler {

    global Messaging.InboundEmailResult handleInboundEmail(
       Messaging.InboundEmail email,
       Messaging.InboundEnvelope envelope) {

 CaseEmailInBoundUtilities handler = new CaseEmailInBoundUtilities();
        Messaging.InboundEmailResult result = handler.processInboundEmail(email);
        return result;        
    }
}


 
Hi,

I'm writing test code for a new class that allows you to add multiple Competitors to an Opportunity. I've got the code and visualforce page working, although I'm having a bit of a tough time on the test code as I'm not really sure how to go about getting coverage for adding or removing a row. Maybe I'm overthinking the whole thing, but here's what I've got so far. Any help would be greatly appreciated. I'm more admin-based than developer so it's a little out of my wheelhouse.

Class
 
public with sharing class OpportunityCompetitor{

    public List<Opportunity_Competitor__c> oppComp {get; set;}
    private final Opportunity opp;
    public OpportunityCompetitor(ApexPages.StandardController cstmController) {
        Opp=(Opportunity)cstmController.getrecord();
        oppComp = new List<Opportunity_Competitor__c>();
        Opportunity_Competitor__c OpptyComp = new Opportunity_Competitor__c();
        OpptyComp.Opportunity__c = opp.id;
        oppComp.add(OpptyComp);
        } 
    
    public void addrow(){
        Opportunity_Competitor__c OpptyComp = new Opportunity_Competitor__c();
        OpptyComp.Opportunity__c = opp.id;
        oppComp.add(OpptyComp);}
    
     public void removerow(){
        Integer i = oppComp.size();
        OppComp.remove(i-1);}
    
    public PageReference save(){
        
   //error handling //   
   try{
      insert OppComp;
    }
      catch(Exception e){
           ApexPages.addMessages(e);
       return null;
    }
      
     
    // redirect the user back to the Opportunity record //        
        PageReference opprec = new PageReference('/'+opp.id);
        opprec.setRedirect(true);
        return opprec;
    }
}

Visualforce Page
<apex:page extensions="OpportunityCompetitor" tabStyle="Opportunity" standardController="Opportunity">
    <apex:form >
      <apex:sectionheader title="Opportunity Competitors" subtitle="{!Opportunity.Name}" />
            <apex:pageBlock >
        <p>
          Add one or more Competitors for this Opportunity. You can find competitors by using the Competitor lookup
           or by typing a name in the Competitor field. Click Add Row to enter multiple records or Remove Row to delete rows.  
       </p>
       <p>
        Click Save to add all entered Competitors to the Opportunity. Click Cancel to return to the Opportunity 
        record without saving. All data entered will be lost if you click Cancel.
       </p>
        <br />
        <apex:pageMessages />
        
            <apex:pageBlockButtons location="bottom">
                <apex:commandButton value="Save" action="{!save}" />
                <apex:commandButton value="Cancel" action="{!cancel}" />
            </apex:pageBlockButtons>
        
             <apex:pageblocktable value="{!OppComp}" var="OC" Title="Opportunity Competitors" id="table">
                      
         <!-- prevent users changing the Opportunity -->
         <apex:column headervalue="Oppportunity" rendered="false">
            <apex:inputfield value="{!OC.Opportunity__c}" style="width:250px;" />
        </apex:column>
         
         <apex:column headervalue="Competitor" >
           <apex:inputfield value="{!OC.Competitor__c}" style="width:290px;" />
        </apex:column>
                 
        <apex:column headervalue="Won" >
           <apex:inputfield value="{!OC.Won__c}" style="width:290px;" />
        </apex:column>
    
            </apex:pageBlockTable>
                      
              <div style="text-align:right;margin-right:10px;font-weight:bold;">       
                     <apex:commandLink value="Add Row" action="{!addRow}" rerender="table,error" immediate="true" /> &nbsp;|&nbsp;
                    <apex:commandLink value="Remove Row" action="{!removeRow}" rerender="table,error" immediate="true" />   
        </div>
            
        </apex:pageBlock>
    </apex:form>
</apex:page>
Test Code
@isTest
private class testOpportunityCompetitor{
      
       static testMethod void testOpportunityCloseExtOpp() {
        
       Id AcctRecordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Sales Accounts').getRecordTypeId();
       Id CompRecordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Competitor Accounts').getRecordTypeId();
       Id OppRecordTypeId = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('Standard').getRecordTypeId();
          
       //Create an account //
        Account acc = new Account();
        acc.Name='Account';
        acc.Type='Prospect';
        acc.recordTypeId = AcctRecordTypeId;
        insert acc;
     
        //Create an Opp //
        Opportunity Opp = new Opportunity();
        
        opp.recordTypeId = OppRecordTypeId;
        opp.name='test opp';
        opp.AccountId=acc.Id;
        opp.Type='NewBusiness';
        opp.Opportunity_Segment__c='Test';
        opp.closeDate=date.today();
        opp.StageName='New';
        opp.LeadSource='Cold Call';
        insert opp;          
       
        //Create a competitor account //
        Account acd = new Account();
        acd.Name='Competitor';
        acd.Type='Competitor';
        acd.recordTypeId = CompRecordTypeId;
        insert acd;
           
        List<Account> Comptr = [SELECT id from Account WHERE Id = :acd.id];
        List<Opportunity> oppList = [SELECT id from Opportunity WHERE Id = :opp.id];
    
        Opportunity_Competitor__c oppComp = new Opportunity_Competitor__c();
        oppComp.Opportunity__c=opp.Id;
        oppComp.Competitor__c=acd.ID;
        insert oppComp;
              
        Test.startTest();
        PageReference pageRef = Page.OpportunityCompetitor;
        Test.setCurrentPageReference(pageRef);
        
        /* Standard controller for the Opportunity */
        ApexPages.StandardController stdCon = new ApexPages.StandardController(opp);
        
        /*Construct the controller extension with the standard controller arg*/
        OpportunityCompetitor Ext = new OpportunityCompetitor(stdCon);
        PageReference oppPage = Ext.save();
        System.assert(oppPage != null);             
        Test.stopTest();
        }
          
          
      
}


 
We have a bit of code for our Live Agent piece that was done by a consultant a few years back. Recently we've been having issues where our contacts are being made "Private" and having the associated account removed. Is there anything in this code that could be doing this?
 
trigger ConsoleUpdate on Contact (before Insert,Before Update) {
    Map<Id,Id> RelatedAccountContact = New Map<Id,Id>();
    Map<Id,String> RelatedAccount = New Map<Id,String>();
    Map<Id,Id> RelatedAccountContactwithNulls = New Map<Id,Id>();
    List<contact> contactList = New List<Contact>();
    for(contact c :trigger.new){
         if(c.Account_Related_To__c!=null){
             String AccountId = c.Asurint_Acct_Id__c;
             RelatedAccount.put(c.id,AccountId);
             contactList.add(c);
         }
    }
    if(contactList.Size()>0){
        id DefaultAcctId = ([Select Id from Account where name = 'Default Account(Live Agent Only)'])[0].Id; 
        Map<String,id> AcctDetailsMap = New Map<String,id>();
        List<Account> AvailableAccounts = [Select Id,CSI_Account_ID__c from Account where CSI_Account_ID__c In: RelatedAccount.Values()];
        for(Account A : AvailableAccounts){
            AcctDetailsMap.put(A.CSI_Account_ID__c,A.id); 
        }
        for(contact c:contactList){
            if(AcctDetailsMap.get(RelatedAccount.get(c.id))!= Null ){
                RelatedAccountContactwithNulls.put(c.id,AcctDetailsMap.get(RelatedAccount.get(c.id)));
            }
            else{
                RelatedAccountContactwithNulls.put(c.id,DefaultAcctId );
            }
        }
        for(contact c:trigger.new){
            c.accountId = RelatedAccountContactwithNulls.get(c.Id);
        }
    }
}

 
Hi,
I'm trying to see why my test code is failing for when I try to create a custom object off our Opportunities. Running this will only give me 4%. Any help would be greatly appreciated!

Here's the class:
public with sharing class triggerLogic_Opportunity { 

        public static void createProject(List<Opportunity> newOpportunities){
        Set<ID> opportunityIDs = new Set<ID>();
            
        // Check for qualifying opportunities.
        for(Opportunity o : newOpportunities){
            if(o.StageName == 'Closed Won' && o.Type == 'New Business' && o.Setup_Opportunity_Created__c == false){
                opportunityIDs.add(o.id);
                           
            }
        }
        try{
            if(opportunityIDs.size() > 0){
            List<Opportunity> createProjectsFor = opportunityQuery(opportunityIDs);
            List<Milestone1_Project__c> projectsCreated = new List<Milestone1_Project__c>();
            List<Milestone1_Milestone__c> mainMilestones = new List<Milestone1_Milestone__c>();
            Group pUserForOwnerID = [SELECT Id FROM GROUP WHERE Name = 'Sales Operations Queue' AND TYPE = 'QUEUE'];
            
            
           
            //supportLogic_Dates sld = new supportLogic_Dates();
            
            for(Opportunity o : createProjectsFor){
                // Create projects
               
                o.Setup_Opportunity_Created__c = true;
                Milestone1_Project__c project = new Milestone1_Project__c();
                project.Name = o.Name + ' New Account Setup';
                //project.Status__c = 'Agreement Signed';
                //project.Project_Type__c = 'New Account Setup';
                project.Opportunity__c = o.Id;
                project.Kickoff__c = Date.today();
                project.Date_Time_Opened__c = system.now();
                project.Deadline__c = supportLogic_Dates.addBusinessDays(Date.today(), 5);
                project.OwnerId = pUserForOwnerID.Id;
                projectsCreated.add(project);
            }                   
                    
                
            insert(projectsCreated);
            update(createProjectsFor);  
            // Add Main Milestones to each project.
            for(Milestone1_Project__c p : projectsCreated){
                // Create Setup Milestone
                Milestone1_Milestone__c mainMilestone1 = new Milestone1_Milestone__c();
                mainMilestone1.Name = 'Implementation Call';
                mainMilestone1.Project__c = p.id;
                mainMilestone1.Date_Time_Opened__c = system.now();
                mainMilestone1.Kickoff__c = Date.today();
                mainMilestone1.Stage__c = 'Stage 1';
                mainMilestone1.Deadline__c = supportLogic_Dates.addBusinessDays(Date.today(), 4);
                mainMilestones.add(mainMilestone1);
 
                Milestone1_Milestone__c mainMilestone2 = new Milestone1_Milestone__c();
                mainMilestone2.Name = 'Packages';
                mainMilestone2.Project__c = p.id;
                mainMilestone2.Date_Time_Opened__c = system.now();
                mainMilestone2.Kickoff__c = Date.today();
                mainMilestone2.Stage__c = 'Stage 2';
                mainMilestone2.Deadline__c = supportLogic_Dates.addBusinessDays(Date.today(), 4);
                mainMilestones.add(mainMilestone2);
                
                Milestone1_Milestone__c mainMilestone3 = new Milestone1_Milestone__c();
                mainMilestone3.Name = 'Users';
                mainMilestone3.Project__c = p.id;
                mainMilestone3.Date_Time_Opened__c = system.now();
                mainMilestone3.Kickoff__c = Date.today();
                mainMilestone3.Stage__c = 'Stage 3';
                mainMilestone3.Deadline__c = supportLogic_Dates.addBusinessDays(Date.today(), 4);
                mainMilestones.add(mainMilestone3);
                
  
            }   
            
            insert(mainMilestones);
            
        }
        }Catch(Exception ex){
            new Opportunity().addError('Issue in creating associated project.');
            new Milestone1_Project__c().addError('Issue in creating associated project.');
        }
        
        
            
    }
    
    public static List<Opportunity> opportunityQuery(Set<ID> queryThese){
        String pqString = supportLogic_SOQL.getAllObjectFields('Opportunity', 'ID IN :queryThese');
        List<Opportunity> theseCases = (List<Opportunity>)database.query(pqString);
        return(theseCases);
    } 
}

And here's the test code:
 
@isTest
private class test_triggerLogic_Opportunity { 
   static testmethod void testCreateProject(){
        // Create a new opportunity
        Opportunity testOpportunity = new Opportunity();
        Opportunity testOpportunityClone = new Opportunity();
        final ID opportunitiesStandardRTID =  supportLogic_RT.getRTId('Standard', 'Opportunity');
        System.debug('STANDARD RECORD TYPE ID: >>>> + opportunitiesStandardRTID');
        
        testOpportunity.Name = 'Project Test Opportunity';
        testOpportunity.RecordTypeID = opportunitiesStandardRTID;
        testOpportunity.type = 'New Business';
        testOpportunity.StageName = 'Qualification';
        testOpportunity.LeadSource = 'Web';
        testOpportunity.CloseDate = date.parse('09/25/1990');
        testOpportunity.Probability = 10;
        testOpportunity.NextStep = 'Nothing';
        insert(testOpportunity);
        
        // This is to throw an exception for 100% code coverage.
        testOpportunityClone.Name = 'Duplicate Test Opportunity';
        testOpportunityClone.RecordTypeID = opportunitiesStandardRTID;
        testOpportunityClone.type = 'New Business';
        testOpportunityClone.StageName = 'Qualification';
        testOpportunityClone.LeadSource = 'Web';
        testOpportunityClone.CloseDate = date.parse('09/25/1990');
        testOpportunityClone.Probability = 10;
        testOpportunityClone.NextStep = 'Nothing';
        insert(testOpportunityClone);
           
        } 
}

 
Hi,
I'm trying to see why my test code is failing for when I try to create a custom object off our Opportunities. Running this will only give me 4%. Any help would be greatly appreciated!

Here's the class:
public with sharing class triggerLogic_Opportunity { 

        public static void createProject(List<Opportunity> newOpportunities){
        Set<ID> opportunityIDs = new Set<ID>();
            
        // Check for qualifying opportunities.
        for(Opportunity o : newOpportunities){
            if(o.StageName == 'Closed Won' && o.Type == 'New Business' && o.Setup_Opportunity_Created__c == false){
                opportunityIDs.add(o.id);
                           
            }
        }
        try{
            if(opportunityIDs.size() > 0){
            List<Opportunity> createProjectsFor = opportunityQuery(opportunityIDs);
            List<Milestone1_Project__c> projectsCreated = new List<Milestone1_Project__c>();
            List<Milestone1_Milestone__c> mainMilestones = new List<Milestone1_Milestone__c>();
            Group pUserForOwnerID = [SELECT Id FROM GROUP WHERE Name = 'Sales Operations Queue' AND TYPE = 'QUEUE'];
            
            
           
            //supportLogic_Dates sld = new supportLogic_Dates();
            
            for(Opportunity o : createProjectsFor){
                // Create projects
               
                o.Setup_Opportunity_Created__c = true;
                Milestone1_Project__c project = new Milestone1_Project__c();
                project.Name = o.Name + ' New Account Setup';
                //project.Status__c = 'Agreement Signed';
                //project.Project_Type__c = 'New Account Setup';
                project.Opportunity__c = o.Id;
                project.Kickoff__c = Date.today();
                project.Date_Time_Opened__c = system.now();
                project.Deadline__c = supportLogic_Dates.addBusinessDays(Date.today(), 5);
                project.OwnerId = pUserForOwnerID.Id;
                projectsCreated.add(project);
            }                   
                    
                
            insert(projectsCreated);
            update(createProjectsFor);  
            // Add Main Milestones to each project.
            for(Milestone1_Project__c p : projectsCreated){
                // Create Setup Milestone
                Milestone1_Milestone__c mainMilestone1 = new Milestone1_Milestone__c();
                mainMilestone1.Name = 'Implementation Call';
                mainMilestone1.Project__c = p.id;
                mainMilestone1.Date_Time_Opened__c = system.now();
                mainMilestone1.Kickoff__c = Date.today();
                mainMilestone1.Stage__c = 'Stage 1';
                mainMilestone1.Deadline__c = supportLogic_Dates.addBusinessDays(Date.today(), 4);
                mainMilestones.add(mainMilestone1);
 
                Milestone1_Milestone__c mainMilestone2 = new Milestone1_Milestone__c();
                mainMilestone2.Name = 'Packages';
                mainMilestone2.Project__c = p.id;
                mainMilestone2.Date_Time_Opened__c = system.now();
                mainMilestone2.Kickoff__c = Date.today();
                mainMilestone2.Stage__c = 'Stage 2';
                mainMilestone2.Deadline__c = supportLogic_Dates.addBusinessDays(Date.today(), 4);
                mainMilestones.add(mainMilestone2);
                
                Milestone1_Milestone__c mainMilestone3 = new Milestone1_Milestone__c();
                mainMilestone3.Name = 'Users';
                mainMilestone3.Project__c = p.id;
                mainMilestone3.Date_Time_Opened__c = system.now();
                mainMilestone3.Kickoff__c = Date.today();
                mainMilestone3.Stage__c = 'Stage 3';
                mainMilestone3.Deadline__c = supportLogic_Dates.addBusinessDays(Date.today(), 4);
                mainMilestones.add(mainMilestone3);
                
  
            }   
            
            insert(mainMilestones);
            
        }
        }Catch(Exception ex){
            new Opportunity().addError('Issue in creating associated project.');
            new Milestone1_Project__c().addError('Issue in creating associated project.');
        }
        
        
            
    }
    
    public static List<Opportunity> opportunityQuery(Set<ID> queryThese){
        String pqString = supportLogic_SOQL.getAllObjectFields('Opportunity', 'ID IN :queryThese');
        List<Opportunity> theseCases = (List<Opportunity>)database.query(pqString);
        return(theseCases);
    } 
}

And here's the test code:
 
@isTest
private class test_triggerLogic_Opportunity { 
   static testmethod void testCreateProject(){
        // Create a new opportunity
        Opportunity testOpportunity = new Opportunity();
        Opportunity testOpportunityClone = new Opportunity();
        final ID opportunitiesStandardRTID =  supportLogic_RT.getRTId('Standard', 'Opportunity');
        System.debug('STANDARD RECORD TYPE ID: >>>> + opportunitiesStandardRTID');
        
        testOpportunity.Name = 'Project Test Opportunity';
        testOpportunity.RecordTypeID = opportunitiesStandardRTID;
        testOpportunity.type = 'New Business';
        testOpportunity.StageName = 'Qualification';
        testOpportunity.LeadSource = 'Web';
        testOpportunity.CloseDate = date.parse('09/25/1990');
        testOpportunity.Probability = 10;
        testOpportunity.NextStep = 'Nothing';
        insert(testOpportunity);
        
        // This is to throw an exception for 100% code coverage.
        testOpportunityClone.Name = 'Duplicate Test Opportunity';
        testOpportunityClone.RecordTypeID = opportunitiesStandardRTID;
        testOpportunityClone.type = 'New Business';
        testOpportunityClone.StageName = 'Qualification';
        testOpportunityClone.LeadSource = 'Web';
        testOpportunityClone.CloseDate = date.parse('09/25/1990');
        testOpportunityClone.Probability = 10;
        testOpportunityClone.NextStep = 'Nothing';
        insert(testOpportunityClone);
           
        } 
}