• Shawn Reichner 33
  • NEWBIE
  • 35 Points
  • Member since 2020

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 7
    Questions
  • 7
    Replies
Hello awesome developer helpers!
I have a problem on my hands around getting enough code coverage for the below code I am working on.
The Scenario: When a CPQ quote is being worked and it is a primary quote I have a process builder that keeps fields updated between the primary quote and the opportunity.
One of these fields is a multi select picklist called opportunity manufacturer, and what should be populating in this field is the manufacturers of each product on the quote only listed once (hence the set to hold those values).
So when this process builder process kicks off, fields are updated and the below "AggregateManufacturerInfo" class is called from the process. This class then grabs the list of Opp IDs from the process and calls a queueable class to do the work listed above for the manufactures and populating the multi select picklist.
Here is where I had to build out the code more as with CPQ it seems to make callouts to heroku when calculation or a document is generated, and I was getting the "Too Many queueable jobs in the queue" error. So I added in the try catch block on the following code "AggregateManQueueableJob" class to check if Limits.getQueueableJobs() is greater than 0 to catch this and if the limit is greater than 0, then call a scheduled class to get around the limit of 2 per queue error.
Here is the problem my friends, this is my first scheduled class, and the test class below saves and covers all of my code except for the calling of the scheduled class in the try / catch block, and my question is what can I change or how can I get that portion covered in my test class?
How can I fake.mock more than one queueable job in the queue to get my test class to test both scenarios? My current coverage is 100% on all classes except for "AggregateManQueuableJob" which is currently at 71%. Any help you can give would be greatly appreciated :)
Initial class called from process :AggregateManufcaturerInfo"
 
public class AggregateManufacturerInfo {

    @InvocableMethod
    public static void setOppMan(LIST<ID> OppIds){
        System.enqueueJob(new AggregateManQueueableJob(oppIds));
    }
}

Queueable class called from above class:
 
public class AggregateManQueueableJob implements Queueable {
    
    public List<Id> oppList;

    public AggregateManQueueableJob (List<Id> oppIds){
        oppList = oppIds;
    }

    public void execute(QueueableContext qc){
        System.debug(oppList);
        
        Id OppId = oppList[0];
        
        Opportunity opp = [SELECT ID, Opportunity_Manufacturer_s__c FROM Opportunity
                          WHERE ID=: OppId];
        opp.Opportunity_Manufacturer_s__c = null;
        List<SBQQ__QuoteLine__c> lines = new List<SBQQ__QuoteLine__c>();
        lines = [SELECT ID, SBQQ__Product__r.Reported_Manufacturer__c, SBQQ__Quote__r.SBQQ__Opportunity2__r.Id
                FROM SBQQ__QuoteLIne__c WHERE SBQQ__Quote__r.SBQQ__Opportunity2__r.ID =: OppId AND 
                SBQQ__Quote__r.SBQQ__Primary__c = True];
        
        if(lines.size()>0){
            Set<String> mans = new Set<String>();
            for(SBQQ__QuoteLine__c linesToProcess : lines){
                if(!String.isBlank(linesToProcess.SBQQ__Product__r.Reported_Manufacturer__c)){
                    if(linesToProcess.SBQQ__Product__r.Reported_Manufacturer__c != 'Critical Start' && linesToProcess.SBQQ__Product__r.Reported_Manufacturer__c != 'INSTALL'){
                   mans.add(linesToProcess.SBQQ__Product__r.Reported_Manufacturer__c);
                    }
                }
            }
            
            if(!mans.isEmpty()){
                for(String man : mans){
                    if(!String.isBlank(opp.Opportunity_Manufacturer_s__c)){
                        opp.Opportunity_Manufacturer_s__c = opp.Opportunity_Manufacturer_s__c + ';' + man;
                    }
                    else{
                        opp.Opportunity_Manufacturer_s__c = man;
                    }
                }
            }
        }
        
        try{
            If(Limits.getQueueableJobs() > 0){
                String hour = String.valueOf(Datetime.now().hour());
                String min = String.valueOf(Datetime.now().minute());
                String ss = String.valueOf(Datetime.now().second() + 5);
                String nextFireTime = ss + '' + min + '' + hour + '**?';
                
                errorAggregateSched schProc = new errorAggregateSched();
                schProc.ProcessIds = oppList;
                System.schedule('errorAggregateSched', nextFireTime, schProc);
            }else{
            update opp;
            }
            
        }catch(Exception e){
            system.debug('Exception:::'+e.getMessage());
        }
        
    }

}

And the scheduled class that would be called if the limits error occurs:
 
public class errorAggregateSched  implements Schedulable {
    
    public List<ID> ProcessIds;
    
    public void execute(SchedulableContext sc) {
        System.enqueueJob(new AggregateManQueueableJob(ProcessIds));
        System.abortJob(sc.getTriggerId());
    }

}

And finally my test class:
 
@isTest(SeeAllData=True)
public class AggregateManufacturerInfo_Test {

     public static testMethod void tm1() {
        List<SBQQ__QuoteLine__c> quoteLines = new List<SBQQ__QuoteLine__c>();
        List<ID> oppsToProcess = new List<ID>();
        //First Test with Good Product and Reported Manufacturer
        Account a = new Account();
            a.Name = 'Test Account1';
            a.Website = 'www.test1class.com';
            a.Type = 'Prospect';
            a.Sub_type__c = 'End User';
            insert a;
        Contact c = new Contact();
            c.FirstName = 'TestClass1';
            c.LastName = 'TesterClass1';
            c.Email = 'testclass1@tester.com';
            c.Phone = '1112223398';
            c.Title = 'Test Title';
            c.AccountId = a.Id;
            insert c;
       // ID standardPB = test.getStandardPricebookId();
        Opportunity opp = new Opportunity();
            opp.Name = 'Test Opp 1';
            opp.Amount = 1000;
            opp.AccountId = a.Id;
            opp.Bill_To_Account__c = a.Id;
            opp.Bill_To_Contact__c = c.Id;
            Opp.CloseDate = Date.today();
            opp.StageName = '1-Qualification';
      //    opp.Pricebook2Id = standardPB;
            insert opp;
        Product2 p = new Product2();
            p.Name = 'TestProduct1';
            p.ProductCode = 'TestProduct1';
            p.Product_Code_Unique__c = 'TestProduct1';
            p.Department__c = 'MDR';
            p.Type__c = 'Service';
            p.Sales_Type__c = 'For Sale';
            p.IsActive = true;
            p.SBQQ__DefaultQuantity__c = 1;
            p.Manufacturer__c = 'Critical Start';
            p.Reported_Manufacturer__c = 'DEVO';
            p.SBQQ__PricingMethod__c = 'List';
            insert p;
        SBQQ__Quote__c qt = new SBQQ__Quote__c();
            qt.SBQQ__Type__c = 'Quote';
            qt.SBQQ__Status__c = 'Draft';
            qt.SBQQ__Opportunity2__c = opp.Id;
            qt.SBQQ__Primary__c = true;
            qt.SBQQ__Account__c = a.Id;
            qt.SBQQ__PrimaryContact__c = c.Id;
        //  qt.SBQQ__PricebookId__c = standardPB;
            insert qt;
        SBQQ__QuoteLine__c ql = new SBQQ__QuoteLine__c();
            ql.SBQQ__Product__c = p.Id;
            ql.Department__c = 'MDR';
            ql.Category__c = 'MDR-Bundle';
            ql.SBQQ__Quantity__c = 1;
            ql.SBQQ__Number__c = 1;
            ql.SBQQ__ListPrice__c = 100;
            ql.SBQQ__ProrateMultiplier__c = 1;
            ql.SBQQ__ProratedListPrice__c = 100;
            ql.SBQQ__SpecialPrice__c = 100;
            ql.SBQQ__ProratedPrice__c = 100;
            ql.SBQQ__NetPrice__c = 100;
            ql.SBQQ__DefaultSubscriptionTerm__c = 12;
            ql.SBQQ__SubscriptionPricing__c = 'Fixed Price';
            ql.SBQQ__ProductSubscriptionType__c = 'Renewable';
            ql.SBQQ__SubscriptionType__c = 'Renewable';
            ql.SBQQ__Quote__c = qt.Id;
          //  quoteLines.add(ql);
        //	oppsToProcess.add(opp.Id);
           insert ql;
        oppsToProcess.add(opp.Id);
        
       Test.startTest();
            AggregateManufacturerInfo.setOppMan(OppsToProcess);
         
                String CRON_EXP = '0 0 0 15 3 ? 2022';
                String hour = String.valueOf(Datetime.now().hour());
                String min = String.valueOf(Datetime.now().minute() + 1);
                String ss = String.valueOf(Datetime.now().second() + 5);
                String nextFireTime = ss + '' + min + '' + hour + '**?';
                
                errorAggregateSched schProc = new errorAggregateSched();
                schProc.ProcessIds = oppsToProcess;
                System.schedule('errorAggregateSched', CRON_EXP, schProc);
        Test.stopTest();
    }
    
}

Thanks again for any help you can provide as I am at my wits end here lol!
Hello Awesome Devs!

I currently have business hours / Holidays removed from business hour calculations using formula fields.  The issue with that is, is an employe works on a holiday or weekend, the formula shows a negative number and I can not figure out a way to resolve that issue, so I am attempting to move to Apex to calculate the number of business hours and holidays.  When attempting to do so via an after insert / after update trigger which calls a class to use the business hour object and the diff method I receive the following error: Method does not exist or incorrect signature: void diff(Id, DateTime, DateTime) from the type BusinessHours

Any idea what my issue is here, and how to resolve? 

Trigger Code: 
trigger ticketTrigger on Ticket__c (after insert, after update) {
    
    List<Ticket__c> ticketsToUpdate = new List<Ticket__c>();
    
    for(Ticket__c tickets : Trigger.New){
		ticketTriggerHandler.sla(Trigger.new); 
    }
    
}

Class Code:
public class ticketTriggerHandler {

    public static void sla(List<Ticket__c> newTickets){
        
    	BusinessHours bh = [SELECT ID FROM BusinessHours WHERE IsDefault=true];
        
    	list<Ticket__c> ticketsToUpdate = new List<Ticket__c>();
        
    	List<Ticket__c> ticketsFromTrigger = newTickets;
        
        for(Ticket__c t : ticketsFromTrigger){
            DateTime create = t.Created_Date__c;
            DateTime Respond = t.Responded_Date__c;
            DateTime Resolve = t.Resolved_Date__c;
            Integer RespondDiff = bh.diff(bh.id, create, Respond);
            Integer ResolveDiff = bh.diff(bh.Id, create, Resolve);
            t.RespondedHours__c = RespondDiff;
            t.ResolvedHours = ResolveDiff;
            ticketsToUpdate.add(t);
        }
        if(ticketsToUpdate.size()>0){
            update ticketsToUpdate;
        }
    }
}

Thanks for any help you can provide!
Hello,

I have the following formula and even though the formula field is set as a number type and has 2 decimals set, the below formula is still rounding up to a whole hour.

I can not figure out how to get this formula to show the actual hours between the two dates.

The example I have to share is Created date is 9/2/2020 at 4:56PM and the resolved Date which is the other date time field is set to 9/2/2020 5:09 PM so this should be a fraction of an hour, but the formula field shows 1 and it is throwing our numbers off.

Can anyone help? Please?

Thanks in advance,

Shawn


ROUND(8 * ( /*# of weeks * 5 + #days leftover (up to five) */ (5 * ( FLOOR( ( DATEVALUE(Resolved_Date__c)-DATE(1900,1,8) ) / 7 ) ) + MIN( 5, MOD( DATEVALUE(Resolved_Date__c)-DATE(1900,1,8), 7 ) ) )
(5 * ( FLOOR( ( DATEVALUE(CreatedDate)-DATE(1900,1,8) ) / 7 ) ) + MIN( 5, MOD( DATEVALUE(CreatedDate)-DATE(1900,1,8), 7 ) ) ) ) + /if outside business hours, read as first/last business hour (CST is GMT-6)/ IF( VALUE(MID(TEXT(Resolved_Date__c - 6/24),12,2)) > 17, 17, IF( VALUE(MID(TEXT(Resolved_Date__c - 6/24),12,2)) < 9, 9, VALUE(MID(TEXT(Resolved_Date__c - 6/24),12,2)) ))
IF( VALUE(MID(TEXT(CreatedDate - 6/24),12,2)) > 17, 17, IF( VALUE(MID(TEXT(CreatedDate - 6/24),12,2)) < 9, 9, VALUE(MID(TEXT(CreatedDate - 6/24),12,2)) )) , 2)
Hello, I am not sure if this is the correct topic to list this under, but I am certain what I am looking for will ulimately need some custom coding.  

What I am being asked to find a potential solution for is for example: An existing quote already has quote lines present.  A User wishes to update said quote by "Importing Quote lines" using an import format.  When the import is used, they wish to have all existing quote lines be deleted and only the new lines from the import remaining.  

Any thoughts on how to possibly achieve this?

Any help would be very much appreciated!

Shawn
Hello awesome Devs! 

I have hit a roadblock on an VF email template I am workign on, and would appreciate any help you all may be able to offer. 

I have the following code where I need to set up an email to an outside party when a contract is created from an Won Opportunity for an order summary.  Seems when I travel from the Contract to the Won Opportunity and then down to its child line items I get the following error: 

Error: Aggregate Relationship is used in an unsupported complex expression containing 'SBQQ__Opportunity__r.opportunitylineitems'

Can anyone look at my below code and tell me what I am doing wrong, and point me in the right direction by manipulating my code below to try?  

Thank you again, very much appreciate any help! 

Email Template Code:
<messaging:emailTemplate recipientType="Contact"
    relatedToType="Contract"
    subject="ORDER SUMMARY_Subscription Contract Number {!relatedTo.ContractNumber}_PO:{!relatedTo.SBQQ__Opportunity__r.Customer_PO__c}"
    replyTo="support@criticalstart.com" >
    
<messaging:htmlEmailBody >        
    <html>
        <body>
         <STYLE type="text/css">
               TH {font-size: 11px; font-face: arial;background: #CCCCCC; border-width: 1;  text-align: center} 
               TD  {font-size: 11px; font-face: verdana } 
               TABLE {border: solid #CCCCCC; border-width: 1}
               TR {border: solid #CCCCCC; border-width: 1}
         </STYLE>
        <div style="text-align:left;">
        <apex:image id="theImage" value="https://xxx.my.salesforce.com/servlet/servlet.ImageServer?id=0153j00000AlYgC&oid=00D3j00000024KB"  width="465" height="84" alt="Critical Start" />
        </div>
        <br/>
        <font face="arial" size="2">
        <b>6100 Tennyson Pkwy #200</b><br/>
        <b>Plano, TX 75024 </b>
        <b>USA</b><br/>
        <b>Phone: (877) 648-2077</b><br/>
        <b>Fax: (214) 919-4050</b><br/> </font>
        <br/>
        <br/>
        <font face="arial" size="5">
        <b>Order Summary</b><br/>
        <br/> </font>
        <font face="arial" size="2">
        <b><u>General Information</u></b><br/>
        Sales ID: {!relatedTo.SBQQ__Opportunity__r.Opp_Num_Only__c}<br/>
        Subscription Contract Number: {!relatedTo.ContractNumber}<br/>
        Subscription Contract Start Date: {!relatedTo.StartDate}<br/>
        Subscription Contract End Date: {relatedTo.EndDate}<br/>
        Subscription Contract Term Length: {!relatedTo.ContractTerm} months<br/>
        Document Date: {!month(relatedTo.Todays_Date__c)}/{!day(relatedTo.Todays_Date__c)}/{!year(relatedTo.Todays_Date__c)}<br/>
        PO #: {!relatedTo.SBQQ__Opportunity__r.Customer_PO__c}<br/>
        Account Manager: {!relatedTo.SBQQ__Opportunity__r.Owner_Full_Name__c}<br/>
        <br/>
        </font>
        <b><u>Sold-To-Party</u></b><br/>
        {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_Name__c}<br/>
        {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_Street__c}<br/>
        {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_City__c}, {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_State__c} {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_Zip__c}<br/>
        {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_Country__c}<br/> 
        E-Mail: {!relatedTo.SBQQ__Opportunity__r.Bill_To_Contact_Email__c}<br/>
        <br/>
        <b><u>End User</u></b><br/>
        {!relatedTo.SBQQ__Opportunity__r.Account_Name__c}<br/>
        {!relatedTo.SBQQ__Opportunity__r.Account_Street__c}<br/>
        {!relatedTo.SBQQ__Opportunity__r.Account_City__c}, {!relatedTo.SBQQ__Opportunity__r.Account_State__c} {!relatedTo.SBQQ__Opportunity__r.Account_Zip__c}<br/>
        {!relatedTo.SBQQ__Opportunity__r.Account_Country__c}<br/>
        <br/>
        <b><u>Bill-To-Party</u></b><br/>
        {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_Name__c}<br/>
        {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_Street__c}<br/>
        {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_City__c}, {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_State__c} {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_Zip__c}<br/>
        {!relatedTo.SBQQ__Opportunity__r.Bill_To_Account_Country__c}<br/> 
        <br/>
        <font face="arial" size="2">
        <p><b>Below contains a list of products ordered:</b></p>  
        <p/>                  
       <table border="5" >
                 <tr > 
                     <th>Product Name</th><th>Description</th><th>Quantity</th>
                  </tr>
    <apex:repeat var="opp" value="{!relatedTo.SBQQ__Opportunity__r.OpportunityLineItems}">
       <tr>
           <td>{!opp.PriceBookEntry.name}</td>
           <td>{!opp.Description__c}</td>
           <td>{!ROUND(opp.Quantity,0)}</td>
       </tr>
    </apex:repeat>                
       </table>
       <p/>
 </font>
       
        </body>
    </html>
</messaging:htmlEmailBody> 
    
<messaging:plainTextEmailBody >
Dear {!recipient.name},
 
Below contains a list of products ordered.

Account: {!relatedTo.SBQQ__Opportunity__r.Account.name}
Opportunity Close Date: {!relatedTo.SBQQ__Opportunity__r.CloseDate}


[ Product Name ] - [ Description ] - [ Quantity ]
-------------------------------------------------------------------------

<apex:repeat var="opp" value="{!relatedTo.SBQQ__Opportunity__r.OpportunityLineItems}">
[ {!opp.PriceBookEntry.name} ] - [{!opp.Description__c} ] - [ {!ROUND(opp.Quantity,0)} ]
</apex:repeat>

</messaging:plainTextEmailBody>       
        
</messaging:emailTemplate>

 
Hello Awsome fellow Salesforce experts!

I have an issue with a flow that I am tryign to create.  First I tried this solution via an apex class being called from a process builder and that caused either Apex Time Out errors and or Record Locking errors, so I tried to go a more decalrative approach that I read can work, just not how. I tried my best and hoping you can help me out.  

What is the Goal? - I have a Text field on our Product (Standard Product2 Object) called Reported Manufacturer.  This field is listing the OEM Manufacturer of the product.  For pipeline purposed and workign with our manufactures we need the ability to concatenate all of the associated Quote Lines "Reported Manufacturer" fields to catpure one or more manufactures that make up the Opportunity. 

When a Quote is marked primary a process builder should call the flow in question to get all Quote Lines, then update the Opportunity associated to blank out the "Opportunity Manufacturer(s)" Multi Select PickList field, then the next step of the flow is to loop through all quoet lines found for that quote and assign the value of the products reported manufacture to a formula field in the flow for each item and then after the last item is looped through, go ahead an update the Multi Picklist field on the Opportunity "Opportunity Manufacture(s)"  with all of the values found for reported manufacturer on the quote lines with deduplicating if possible. 

Example: Product A has a reported manufacturer of xxx and Product B has a reported manufacturer of yyy and Product C has a reported manufacturer of xxx.  When the quote is saved and is the primary quote, then process runs, calls the flow and the above should when completed should have updated the Opportunity Multi Select Picklist field "Opportunity Manufactuer(s)" with xxx and yyy. 

Hope that made sense and if you need any further information please ask away...Please see the flow below as well as each Element. 

PLEASE HELP!!!!!

Total FLow:
User-added imageUser-added imageUser-added image
User-added imageUser-added image
Hello awesome developers! 

I have the following Apex class that implements an incoming Apex Email Service.  The class works 100% with no issues and I get a Custom Object record creatd and all is good.  The issue is when I attempted to create a test class for this service.  I get the lines of the email service covered but the record being created is not being covered.  This is due to in my test class below you will notice the SOQL query to bring back the custom object record that was created by the test class to assert against and there are no rows for assignment.  

Can you kindly help me update the beloe test class to cover 100% and to cover the custom object record that is being created. 

Thank you so much in advance for any help you are able to provide,

Shawn

Class:
global class SFDCIssueEmailClass implements Messaging.InboundEmailHandler {
 
  global Messaging.InboundEmailResult handleInboundEmail(Messaging.inboundEmail email, 
                                                       Messaging.InboundEnvelope env){
 
    Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
  
    String myPlainText= '';
    Group queue = [SELECT Id FROM Group WHERE Name = 'Salesforce Queue' and Type='Queue'];
                                                           
    myPlainText = email.plainTextBody;
   
    Salesforce_Issue__c[] newTask = new Salesforce_Issue__c[0];
   
    try {
      User vCon = [SELECT Id, FirstName, LastName, Email
        FROM User
        WHERE Email = :email.fromAddress
        LIMIT 1];
      
      newTask.add(new Salesforce_Issue__c(Descripton__c =  myPlainText,
           Priority__c = 'P4',
           Status__c = 'New',
           Subject__c = email.subject,
           Email_Requestor__c =  email.fromAddress,
           OwnerId = queue.Id,
           Origin__c = 'Email',
           RecordTypeId = '012q00000005mXhAAI'));
     

     insert newTask;    
     
     System.debug('New Task Object: ' + newTask );   
    }

   catch (QueryException e) {
       System.debug('Query Issue: ' + e);
   }

   result.success = true;
   
   return result;
  }
}

Test Class:
@isTest
public class SFDCIssueEmailClassTest {

    public static testMethod void EmailTest(){
        
        Contact c = new Contact(lastname = 'tested', email = 'test@test.com');
        insert c;
        
        SFDCIssueEmailClass objconfirm = new SFDCIssueEmailClass();
        Messaging.InboundEmail email = new Messaging.InboundEmail();
        email.fromAddress = c.email;
        email.subject = 'Test Subject';
        email.plainTextBody = 'my text';
          
       // objconfirm.handleInboundEmail(email, envelope);
        Messaging.InboundEnvelope envelope = new Messaging.InboundEnvelope();
        objconfirm.handleInboundEmail(email, envelope);
        Messaging.InboundEmailResult result = objconfirm.handleInboundEmail(email, envelope);
        system.assertEquals(result.success, true); 
        
        Salesforce_Issue__c[] issue = [SELECT ID FROM Salesforce_Issue__c WHERE Email_Requestor__c = :email.fromAddress];
        system.assertEquals(1, issue.size(),'Issue not inserted');
        
    }
    
}

​​​​​​​
Hello Awesome Devs!

I currently have business hours / Holidays removed from business hour calculations using formula fields.  The issue with that is, is an employe works on a holiday or weekend, the formula shows a negative number and I can not figure out a way to resolve that issue, so I am attempting to move to Apex to calculate the number of business hours and holidays.  When attempting to do so via an after insert / after update trigger which calls a class to use the business hour object and the diff method I receive the following error: Method does not exist or incorrect signature: void diff(Id, DateTime, DateTime) from the type BusinessHours

Any idea what my issue is here, and how to resolve? 

Trigger Code: 
trigger ticketTrigger on Ticket__c (after insert, after update) {
    
    List<Ticket__c> ticketsToUpdate = new List<Ticket__c>();
    
    for(Ticket__c tickets : Trigger.New){
		ticketTriggerHandler.sla(Trigger.new); 
    }
    
}

Class Code:
public class ticketTriggerHandler {

    public static void sla(List<Ticket__c> newTickets){
        
    	BusinessHours bh = [SELECT ID FROM BusinessHours WHERE IsDefault=true];
        
    	list<Ticket__c> ticketsToUpdate = new List<Ticket__c>();
        
    	List<Ticket__c> ticketsFromTrigger = newTickets;
        
        for(Ticket__c t : ticketsFromTrigger){
            DateTime create = t.Created_Date__c;
            DateTime Respond = t.Responded_Date__c;
            DateTime Resolve = t.Resolved_Date__c;
            Integer RespondDiff = bh.diff(bh.id, create, Respond);
            Integer ResolveDiff = bh.diff(bh.Id, create, Resolve);
            t.RespondedHours__c = RespondDiff;
            t.ResolvedHours = ResolveDiff;
            ticketsToUpdate.add(t);
        }
        if(ticketsToUpdate.size()>0){
            update ticketsToUpdate;
        }
    }
}

Thanks for any help you can provide!
Hello,

I have the following formula and even though the formula field is set as a number type and has 2 decimals set, the below formula is still rounding up to a whole hour.

I can not figure out how to get this formula to show the actual hours between the two dates.

The example I have to share is Created date is 9/2/2020 at 4:56PM and the resolved Date which is the other date time field is set to 9/2/2020 5:09 PM so this should be a fraction of an hour, but the formula field shows 1 and it is throwing our numbers off.

Can anyone help? Please?

Thanks in advance,

Shawn


ROUND(8 * ( /*# of weeks * 5 + #days leftover (up to five) */ (5 * ( FLOOR( ( DATEVALUE(Resolved_Date__c)-DATE(1900,1,8) ) / 7 ) ) + MIN( 5, MOD( DATEVALUE(Resolved_Date__c)-DATE(1900,1,8), 7 ) ) )
(5 * ( FLOOR( ( DATEVALUE(CreatedDate)-DATE(1900,1,8) ) / 7 ) ) + MIN( 5, MOD( DATEVALUE(CreatedDate)-DATE(1900,1,8), 7 ) ) ) ) + /if outside business hours, read as first/last business hour (CST is GMT-6)/ IF( VALUE(MID(TEXT(Resolved_Date__c - 6/24),12,2)) > 17, 17, IF( VALUE(MID(TEXT(Resolved_Date__c - 6/24),12,2)) < 9, 9, VALUE(MID(TEXT(Resolved_Date__c - 6/24),12,2)) ))
IF( VALUE(MID(TEXT(CreatedDate - 6/24),12,2)) > 17, 17, IF( VALUE(MID(TEXT(CreatedDate - 6/24),12,2)) < 9, 9, VALUE(MID(TEXT(CreatedDate - 6/24),12,2)) )) , 2)
Hello, I am not sure if this is the correct topic to list this under, but I am certain what I am looking for will ulimately need some custom coding.  

What I am being asked to find a potential solution for is for example: An existing quote already has quote lines present.  A User wishes to update said quote by "Importing Quote lines" using an import format.  When the import is used, they wish to have all existing quote lines be deleted and only the new lines from the import remaining.  

Any thoughts on how to possibly achieve this?

Any help would be very much appreciated!

Shawn
Hello Awsome fellow Salesforce experts!

I have an issue with a flow that I am tryign to create.  First I tried this solution via an apex class being called from a process builder and that caused either Apex Time Out errors and or Record Locking errors, so I tried to go a more decalrative approach that I read can work, just not how. I tried my best and hoping you can help me out.  

What is the Goal? - I have a Text field on our Product (Standard Product2 Object) called Reported Manufacturer.  This field is listing the OEM Manufacturer of the product.  For pipeline purposed and workign with our manufactures we need the ability to concatenate all of the associated Quote Lines "Reported Manufacturer" fields to catpure one or more manufactures that make up the Opportunity. 

When a Quote is marked primary a process builder should call the flow in question to get all Quote Lines, then update the Opportunity associated to blank out the "Opportunity Manufacturer(s)" Multi Select PickList field, then the next step of the flow is to loop through all quoet lines found for that quote and assign the value of the products reported manufacture to a formula field in the flow for each item and then after the last item is looped through, go ahead an update the Multi Picklist field on the Opportunity "Opportunity Manufacture(s)"  with all of the values found for reported manufacturer on the quote lines with deduplicating if possible. 

Example: Product A has a reported manufacturer of xxx and Product B has a reported manufacturer of yyy and Product C has a reported manufacturer of xxx.  When the quote is saved and is the primary quote, then process runs, calls the flow and the above should when completed should have updated the Opportunity Multi Select Picklist field "Opportunity Manufactuer(s)" with xxx and yyy. 

Hope that made sense and if you need any further information please ask away...Please see the flow below as well as each Element. 

PLEASE HELP!!!!!

Total FLow:
User-added imageUser-added imageUser-added image
User-added imageUser-added image
trigger Trigger1Problem on Account(after insert, after update) 
{
    List<Opportunity> opp = new List<Opportunity>();
    
    Map<ID, Account> accountmap = new Map<ID, Account>([Select Id, Name, (Select Id From Opportunities) From Account Where Id In :Trigger.New]);
    for(Account a : trigger.new)
    {
        if(accountmap.get(a.Id).Opportunities.size() == 0)
        {
            opp.add(new Opportunity(AccountId = a.Id, Name ='First Opportunity'+a.Name, StageName ='prospecting',CloseDate =System.today()));
        }

    }
    if(opp.size()>0)
    {
        Insert opp;
    }
}
Helper Class Which Way Doing
Hello awesome developers! 

I have the following Apex class that implements an incoming Apex Email Service.  The class works 100% with no issues and I get a Custom Object record creatd and all is good.  The issue is when I attempted to create a test class for this service.  I get the lines of the email service covered but the record being created is not being covered.  This is due to in my test class below you will notice the SOQL query to bring back the custom object record that was created by the test class to assert against and there are no rows for assignment.  

Can you kindly help me update the beloe test class to cover 100% and to cover the custom object record that is being created. 

Thank you so much in advance for any help you are able to provide,

Shawn

Class:
global class SFDCIssueEmailClass implements Messaging.InboundEmailHandler {
 
  global Messaging.InboundEmailResult handleInboundEmail(Messaging.inboundEmail email, 
                                                       Messaging.InboundEnvelope env){
 
    Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
  
    String myPlainText= '';
    Group queue = [SELECT Id FROM Group WHERE Name = 'Salesforce Queue' and Type='Queue'];
                                                           
    myPlainText = email.plainTextBody;
   
    Salesforce_Issue__c[] newTask = new Salesforce_Issue__c[0];
   
    try {
      User vCon = [SELECT Id, FirstName, LastName, Email
        FROM User
        WHERE Email = :email.fromAddress
        LIMIT 1];
      
      newTask.add(new Salesforce_Issue__c(Descripton__c =  myPlainText,
           Priority__c = 'P4',
           Status__c = 'New',
           Subject__c = email.subject,
           Email_Requestor__c =  email.fromAddress,
           OwnerId = queue.Id,
           Origin__c = 'Email',
           RecordTypeId = '012q00000005mXhAAI'));
     

     insert newTask;    
     
     System.debug('New Task Object: ' + newTask );   
    }

   catch (QueryException e) {
       System.debug('Query Issue: ' + e);
   }

   result.success = true;
   
   return result;
  }
}

Test Class:
@isTest
public class SFDCIssueEmailClassTest {

    public static testMethod void EmailTest(){
        
        Contact c = new Contact(lastname = 'tested', email = 'test@test.com');
        insert c;
        
        SFDCIssueEmailClass objconfirm = new SFDCIssueEmailClass();
        Messaging.InboundEmail email = new Messaging.InboundEmail();
        email.fromAddress = c.email;
        email.subject = 'Test Subject';
        email.plainTextBody = 'my text';
          
       // objconfirm.handleInboundEmail(email, envelope);
        Messaging.InboundEnvelope envelope = new Messaging.InboundEnvelope();
        objconfirm.handleInboundEmail(email, envelope);
        Messaging.InboundEmailResult result = objconfirm.handleInboundEmail(email, envelope);
        system.assertEquals(result.success, true); 
        
        Salesforce_Issue__c[] issue = [SELECT ID FROM Salesforce_Issue__c WHERE Email_Requestor__c = :email.fromAddress];
        system.assertEquals(1, issue.size(),'Issue not inserted');
        
    }
    
}

​​​​​​​