• Marry Stein
  • NEWBIE
  • 95 Points
  • Member since 2018

  • Chatter
    Feed
  • 0
    Best Answers
  • 2
    Likes Received
  • 0
    Likes Given
  • 20
    Questions
  • 39
    Replies
Hello folks,
I recently came across the method of accessing report data via Apex. https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_analytics_report_data.htm

I find the method very interesting for a current use case. I could either access one or more reports directly and use the aggregations or go the usual way via a soql query.

Do you have an opinion on this? Do you already use the method and can you name the advantages?

Thank you very much and have a nice day,
M
 
Hello Community,

i have created a class which handles customer activities. It checks all activities within the customer relationship. A separate object (Activity Template) defines which activities should be available. If an activity is missing, the class creates a new one. If there is a unneeded activity, the class marks it as "to be deleted".  The class pushes the records in a list and do an upsert call (create new records and update unneeded record).This class will be run once a week (scheduled).

To play it save, i want to create a batch job, but this one is different from my previous ones. Normally i query all records (usallly one object) in my start method and use them in my execute methode. (Call a separate class and use the scope as parameter).

This time i have the whole logic in my separate class, which queries different objects (Tasks, Events, Opportunities), do sth with it and finaly return a list of a list of SObjects (Task and Events).

Now i wonder, what is the best way to handle this? Just call the class in my start method and use the execute methode for the upsert?
public with sharing class BatchTaskCreation implements Database.Batchable<SObject>{

    public List<SObject> start(Database.BatchableContext bc) {

    	// call method to retrieve list of sObjects

        GetActivitiesPerCustomer gapc = new GetActivitiesPerCustomer();

        return gapc.getSObjectList();
    }
    public void execute(Database.BatchableContext bc, List<SObject> scope){

        List<SObject> objectsToUpdate = scope;
        recordsProcessed = scope.size();

        // just execute the upsert 
        upsert scope;

    }
    public void finish(Database.BatchableContext bc) {
        System.debug(recordsProcessed + ' records processed');
    }
}

To sum up, GetActivitiesPerCustomer is a really complex class which queries different objects (overall less than 50k), proccess them and finally returns a list of SObjects. Because the number of records in the list is really flexible, i want to start with a batch job, make some data analysis in the next few weeks/month and plan my next steps.
Hello Community,

i have created a class which handles customer activities. It checks all activities within the customer relationship. A separate object (Activity Template) defines which activities should be available. If an activity is missing, the class creates a new one. If there is a unneeded activity, the class marks it as "to be deleted".  The class pushes the records in a list and do an upsert call (create new records and update unneeded record).This class will be run once a week (scheduled).

The problem i have is, that the number of records in the list is really flexibel. As we know, it is not possible to insert more than 10k rows within one call. A batch job should process thousands or millions of records. In our case, the number of records could be between 0 and 15000 per week. Both numbers are the extremes.

I think about different options and would appreciate you opinion:
1. create a batch job which runs once a week and accept the small number of records.
2. create a class which runs several times a week that upserts a maximum of 10000 records.  Since the job runs several times a week, capacity is divided up.  

Option 1 is more comfortable because the batch job basically takes care of all problems. Nevertheless, I tend to go for option 2, because I think you should really only use batch jobs when they are really needed.

Do you have any advice/experience? Is it ok to use a batch job for a few data sets to handle extreme cases?
Hello guys, 

some users have an issue to open a visualforce page. Sometimes, the following error occurs: 

common.apex.runtime.impl.executionexception sobject row was retrieved via soql field__c 

Its weird, because the page included the field__c and after the users tried to load it again, it works. Is it a salesforce issue > 
Hello guys, 
pretty simple, but i can not figure out, where the error comes from.  
 
public class UpdateBillingAdress {
    public static void retrieveAdress (Opportunity opp){
        Account billAcc = [
        Select 
        ShippingStreet,
        ShippingCity, 
        ShippingPostalCode,
        ShippingCountry
        FROM Account
        WHERE Id =: opp.umsatz_durch_Account__c
        ];

        Account shipAcc = [
            Select 
            BillingStreet,
            BillingCity, 
            BillingPostalCode,
            BillingCountry
            FROM Account
            WHERE Id =: opp.AccountId
        ];

        Boolean condition = (
            !String.isBlank(billAcc.ShippingStreet) &&
            !String.isBlank(billAcc.ShippingPostalCode) &&
            !String.isBlank(billAcc.ShippingCity) &&
            !String.isBlank(billAcc.ShippingCountry)
        );

        if(condition){
            shipAcc.BillingStreet = billAcc.ShippingStreet;
            shipAcc.BillingPostalCode = billAcc.ShippingPostalCode;
            shipAcc.BillingCity = billAcc.ShippingCity;
            shipAcc.BillingCountry = billAcc.ShippingCountry;
            shipAcc.alternative_Rechnungsanschrift__c = true;
            update shipAcc;
        }
    }
}
 
@isTest
public class TestUpdateBillingAdress {
    @isTest static void testUpdate(){
        Account billAcc =  DataFactory.createAccount();
        Account shipAcc =  DataFactory.createAccount();
        insert billAcc;
        insert shipAcc;
        Opportunity opp = DataFactory.createOpportunity('40 - Converted/Demo agreed', shipAcc.Id);
        opp.umsatz_durch_Account__c = billAcc.Id;
        insert opp;

        shipAcc.BillingStreet = ' ';
        shipAcc.BillingCity = ' ';
        shipAcc.BillingPostalCode = ' ';
        shipAcc.BillingCountry = ' ';
        shipAcc.alternative_Rechnungsanschrift__c = true;
        update shipAcc;

        Boolean condition = (
            !String.isBlank(billAcc.ShippingStreet) &&
            !String.isBlank(billAcc.ShippingPostalCode) &&
            !String.isBlank(billAcc.ShippingCity) &&
            !String.isBlank(billAcc.ShippingCountry)
        );
        System.debug('condition' + condition);
        UpdateBillingAdress.retrieveAdress(opp);
        System.assertEquals(shipAcc.BillingStreet, billAcc.ShippingStreet); // this should be true
    }
}

I would appreciate your help !

Thank you, 
Marry
hi guys, 

i have created a data factory class. i am struggeling to pass the stagename of the opportunity as parameter. This is my code:
 
public static Opportunity createOpportunity(String stageName, Id accountId){
        Opportunity opp = new Opportunity();
        opp.Name = 'Test';
        opp.StageName = stageName;
        opp.Type = 'Neukundengeschäft';
        opp.AccountId = accountId;
        opp.CloseDate = System.today();
        opp.z_Vertragsbeginn__c = Date.newInstance(2019, 1, 1);
        opp.z_Enddatum__c = Date.newInstance(2019, 12, 31);

        return opp;
    }
// here i pass the parameter stage1 
Opportunity opp = DataFactory.createOpportunity('stage1', acc.id);
// but this condition fails, it is null
System.assertEquals(opp.StageName, 'stage1')

I appreciate your help guys ! 
 

Greetings marry

Hi guys ! 

i am looking for a way to transfer multiple objects (Accounts, Opportunities and Tasks) to a new owner. 

I can store each object in an individual list and update the owner, but i think there should be a better solution than that. Probabily to store it in a map but can't figuare it out, how to do it. 

Greetings Marry
Hello guys,
 
i am looking for the best way to handle validation rules in apex triggers. Sometimes i want to execute some dml actions after the record is validated. 

Is it possible to query all my validation rules and extract the error condition ? i don't want to translate my validation rules into apex and i am pretty sure, that there is better way to do that.  

Another option is to translate all my validation rules into apex methodes to receive a boolean. So it would be possible to use them in classes and triggers.

I hope you will understand my concers and i am appreciate your help ! 
Hey Guys,

i dont know why, but i am not able to cover the following switch statment.
public void createPdfSections(){
        List<OpportunityLineItem> oliList = [Select Id, Name, ListPrice, TotalPrice,  Quantity,  Product2.CustomQuoteCategory__c,      
                                            ON_Produktbeschreibung_detailliert__c, Produkt__c, CustomQuoteQuantity__c,Custom_Quote_List_Price__c,
                                            Product2.family, Product2.domain__c, Product2.size__c, Product2.Subname__c,SumListPrice__c
                                            FROM OpportunityLineItem
                                            WHERE OpportunityId =:opportunityId Limit 50];

        for(OpportunityLineItem oli : oliList){
            switch on oli.Product2.CustomQuoteCategory__c { // add the prdocuts to different sections for the vf template
                when 'BAS' {
                    sectionFlat.add(oli);
                }
                when 'EMP' {
                    sectionEmployerBranding.add(oli);  
                }
                when 'PER'{
                    sectionPerformance.add(oli);  
                }
                when 'SER'{
                    sectionService.add(oli);  
                }
                when else {
                    sectionSonstiges.add(oli);
                }
            }
        }
    }
Thats my test code : 
@isTest
public class TestCreateCustomOpportunityQuote {  
    @isTest private static void TestCreateCustomOpportunityQuote(){
   
         Opportunity opp = new Opportunity ();
         opp.name = 'test';
         opp.StageName = '40 - Demo Termin vereinbart';
         opp.CloseDate = System.today();
         insert opp;
        
         PageReference testPage = Page.CustomizeOpportunityQuote;
         testPage.getParameters().put('id', opp.id);
         Test.setCurrentPage(testPage);
         ApexPages.StandardController sc = new ApexPages.StandardController(opp);
         CreateCustomOpporutnityQuote tstCtrl = new CreateCustomOpporutnityQuote(sc);
         tstCtrl.opportunityId = testPage.getParameters().get(opp.id);
        
         tstCtrl.image = 'test';
         tstCtrl.secondtext = 'test';
         tstCtrl.subject = 'test';
         tstCtrl.firsttext = 'test';
         tstCtrl.pageBreak = false;
         tstCtrl.pageBreak1 = false;
         tstCtrl.pageBreak2 = false;
         tstCtrl.pageBreak3 = false;
         tstCtrl.qDate = System.today();
     } 
        
        @testSetup static void Setup(){
            Id pricebookId = Test.getStandardPricebookId();
            
            Product2 pro = new Product2();
            pro.name = 'test';
            pro.Produktbeschreibung_detailliert__c = 'test';
            pro.Family = 'Anzeigen Flat'; 
            pro.IsActive = true;
            insert pro;
            
            Product2 pro1 = new Product2();
            pro1.name = 'test1';
            pro1.Produktbeschreibung_detailliert__c = 'test';
            pro1.Family = 'Exklusiv Logo'; 
            pro1.IsActive = true;
            insert pro1;
            
            Product2 pro2 = new Product2();
            pro2.name = 'test2';
            pro2.Produktbeschreibung_detailliert__c = 'test';
            pro2.Family = 'Top Job'; 
            pro2.IsActive = true;
            insert pro2;
            
            Product2 pro3 = new Product2();
            pro3.name = 'test3';
            pro3.Produktbeschreibung_detailliert__c = 'test';
            pro3.Family = 'Dienstleistungen'; 
            pro3.IsActive = true;
            insert pro3;
            
            Product2 pro4 = new Product2();
            pro4.name = 'test4';
            pro4.Produktbeschreibung_detailliert__c = 'test';
            pro4.Family = 'Sonstiges'; 
            pro4.IsActive = true;
            insert pro4;
                        
            PricebookEntry pEntry = new PricebookEntry (); 
            pEntry.Product2Id = pro.id;
            pEntry.UseStandardPrice = false;
            pEntry.UnitPrice = 600; 
            pEntry.Pricebook2Id = pricebookId;
            pEntry.IsActive = true;
            insert pEntry; 
            
            PricebookEntry pEntry1 = new PricebookEntry (); 
            pEntry1.Product2Id = pro1.id;
            pEntry1.UseStandardPrice = false;
            pEntry1.UnitPrice = 600; 
            pEntry1.Pricebook2Id = pricebookId;
            pEntry1.IsActive = true;
            insert pEntry1;
            
            PricebookEntry pEntry2 = new PricebookEntry (); 
            pEntry2.Product2Id = pro2.id;
            pEntry2.UseStandardPrice = false;
            pEntry2.UnitPrice = 600; 
            pEntry2.Pricebook2Id = pricebookId;
            pEntry2.IsActive = true;
            insert pEntry2;
            
            PricebookEntry pEntry3 = new PricebookEntry (); 
            pEntry3.Product2Id = pro3.id;
            pEntry3.UseStandardPrice = false;
            pEntry3.UnitPrice = 600; 
            pEntry3.Pricebook2Id = pricebookId;
            pEntry3.IsActive = true;
            insert pEntry3;
            
            PricebookEntry pEntry4 = new PricebookEntry (); 
            pEntry4.Product2Id = pro4.id;
            pEntry4.UseStandardPrice = false;
            pEntry4.UnitPrice = 600; 
            pEntry4.Pricebook2Id = pricebookId;
            pEntry4.IsActive = true;
            insert pEntry4;
        
            Account acc = new Account();
            acc.name = 'testAcc';
            acc.BillingStreet = 'testStreet';
            acc.BillingCity = 'München';
            acc.BillingPostalCode = '80331';
            acc.BillingCountry = 'Deutschland';
            acc.RecordTypeId = '012D0000000BZ8L';
            insert acc;
            
            Account acc1 = new Account();
            acc1.name = 'testAcc1';
            acc1.BillingStreet = 'testStreet';
            acc1.BillingCity = 'Brüssel';
            acc1.BillingPostalCode = '020203';
            acc1.BillingCountry = 'Belgien';
            acc1.ON_UID_Nummer__c = 'U2323232';
            acc1.RecordTypeId = '012D0000000BZ8L';
            insert acc1;
            
            // Formelfeld --> query
            Account tstAcc = [Select ON_Steuerart__c FROM Account WHERE name = 'testAcc1'];
            system.assertEquals('Nicht steuerbar (EU mit UStID-Nr.)', tstAcc.ON_Steuerart__c );

            
            Contact con = new Contact();
            con.AccountId = acc.id;
            con.FirstName = 'böser';
            con.LastName = 'Moritz';
            con.Salutation = 'Herr';
            con.Briefanrede__c = 'Sehr geehrter';
            con.Entscheider__c = true;
            insert con;
            
            Contact con1 = new Contact();
            con1.AccountId = acc1.id;
            con1.FirstName = 'netter';
            con1.LastName = 'Moritz';
            con1.Salutation = 'Herr';
            con1.Briefanrede__c = 'Sehr geehrter';
            con1.Entscheider__c = true;
            insert con1;
            
            
            Opportunity opp = new Opportunity ();
            opp.AccountId = acc.Id; 
            opp.Name = 'test';
            opp.StageName = '40 - Demo Termin vereinbart';
            opp.Override_Region__c = 'München';
            opp.CloseDate = System.today();
            opp.z_Entscheider__c = con.id;
            opp.z_Vertragsbeginn__c = system.today();
            opp.z_Enddatum__c = system.today().addDays(360);
            opp.Type = 'Bestandskundengeschäft'; 
            opp.ON_Kein_Rabatt_ausweisen__c = false; 
            insert opp;
            
            system.assertEquals('test', opp.Name);

            Opportunity opp1 = new Opportunity ();
            opp1.AccountId = acc.Id; 
            opp1.Name = 'test1';
            opp1.StageName = '40 - Demo Termin vereinbart';
            opp1.Override_Region__c = 'München';
            opp1.CloseDate = System.today();
            opp1.z_Entscheider__c = con.id;
            opp1.z_Vertragsbeginn__c = system.today();
            opp1.z_Enddatum__c = system.today().addDays(360);
            opp1.Type = 'Bestandskundengeschäft'; 
            opp1.ON_Kein_Rabatt_ausweisen__c = true; 
            insert opp1;
            
            Opportunity opp2 = new Opportunity ();
            opp2.AccountId = acc1.Id; 
            opp2.Name = 'test2';
            opp2.StageName = '40 - Demo Termin vereinbart';
            opp2.Override_Region__c = 'München';
            opp2.CloseDate = System.today();
            opp2.z_Entscheider__c = con1.id;
            opp2.z_Vertragsbeginn__c = system.today();
            opp2.z_Enddatum__c = system.today().addDays(360);
            opp2.Type = 'Bestandskundengeschäft'; 
            opp2.ON_Kein_Rabatt_ausweisen__c = true; 
            insert opp2;
            
            OpportunityLineItem oli = new OpportunityLineItem ();
            oli.TotalPrice = 500;
            oli.Produkt__c = 'test';
            oli.Quantity = 4;
            oli.OpportunityId = opp.Id;
            oli.Product2Id = pro.id;
            oli.ON_Produktbeschreibung_detailliert__c = 'test';                            
            oli.PricebookEntryId = pEntry.id;
            insert oli;
            
            OpportunityLineItem oli1 = new OpportunityLineItem ();
            oli1.TotalPrice = 600;
            oli1.Produkt__c = 'test1';
            oli1.Quantity = 4;
            oli1.OpportunityId = opp.Id;
            oli1.Product2Id = pro1.id;
            oli1.ON_Produktbeschreibung_detailliert__c = 'test';                            
            oli1.PricebookEntryId = pEntry1.id;
            insert oli1;
            
            OpportunityLineItem oli2 = new OpportunityLineItem ();
            oli2.TotalPrice = 1000;
            oli2.Produkt__c = 'test2'; 
            oli2.Quantity = 4;
            oli2.OpportunityId = opp.Id;
            oli2.Product2Id = pro2.id;
            oli2.ON_Produktbeschreibung_detailliert__c = 'test';                            
            oli2.PricebookEntryId = pEntry2.id;
            insert oli2;
            
            OpportunityLineItem oli3 = new OpportunityLineItem ();
            oli3.TotalPrice = 1000;
            oli3.Produkt__c = 'test2'; 
            oli3.Quantity = 4;
            oli3.OpportunityId = opp.Id;
            oli3.Product2Id = pro3.id;
            oli3.ON_Produktbeschreibung_detailliert__c = 'test';                            
            oli3.PricebookEntryId = pEntry3.id;
            insert oli3;
            
            OpportunityLineItem oli4 = new OpportunityLineItem ();
            oli4.TotalPrice = 1000;
            oli4.Produkt__c = 'test2'; 
            oli4.Quantity = 4;
            oli4.OpportunityId = opp.Id;
            oli4.Product2Id = pro4.id;
            oli4.ON_Produktbeschreibung_detailliert__c = 'test';                            
            oli4.PricebookEntryId = pEntry4.id;
            insert oli4;
    
        }
    
        // positiver Test
        @isTest static void testSectionGenerator(){

            Opportunity opp = [SELECT Id, Name FROM Opportunity WHERE Name = 'test' LIMIT 1]; 
            System.assertEquals(opp.name, 'test');
            List<OpportunityLineItem> testList = [Select Id, Product2.CustomQuoteCategory__c FROM OpportunityLineItem  WHERE OpportunityId =: opp.Id Limit 50];
            System.assertEquals(testList.isEmpty(), false);

            ApexPages.StandardController sc = new ApexPages.StandardController(opp);
            CreateCustomOpporutnityQuote tstCtrl = new CreateCustomOpporutnityQuote(sc);
            Test.startTest();
            tstCtrl.createPdfSections();
            List<OpportunityLineItem> bas = tstCtrl.sectionFlat;
            List<OpportunityLineItem> emp = tstCtrl.sectionEmployerBranding;
            List<OpportunityLineItem> perv = tstCtrl.sectionPerformance;
            List<OpportunityLineItem> serv = tstCtrl.sectionService;
            List<OpportunityLineItem> sons = tstCtrl.sectionSonstiges;
            Test.stopTest();
        }
}
What i am doing wrong ? The switch statment is not covered and if i call the methode, it does not create values for the list variables.  

 
Hey guys, 

i have read several articels about best practice for triggers. Most of the 'rules' are easaly to understand and logical. 

One of the rules is 'less logic trigger'. I understand that it doesn't make sense to write very complex triggers.  But in my opinion, when i have one trigger per object, at least i have to tell trigger when he needs to fire the specific classes. 

To be more specific: 

I have three classes, each of them should be fired after a specific update: 

- 1 classe creates a copy of the opportunity (fire after closed won)
- 1 class creates different tasks (fire after the owner has changed)
- 1 class for an apex callout (fire after field is updated for the first time) 
- 1 class for handle recursion

All of these classes are related to the opportunity object. So i have to create one trigger with the context variable (after update).  Sometimes i can handle the logic within the class but often i need the trigger.oldmap variable to make sure, that the trigger act like it should.

so my trigger would look sth like
trigger opptrigger on Opportunity (after update) {

for (Opportunity opp : trigger.new){

if(!HelperClassTrigger.SetOfIDs.contains(opp.Id)){

Opporuntiy oldOpp = trigger.oldMap.get(opp.Id)

if( !oldOpp.isWon && opp.isWon){
// class for copy creation
}

if( !oldOpp.OwnerId != opp.OwnerId){
// class for owner change
}

if(String.IsEmpty(oldOpp.Field__c) 
&& !String.IsEmpty(old.Field__c)){
// class for callout
}
}
}





 
Hey guys, 
i am going crazy on this testclass. In my opionion it should be very simple but it does not work. 

This is the necessary part of my class. 
public class CreateCustomOpporutnityQuote {
    // create necessary attributes 
    public Opportunity oppo {get; set;}
    public Id opportunityId {get; set;}
    public PageReference pdfQuote;

    public ID parentId {get; set;}
    // create sections  
    public List <OpportunityLineItem> sectionFlat {get;set;}
    public List <OpportunityLineItem> sectionEmployerBranding {get;set;}
    public List <OpportunityLineItem> sectionPerformance {get;set;}
    public List <OpportunityLineItem> sectionService {get;set;}
    public List <OpportunityLineItem> sectionSonstiges {get;set;}
    // variables for customization 
    public String subject {get; set;}
    public String firsttext {get; set;}
    public String secondtext {get; set;}
    public String image {get; set;}
    public Date qDate {get; set;} // Enddatum für Angebot
    // pagebreaks between sections 
    public Boolean pageBreak {get; set;}
    public Boolean pageBreak1 {get; set;}
    public Boolean pageBreak2 {get; set;}
    public Boolean pageBreak3 {get; set;}

    public CreateCustomOpporutnityQuote(ApexPages.StandardController stdController ){
        this.oppo = (Opportunity)stdController.getRecord();
        this.opportunityId = ApexPages.currentPage().getParameters().get('Id');
    }
    //create pdf sections related to prodcut quote category
    public void createPdfSections(){
        List<OpportunityLineItem> oliList = [Select Id, Name, ListPrice, TotalPrice,  Quantity,  Product2.CustomQuoteCategory__c,      
                                            ON_Produktbeschreibung_detailliert__c, Produkt__c, CustomQuoteQuantity__c,Custom_Quote_List_Price__c,
                                            Product2.family, Product2.domain__c, Product2.size__c, Product2.Subname__c,SumListPrice__c
                                            FROM OpportunityLineItem
                                            WHERE OpportunityId =:opportunityId Limit 50];
        for(OpportunityLineItem oli : oliList){
            switch on oli.Product2.CustomQuoteCategory__c { // Custom
                when 'BAS' {
                    sectionFlat.add(oli);
                    System.debug('Wenn Category gleich BAS, dann Abschnitt Basis');
                }
                when 'EMP' {
                    sectionEmployerBranding.add(oli);  
                    System.debug('Wenn Category EMP, dann Abschnitt Employer Brand');
                }
                when 'PER'{
                    sectionPerformance.add(oli);  
                    System.debug('Wenn Category PER, dann Abschnitt Performane');
                }
                when 'SER'{
                    sectionService.add(oli);  
                    System.debug('Wenn Category SER, dann Abschnitt Service');
                }
                when else {
                    sectionSonstiges.add(oli);
                    System.debug('Wenn nicht zugeordnet, dann Abschnitt Sonstiges');
                }
            }
        }
    }
so i created the following / testmethode  (i think the data setup is not necassary at this point) 
 
@isTest static void testGetOliProd(){

            Opportunity opp = [SELECT Id FROM Opportunity LIMIT 1]; 
            ApexPages.StandardController sc = new ApexPages.StandardController(opp);
            CreateCustomOpporutnityQuote tstCtrl = new CreateCustomOpporutnityQuote(sc);
            tstCtrl.opportunityId = opp.Id;
            List<OpportunityLineItem> testList = [Select Id, OpportunityId, Product2.CustomQuoteCategory__c FROM OpportunityLineItem WHERE OpportunityId =: opp.id];
            System.assertEquals(testList.size(), 5);
            List<OpportunityLineItem> bas = new List <OpportunityLineItem>();
            List<OpportunityLineItem> emp = new List <OpportunityLineItem>();
            List<OpportunityLineItem> perv = new List <OpportunityLineItem>();
            List<OpportunityLineItem> serv = new List <OpportunityLineItem>();
            List<OpportunityLineItem> sons = new List <OpportunityLineItem>();
            Test.startTest();
            tstCtrl.createPdfSections();
            bas = tstCtrl.sectionFlat; // at this point i get an null pointer exception and i don't know why :( 
       
            Test.stopTest();
        }

I would appreciate some advices . Thanks for your help and your time guys ! 
 
 
Hey guys,
i want to create a matrix table. Because there is no standard function for this case i have to create value by myself. I wonder what is the best solution for this ?  Multiple queries like option 1 or one query like in option 2 ? 
 
// Option 1

public void getIntegers(){       
        List<AggregateResult> Monday = [SELECT Count(id)cnt  From task WHERE Weekday__c = 'Monday'];	
        	mo = Integer.valueOf(Monday[0].get('cnt')); 
        List<AggregateResult> Tuesday = [SELECT Count(id)cnt  From task WHERE Weekday__c = 'Tuesday'];
        	tu = Integer.valueOf(Tuesday[0].get('cnt')); 
        List<AggregateResult> Wednesday = [SELECT Count(id)cnt  From task WHERE Weekday__c = 'Wednesday'];
        	we = Integer.valueOf(Wednesday[0].get('cnt')); 
        List<AggregateResult> Thursday = [SELECT Count(id)cnt  From task WHERE Weekday__c = 'Thursday'];
        	th = Integer.valueOf(Thursday[0].get('cnt')); 
        List<AggregateResult> Friday = [SELECT Count(id)cnt  From task WHERE Weekday__c = 'Friday'];
        	fr = Integer.valueOf(Friday[0].get('cnt')); 
    }
    
// Option 2

    public void getCalls(){
        List<Task> tskList = [SELECT Id, Weekday__c FROM Task ];
        for(task t : tskList){
            if(t.Weekday__c.equals('Monday')){
                mond = mond +1;
            } else if (t.Weekday__c.equals('Tuesday')){
                tues = tues + 1;             
            } else if (t.Weekday__c.equals('Wednesday')){
                wedn = wedn + 1;             
            } else if (t.Weekday__c.equals('Thursday')){
                thur = thur + 1;                
            } else if (t.Weekday__c.equals('Friday')){
                frid = frid + 1;  
            }
        }      
    }

 
Hey guys,
i am starting to freak out ^^  i have created multiple records in my testsetup methode. Now, i want to test my controller methode in different ways...Null, bulky, postive. I thought i have query the records i want to use in the specific test methode to test that the controller methode works like it should. 

Unfortunately, the controller methode catches all records  in my testsetup methode... 
Controller methode:
    public List<Opportunity>getOpportuntiies(){
        List <Opportunity> oppList = [SELECT Name, Account.Name, Stagename, CloseDate, z_Vertragsbeginn__c FROM Opportunity WHERE OwnerId =:UserInfo.getUserId() AND IsClosed = false AND z_Vertragsbeginn__c <= Last_Month LIMIT 100 ];
        
        numOpps = oppList.size();
        return oppList;        
    }


testsetup methode: 

 @testSetup static void setup () {
        
        Opportunity opp = new Opportunity ();
        opp.Name = 'test';
        opp.StageName = '40 - Demo Termin vereinbart';
        opp.Override_Region__c = 'München';
        opp.CloseDate = System.today();
        opp.z_Vertragsbeginn__c = System.today().addDays(-91);
        insert opp;
        
        Opportunity opp1 = new Opportunity ();
        opp1.Name = 'test';
        opp1.StageName = '40 - Demo Termin vereinbart';
        opp1.Override_Region__c = 'München';
        opp1.CloseDate = System.today();
     	opp1.z_Vertragsbeginn__c = System.today().addDays(-35);
        insert opp1;
        
        Opportunity opp2 = new Opportunity ();
        opp2.Name = 'test';
        opp2.StageName = '40 - Demo Termin vereinbart';
        opp2.Override_Region__c = 'München';
        opp2.CloseDate = System.today();
        opp2.z_Vertragsbeginn__c = System.today();
        insert opp2;
}



Null test 

@isTest static void getOpportuntiiesNull(){
        
        List<Opportunity> tstOpps = new List <Opportunity>();         
        
        tstOpps = [SELECT Name, Account.Name, Stagename, CloseDate, z_Vertragsbeginn__c 
                   FROM Opportunity WHERE OwnerId =:UserInfo.getUserId() AND IsClosed = false AND z_Vertragsbeginn__c = THIS_Month];
        
        system.assertEquals(1, tstOpps.size());
        TaskList tstCtrl = new TaskList();
        Test.startTest();
        system.assertEquals(0, tstCtrl.getOpportuntiies().size());
        Test.stopTest();
    }

 
Hey Guys, 

is there a solution to hand over the tableau server credentials through a visualforce page ?  I want to embed an iframe on a visualforce page to show a dashboard without to login. 

Greetings Marry 

Hey Guys,

i have created a controller to generate a query which summarize the monthly revenue of each user. Now, i want to create a visualforce page which shows one chart for each user.  Is there a way to do that in visualforce without to create a separate query for each user ? I don't want to customize the controller for new employees. 


Thanks for your help guys !

Greetings Marry



 

Hey experts, 

hopefully, somebody will unterstand what i want to do. I am looking for way to divide the business day in different time slots.  For each task record, i want to cluster the created date timestamp in one category.  

For example: 
hh:mm:ss to
08:00:00 to 08:15:00 = part 1
08:15:01 to 08:30:00 = part 2
08:30:01 to 08:45:00 = part 2
08:45:01 to 09:00:00 = part 4
...
17:45:01 to 18:00:00 = part 40

Why ?  iI just want to see the productivity development of each sales agent in 15 min ( or 30 min) steps and compare each other. Then, i want to create a real time dashboard which is moving forward over the day.

My first thought was,  to create three fields:

The first one, catches the time of the createdDate field:
The second one, transform the value of the first field to a number. ( 08:30:00 == 83000)
The third one, is an if statment to check, in which timeslot the number field falls. 

Firstly, this solution is not really nice and secondly it doesn't work, because the if statment exceed the character limit.  Of course i can split the if statment in many fields but this would be the worst solution  ^^  Any suggestion for this ? 

Thanks for your effort guys. 
 
Greetings Marry
 
Hey guys,

i am not familar with javascript, but i really like how the chart.js libary looks. To get started i want to create some cool Salesforce Dashboards with chart.js. I have already create a visualforce Page to show a simple bar chart. Now, i am looking for a way to get the controller variable to the javascript function : 
http://www.chartjs.org/docs/latest/

This is the javascript Code: 
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ["M1", "M2", "M3", "M4", "M5", "M6"],
        datasets: [{
            label: '# of Votes',
            data: [12, 19, 3, 5, 2, 3],   
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255,99,132,1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                }
            }]
        }
    }
});
</script>
How can i change the label and dataset with controller variables ? My idea is to create a simple list and transform the list to string. Does this work ? 

Thanks for help guys. I cant find any help for chart.js and visualforce...

Greetings,

Marry





 
Hey guys,

i want to check the new possabilitys with lightning. I am familiar with visualforce but not lightning components. I definitely will learn to create some components , but at this moment i am looking for coll "widgets". I like how the slider works and want to create one for the opportunity object to change a number or percent field. 

Does anyone have a solution for that ?  It would be great to see some cool stuff in lightning! 

Greetings Marry 
Hey Guys, 

I have created a radar chart like
http://www.infallibletechie.com/2013/12/radar-chart-using-visualforce-and-apex.html

Now, i am looking for a way create one for my needs. I want to create a radar chart, which shows me the number of contacts related to the dimension (DISC__c)

1 Dimension = Steadiness
2 Dimesnion = Dominance
3 Dimension = Influence
4 Dimenson  = conscientious

So queried the contact object to get a result like this:

DISC__C | Number or Records
Steadiness | 20
Dominance | 30
Influence | 40
conscientious | 30

So i have changed the Conroller for my needs. But, if i use the field DISC__C in my Group By statement it 
does not recognize the variable.
public class RadarChart{   

    public List<RadarData> data {get;set;}
    
    public RadarChart() {        
    data = new List<RadarData>();
        List<AggregateResult> conList = new List<AggregateResult>();
        conList = [SELECT DISC__c, Count(id)numb  FROM Contact 
                  WHERE DISC__c != Null
                  GROUP BY DISC__c];
        		
        for(AggregateResult con : conList) {
            data.add(new RadarData(con.DISC__c, con.id )); // Problem with variable DISC__c
        }
    }
    public class RadarData {
        String discName {get;set;}
        Decimal numb {get;set;}
       
        
        public RadarData(String discName, Decimal numb) {
            this.discName = discName;
            this.numb = numb;
            
        }
    }
}

Here is the page. NumberOfContacts is just a placeholder.
<apex:page sidebar="false" Controller="RadarChart" showHeader="true" id="pg">
<apex:chart height="750" width="800" legend="true" data="{!data}">
    <apex:legend position="left"/>
    <apex:axis type="Radial" position="radial">
        <apex:chartLabel />
    </apex:axis>
    <apex:radarSeries xField="discName" yField="NumberOfContacts" tips="true" opacity="0.4"/>
</apex:chart>
</apex:page>

Thanks for your help guys. I am thankful for any help in this case. It would be amazing to get this radar chart work !

Cheers,

Marry
 

Hey Guys,

i am looking for a "best practice" solution, to create a conditionally url button. The button should be placed on the standard page layout.
Related to a value of the object, the button button should redirect the user to a page.

For example, if the status is x, redirect to a new task.
if the status is y, redirect to the homepage.
if the status is z, redirect to an external page.

Unfortunately, a javascript button is not a soultion for lightning.

I have created a controller and a methode to create a conditionally PageReference for each case. I dont think that this solution is best practice. Moreover, i used simply urls like
1new PageReference('https://...............+lead.id');
what is definitely not best practise.  So my button opens the page which is fireing the action methode automatically.

Conclusion, i am looking for : 
- a solution for lightning and classic
- a button placed on the standard page layout
- the button should redirect to different pages related to a value of the object
- a more best practice solution than mine 

I appreciate your help ! 

Cheers, 
Marry
Hey guys,

i am not familar with javascript, but i really like how the chart.js libary looks. To get started i want to create some cool Salesforce Dashboards with chart.js. I have already create a visualforce Page to show a simple bar chart. Now, i am looking for a way to get the controller variable to the javascript function : 
http://www.chartjs.org/docs/latest/

This is the javascript Code: 
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ["M1", "M2", "M3", "M4", "M5", "M6"],
        datasets: [{
            label: '# of Votes',
            data: [12, 19, 3, 5, 2, 3],   
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255,99,132,1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                }
            }]
        }
    }
});
</script>
How can i change the label and dataset with controller variables ? My idea is to create a simple list and transform the list to string. Does this work ? 

Thanks for help guys. I cant find any help for chart.js and visualforce...

Greetings,

Marry





 

Hey Guys,

i am looking for a "best practice" solution, to create a conditionally url button. The button should be placed on the standard page layout.
Related to a value of the object, the button button should redirect the user to a page.

For example, if the status is x, redirect to a new task.
if the status is y, redirect to the homepage.
if the status is z, redirect to an external page.

Unfortunately, a javascript button is not a soultion for lightning.

I have created a controller and a methode to create a conditionally PageReference for each case. I dont think that this solution is best practice. Moreover, i used simply urls like
1new PageReference('https://...............+lead.id');
what is definitely not best practise.  So my button opens the page which is fireing the action methode automatically.

Conclusion, i am looking for : 
- a solution for lightning and classic
- a button placed on the standard page layout
- the button should redirect to different pages related to a value of the object
- a more best practice solution than mine 

I appreciate your help ! 

Cheers, 
Marry
Hello Community,

i have created a class which handles customer activities. It checks all activities within the customer relationship. A separate object (Activity Template) defines which activities should be available. If an activity is missing, the class creates a new one. If there is a unneeded activity, the class marks it as "to be deleted".  The class pushes the records in a list and do an upsert call (create new records and update unneeded record).This class will be run once a week (scheduled).

To play it save, i want to create a batch job, but this one is different from my previous ones. Normally i query all records (usallly one object) in my start method and use them in my execute methode. (Call a separate class and use the scope as parameter).

This time i have the whole logic in my separate class, which queries different objects (Tasks, Events, Opportunities), do sth with it and finaly return a list of a list of SObjects (Task and Events).

Now i wonder, what is the best way to handle this? Just call the class in my start method and use the execute methode for the upsert?
public with sharing class BatchTaskCreation implements Database.Batchable<SObject>{

    public List<SObject> start(Database.BatchableContext bc) {

    	// call method to retrieve list of sObjects

        GetActivitiesPerCustomer gapc = new GetActivitiesPerCustomer();

        return gapc.getSObjectList();
    }
    public void execute(Database.BatchableContext bc, List<SObject> scope){

        List<SObject> objectsToUpdate = scope;
        recordsProcessed = scope.size();

        // just execute the upsert 
        upsert scope;

    }
    public void finish(Database.BatchableContext bc) {
        System.debug(recordsProcessed + ' records processed');
    }
}

To sum up, GetActivitiesPerCustomer is a really complex class which queries different objects (overall less than 50k), proccess them and finally returns a list of SObjects. Because the number of records in the list is really flexible, i want to start with a batch job, make some data analysis in the next few weeks/month and plan my next steps.
Hello Guys
i have some requirment that there is one user ABC so if he login when he go to Quote object if that Status (picklist)is draft so he can  only edit only CollectioNumber_c(picklist) if other field  he ediit its show  should show error.
i want to do though validation ruleUser-added image
  • June 15, 2021
  • Like
  • 0
Hello Community,

i have created a class which handles customer activities. It checks all activities within the customer relationship. A separate object (Activity Template) defines which activities should be available. If an activity is missing, the class creates a new one. If there is a unneeded activity, the class marks it as "to be deleted".  The class pushes the records in a list and do an upsert call (create new records and update unneeded record).This class will be run once a week (scheduled).

The problem i have is, that the number of records in the list is really flexibel. As we know, it is not possible to insert more than 10k rows within one call. A batch job should process thousands or millions of records. In our case, the number of records could be between 0 and 15000 per week. Both numbers are the extremes.

I think about different options and would appreciate you opinion:
1. create a batch job which runs once a week and accept the small number of records.
2. create a class which runs several times a week that upserts a maximum of 10000 records.  Since the job runs several times a week, capacity is divided up.  

Option 1 is more comfortable because the batch job basically takes care of all problems. Nevertheless, I tend to go for option 2, because I think you should really only use batch jobs when they are really needed.

Do you have any advice/experience? Is it ok to use a batch job for a few data sets to handle extreme cases?
Hello guys, 

some users have an issue to open a visualforce page. Sometimes, the following error occurs: 

common.apex.runtime.impl.executionexception sobject row was retrieved via soql field__c 

Its weird, because the page included the field__c and after the users tried to load it again, it works. Is it a salesforce issue > 
Hello guys, 
pretty simple, but i can not figure out, where the error comes from.  
 
public class UpdateBillingAdress {
    public static void retrieveAdress (Opportunity opp){
        Account billAcc = [
        Select 
        ShippingStreet,
        ShippingCity, 
        ShippingPostalCode,
        ShippingCountry
        FROM Account
        WHERE Id =: opp.umsatz_durch_Account__c
        ];

        Account shipAcc = [
            Select 
            BillingStreet,
            BillingCity, 
            BillingPostalCode,
            BillingCountry
            FROM Account
            WHERE Id =: opp.AccountId
        ];

        Boolean condition = (
            !String.isBlank(billAcc.ShippingStreet) &&
            !String.isBlank(billAcc.ShippingPostalCode) &&
            !String.isBlank(billAcc.ShippingCity) &&
            !String.isBlank(billAcc.ShippingCountry)
        );

        if(condition){
            shipAcc.BillingStreet = billAcc.ShippingStreet;
            shipAcc.BillingPostalCode = billAcc.ShippingPostalCode;
            shipAcc.BillingCity = billAcc.ShippingCity;
            shipAcc.BillingCountry = billAcc.ShippingCountry;
            shipAcc.alternative_Rechnungsanschrift__c = true;
            update shipAcc;
        }
    }
}
 
@isTest
public class TestUpdateBillingAdress {
    @isTest static void testUpdate(){
        Account billAcc =  DataFactory.createAccount();
        Account shipAcc =  DataFactory.createAccount();
        insert billAcc;
        insert shipAcc;
        Opportunity opp = DataFactory.createOpportunity('40 - Converted/Demo agreed', shipAcc.Id);
        opp.umsatz_durch_Account__c = billAcc.Id;
        insert opp;

        shipAcc.BillingStreet = ' ';
        shipAcc.BillingCity = ' ';
        shipAcc.BillingPostalCode = ' ';
        shipAcc.BillingCountry = ' ';
        shipAcc.alternative_Rechnungsanschrift__c = true;
        update shipAcc;

        Boolean condition = (
            !String.isBlank(billAcc.ShippingStreet) &&
            !String.isBlank(billAcc.ShippingPostalCode) &&
            !String.isBlank(billAcc.ShippingCity) &&
            !String.isBlank(billAcc.ShippingCountry)
        );
        System.debug('condition' + condition);
        UpdateBillingAdress.retrieveAdress(opp);
        System.assertEquals(shipAcc.BillingStreet, billAcc.ShippingStreet); // this should be true
    }
}

I would appreciate your help !

Thank you, 
Marry
hi guys, 

i have created a data factory class. i am struggeling to pass the stagename of the opportunity as parameter. This is my code:
 
public static Opportunity createOpportunity(String stageName, Id accountId){
        Opportunity opp = new Opportunity();
        opp.Name = 'Test';
        opp.StageName = stageName;
        opp.Type = 'Neukundengeschäft';
        opp.AccountId = accountId;
        opp.CloseDate = System.today();
        opp.z_Vertragsbeginn__c = Date.newInstance(2019, 1, 1);
        opp.z_Enddatum__c = Date.newInstance(2019, 12, 31);

        return opp;
    }
// here i pass the parameter stage1 
Opportunity opp = DataFactory.createOpportunity('stage1', acc.id);
// but this condition fails, it is null
System.assertEquals(opp.StageName, 'stage1')

I appreciate your help guys ! 
 

Greetings marry

Hi guys ! 

i am looking for a way to transfer multiple objects (Accounts, Opportunities and Tasks) to a new owner. 

I can store each object in an individual list and update the owner, but i think there should be a better solution than that. Probabily to store it in a map but can't figuare it out, how to do it. 

Greetings Marry
Hey Guys,

i dont know why, but i am not able to cover the following switch statment.
public void createPdfSections(){
        List<OpportunityLineItem> oliList = [Select Id, Name, ListPrice, TotalPrice,  Quantity,  Product2.CustomQuoteCategory__c,      
                                            ON_Produktbeschreibung_detailliert__c, Produkt__c, CustomQuoteQuantity__c,Custom_Quote_List_Price__c,
                                            Product2.family, Product2.domain__c, Product2.size__c, Product2.Subname__c,SumListPrice__c
                                            FROM OpportunityLineItem
                                            WHERE OpportunityId =:opportunityId Limit 50];

        for(OpportunityLineItem oli : oliList){
            switch on oli.Product2.CustomQuoteCategory__c { // add the prdocuts to different sections for the vf template
                when 'BAS' {
                    sectionFlat.add(oli);
                }
                when 'EMP' {
                    sectionEmployerBranding.add(oli);  
                }
                when 'PER'{
                    sectionPerformance.add(oli);  
                }
                when 'SER'{
                    sectionService.add(oli);  
                }
                when else {
                    sectionSonstiges.add(oli);
                }
            }
        }
    }
Thats my test code : 
@isTest
public class TestCreateCustomOpportunityQuote {  
    @isTest private static void TestCreateCustomOpportunityQuote(){
   
         Opportunity opp = new Opportunity ();
         opp.name = 'test';
         opp.StageName = '40 - Demo Termin vereinbart';
         opp.CloseDate = System.today();
         insert opp;
        
         PageReference testPage = Page.CustomizeOpportunityQuote;
         testPage.getParameters().put('id', opp.id);
         Test.setCurrentPage(testPage);
         ApexPages.StandardController sc = new ApexPages.StandardController(opp);
         CreateCustomOpporutnityQuote tstCtrl = new CreateCustomOpporutnityQuote(sc);
         tstCtrl.opportunityId = testPage.getParameters().get(opp.id);
        
         tstCtrl.image = 'test';
         tstCtrl.secondtext = 'test';
         tstCtrl.subject = 'test';
         tstCtrl.firsttext = 'test';
         tstCtrl.pageBreak = false;
         tstCtrl.pageBreak1 = false;
         tstCtrl.pageBreak2 = false;
         tstCtrl.pageBreak3 = false;
         tstCtrl.qDate = System.today();
     } 
        
        @testSetup static void Setup(){
            Id pricebookId = Test.getStandardPricebookId();
            
            Product2 pro = new Product2();
            pro.name = 'test';
            pro.Produktbeschreibung_detailliert__c = 'test';
            pro.Family = 'Anzeigen Flat'; 
            pro.IsActive = true;
            insert pro;
            
            Product2 pro1 = new Product2();
            pro1.name = 'test1';
            pro1.Produktbeschreibung_detailliert__c = 'test';
            pro1.Family = 'Exklusiv Logo'; 
            pro1.IsActive = true;
            insert pro1;
            
            Product2 pro2 = new Product2();
            pro2.name = 'test2';
            pro2.Produktbeschreibung_detailliert__c = 'test';
            pro2.Family = 'Top Job'; 
            pro2.IsActive = true;
            insert pro2;
            
            Product2 pro3 = new Product2();
            pro3.name = 'test3';
            pro3.Produktbeschreibung_detailliert__c = 'test';
            pro3.Family = 'Dienstleistungen'; 
            pro3.IsActive = true;
            insert pro3;
            
            Product2 pro4 = new Product2();
            pro4.name = 'test4';
            pro4.Produktbeschreibung_detailliert__c = 'test';
            pro4.Family = 'Sonstiges'; 
            pro4.IsActive = true;
            insert pro4;
                        
            PricebookEntry pEntry = new PricebookEntry (); 
            pEntry.Product2Id = pro.id;
            pEntry.UseStandardPrice = false;
            pEntry.UnitPrice = 600; 
            pEntry.Pricebook2Id = pricebookId;
            pEntry.IsActive = true;
            insert pEntry; 
            
            PricebookEntry pEntry1 = new PricebookEntry (); 
            pEntry1.Product2Id = pro1.id;
            pEntry1.UseStandardPrice = false;
            pEntry1.UnitPrice = 600; 
            pEntry1.Pricebook2Id = pricebookId;
            pEntry1.IsActive = true;
            insert pEntry1;
            
            PricebookEntry pEntry2 = new PricebookEntry (); 
            pEntry2.Product2Id = pro2.id;
            pEntry2.UseStandardPrice = false;
            pEntry2.UnitPrice = 600; 
            pEntry2.Pricebook2Id = pricebookId;
            pEntry2.IsActive = true;
            insert pEntry2;
            
            PricebookEntry pEntry3 = new PricebookEntry (); 
            pEntry3.Product2Id = pro3.id;
            pEntry3.UseStandardPrice = false;
            pEntry3.UnitPrice = 600; 
            pEntry3.Pricebook2Id = pricebookId;
            pEntry3.IsActive = true;
            insert pEntry3;
            
            PricebookEntry pEntry4 = new PricebookEntry (); 
            pEntry4.Product2Id = pro4.id;
            pEntry4.UseStandardPrice = false;
            pEntry4.UnitPrice = 600; 
            pEntry4.Pricebook2Id = pricebookId;
            pEntry4.IsActive = true;
            insert pEntry4;
        
            Account acc = new Account();
            acc.name = 'testAcc';
            acc.BillingStreet = 'testStreet';
            acc.BillingCity = 'München';
            acc.BillingPostalCode = '80331';
            acc.BillingCountry = 'Deutschland';
            acc.RecordTypeId = '012D0000000BZ8L';
            insert acc;
            
            Account acc1 = new Account();
            acc1.name = 'testAcc1';
            acc1.BillingStreet = 'testStreet';
            acc1.BillingCity = 'Brüssel';
            acc1.BillingPostalCode = '020203';
            acc1.BillingCountry = 'Belgien';
            acc1.ON_UID_Nummer__c = 'U2323232';
            acc1.RecordTypeId = '012D0000000BZ8L';
            insert acc1;
            
            // Formelfeld --> query
            Account tstAcc = [Select ON_Steuerart__c FROM Account WHERE name = 'testAcc1'];
            system.assertEquals('Nicht steuerbar (EU mit UStID-Nr.)', tstAcc.ON_Steuerart__c );

            
            Contact con = new Contact();
            con.AccountId = acc.id;
            con.FirstName = 'böser';
            con.LastName = 'Moritz';
            con.Salutation = 'Herr';
            con.Briefanrede__c = 'Sehr geehrter';
            con.Entscheider__c = true;
            insert con;
            
            Contact con1 = new Contact();
            con1.AccountId = acc1.id;
            con1.FirstName = 'netter';
            con1.LastName = 'Moritz';
            con1.Salutation = 'Herr';
            con1.Briefanrede__c = 'Sehr geehrter';
            con1.Entscheider__c = true;
            insert con1;
            
            
            Opportunity opp = new Opportunity ();
            opp.AccountId = acc.Id; 
            opp.Name = 'test';
            opp.StageName = '40 - Demo Termin vereinbart';
            opp.Override_Region__c = 'München';
            opp.CloseDate = System.today();
            opp.z_Entscheider__c = con.id;
            opp.z_Vertragsbeginn__c = system.today();
            opp.z_Enddatum__c = system.today().addDays(360);
            opp.Type = 'Bestandskundengeschäft'; 
            opp.ON_Kein_Rabatt_ausweisen__c = false; 
            insert opp;
            
            system.assertEquals('test', opp.Name);

            Opportunity opp1 = new Opportunity ();
            opp1.AccountId = acc.Id; 
            opp1.Name = 'test1';
            opp1.StageName = '40 - Demo Termin vereinbart';
            opp1.Override_Region__c = 'München';
            opp1.CloseDate = System.today();
            opp1.z_Entscheider__c = con.id;
            opp1.z_Vertragsbeginn__c = system.today();
            opp1.z_Enddatum__c = system.today().addDays(360);
            opp1.Type = 'Bestandskundengeschäft'; 
            opp1.ON_Kein_Rabatt_ausweisen__c = true; 
            insert opp1;
            
            Opportunity opp2 = new Opportunity ();
            opp2.AccountId = acc1.Id; 
            opp2.Name = 'test2';
            opp2.StageName = '40 - Demo Termin vereinbart';
            opp2.Override_Region__c = 'München';
            opp2.CloseDate = System.today();
            opp2.z_Entscheider__c = con1.id;
            opp2.z_Vertragsbeginn__c = system.today();
            opp2.z_Enddatum__c = system.today().addDays(360);
            opp2.Type = 'Bestandskundengeschäft'; 
            opp2.ON_Kein_Rabatt_ausweisen__c = true; 
            insert opp2;
            
            OpportunityLineItem oli = new OpportunityLineItem ();
            oli.TotalPrice = 500;
            oli.Produkt__c = 'test';
            oli.Quantity = 4;
            oli.OpportunityId = opp.Id;
            oli.Product2Id = pro.id;
            oli.ON_Produktbeschreibung_detailliert__c = 'test';                            
            oli.PricebookEntryId = pEntry.id;
            insert oli;
            
            OpportunityLineItem oli1 = new OpportunityLineItem ();
            oli1.TotalPrice = 600;
            oli1.Produkt__c = 'test1';
            oli1.Quantity = 4;
            oli1.OpportunityId = opp.Id;
            oli1.Product2Id = pro1.id;
            oli1.ON_Produktbeschreibung_detailliert__c = 'test';                            
            oli1.PricebookEntryId = pEntry1.id;
            insert oli1;
            
            OpportunityLineItem oli2 = new OpportunityLineItem ();
            oli2.TotalPrice = 1000;
            oli2.Produkt__c = 'test2'; 
            oli2.Quantity = 4;
            oli2.OpportunityId = opp.Id;
            oli2.Product2Id = pro2.id;
            oli2.ON_Produktbeschreibung_detailliert__c = 'test';                            
            oli2.PricebookEntryId = pEntry2.id;
            insert oli2;
            
            OpportunityLineItem oli3 = new OpportunityLineItem ();
            oli3.TotalPrice = 1000;
            oli3.Produkt__c = 'test2'; 
            oli3.Quantity = 4;
            oli3.OpportunityId = opp.Id;
            oli3.Product2Id = pro3.id;
            oli3.ON_Produktbeschreibung_detailliert__c = 'test';                            
            oli3.PricebookEntryId = pEntry3.id;
            insert oli3;
            
            OpportunityLineItem oli4 = new OpportunityLineItem ();
            oli4.TotalPrice = 1000;
            oli4.Produkt__c = 'test2'; 
            oli4.Quantity = 4;
            oli4.OpportunityId = opp.Id;
            oli4.Product2Id = pro4.id;
            oli4.ON_Produktbeschreibung_detailliert__c = 'test';                            
            oli4.PricebookEntryId = pEntry4.id;
            insert oli4;
    
        }
    
        // positiver Test
        @isTest static void testSectionGenerator(){

            Opportunity opp = [SELECT Id, Name FROM Opportunity WHERE Name = 'test' LIMIT 1]; 
            System.assertEquals(opp.name, 'test');
            List<OpportunityLineItem> testList = [Select Id, Product2.CustomQuoteCategory__c FROM OpportunityLineItem  WHERE OpportunityId =: opp.Id Limit 50];
            System.assertEquals(testList.isEmpty(), false);

            ApexPages.StandardController sc = new ApexPages.StandardController(opp);
            CreateCustomOpporutnityQuote tstCtrl = new CreateCustomOpporutnityQuote(sc);
            Test.startTest();
            tstCtrl.createPdfSections();
            List<OpportunityLineItem> bas = tstCtrl.sectionFlat;
            List<OpportunityLineItem> emp = tstCtrl.sectionEmployerBranding;
            List<OpportunityLineItem> perv = tstCtrl.sectionPerformance;
            List<OpportunityLineItem> serv = tstCtrl.sectionService;
            List<OpportunityLineItem> sons = tstCtrl.sectionSonstiges;
            Test.stopTest();
        }
}
What i am doing wrong ? The switch statment is not covered and if i call the methode, it does not create values for the list variables.  

 
Hey guys, 

i have read several articels about best practice for triggers. Most of the 'rules' are easaly to understand and logical. 

One of the rules is 'less logic trigger'. I understand that it doesn't make sense to write very complex triggers.  But in my opinion, when i have one trigger per object, at least i have to tell trigger when he needs to fire the specific classes. 

To be more specific: 

I have three classes, each of them should be fired after a specific update: 

- 1 classe creates a copy of the opportunity (fire after closed won)
- 1 class creates different tasks (fire after the owner has changed)
- 1 class for an apex callout (fire after field is updated for the first time) 
- 1 class for handle recursion

All of these classes are related to the opportunity object. So i have to create one trigger with the context variable (after update).  Sometimes i can handle the logic within the class but often i need the trigger.oldmap variable to make sure, that the trigger act like it should.

so my trigger would look sth like
trigger opptrigger on Opportunity (after update) {

for (Opportunity opp : trigger.new){

if(!HelperClassTrigger.SetOfIDs.contains(opp.Id)){

Opporuntiy oldOpp = trigger.oldMap.get(opp.Id)

if( !oldOpp.isWon && opp.isWon){
// class for copy creation
}

if( !oldOpp.OwnerId != opp.OwnerId){
// class for owner change
}

if(String.IsEmpty(oldOpp.Field__c) 
&& !String.IsEmpty(old.Field__c)){
// class for callout
}
}
}





 
Hey guys, 
i am going crazy on this testclass. In my opionion it should be very simple but it does not work. 

This is the necessary part of my class. 
public class CreateCustomOpporutnityQuote {
    // create necessary attributes 
    public Opportunity oppo {get; set;}
    public Id opportunityId {get; set;}
    public PageReference pdfQuote;

    public ID parentId {get; set;}
    // create sections  
    public List <OpportunityLineItem> sectionFlat {get;set;}
    public List <OpportunityLineItem> sectionEmployerBranding {get;set;}
    public List <OpportunityLineItem> sectionPerformance {get;set;}
    public List <OpportunityLineItem> sectionService {get;set;}
    public List <OpportunityLineItem> sectionSonstiges {get;set;}
    // variables for customization 
    public String subject {get; set;}
    public String firsttext {get; set;}
    public String secondtext {get; set;}
    public String image {get; set;}
    public Date qDate {get; set;} // Enddatum für Angebot
    // pagebreaks between sections 
    public Boolean pageBreak {get; set;}
    public Boolean pageBreak1 {get; set;}
    public Boolean pageBreak2 {get; set;}
    public Boolean pageBreak3 {get; set;}

    public CreateCustomOpporutnityQuote(ApexPages.StandardController stdController ){
        this.oppo = (Opportunity)stdController.getRecord();
        this.opportunityId = ApexPages.currentPage().getParameters().get('Id');
    }
    //create pdf sections related to prodcut quote category
    public void createPdfSections(){
        List<OpportunityLineItem> oliList = [Select Id, Name, ListPrice, TotalPrice,  Quantity,  Product2.CustomQuoteCategory__c,      
                                            ON_Produktbeschreibung_detailliert__c, Produkt__c, CustomQuoteQuantity__c,Custom_Quote_List_Price__c,
                                            Product2.family, Product2.domain__c, Product2.size__c, Product2.Subname__c,SumListPrice__c
                                            FROM OpportunityLineItem
                                            WHERE OpportunityId =:opportunityId Limit 50];
        for(OpportunityLineItem oli : oliList){
            switch on oli.Product2.CustomQuoteCategory__c { // Custom
                when 'BAS' {
                    sectionFlat.add(oli);
                    System.debug('Wenn Category gleich BAS, dann Abschnitt Basis');
                }
                when 'EMP' {
                    sectionEmployerBranding.add(oli);  
                    System.debug('Wenn Category EMP, dann Abschnitt Employer Brand');
                }
                when 'PER'{
                    sectionPerformance.add(oli);  
                    System.debug('Wenn Category PER, dann Abschnitt Performane');
                }
                when 'SER'{
                    sectionService.add(oli);  
                    System.debug('Wenn Category SER, dann Abschnitt Service');
                }
                when else {
                    sectionSonstiges.add(oli);
                    System.debug('Wenn nicht zugeordnet, dann Abschnitt Sonstiges');
                }
            }
        }
    }
so i created the following / testmethode  (i think the data setup is not necassary at this point) 
 
@isTest static void testGetOliProd(){

            Opportunity opp = [SELECT Id FROM Opportunity LIMIT 1]; 
            ApexPages.StandardController sc = new ApexPages.StandardController(opp);
            CreateCustomOpporutnityQuote tstCtrl = new CreateCustomOpporutnityQuote(sc);
            tstCtrl.opportunityId = opp.Id;
            List<OpportunityLineItem> testList = [Select Id, OpportunityId, Product2.CustomQuoteCategory__c FROM OpportunityLineItem WHERE OpportunityId =: opp.id];
            System.assertEquals(testList.size(), 5);
            List<OpportunityLineItem> bas = new List <OpportunityLineItem>();
            List<OpportunityLineItem> emp = new List <OpportunityLineItem>();
            List<OpportunityLineItem> perv = new List <OpportunityLineItem>();
            List<OpportunityLineItem> serv = new List <OpportunityLineItem>();
            List<OpportunityLineItem> sons = new List <OpportunityLineItem>();
            Test.startTest();
            tstCtrl.createPdfSections();
            bas = tstCtrl.sectionFlat; // at this point i get an null pointer exception and i don't know why :( 
       
            Test.stopTest();
        }

I would appreciate some advices . Thanks for your help and your time guys ! 
 
 
Hey guys,
i want to create a matrix table. Because there is no standard function for this case i have to create value by myself. I wonder what is the best solution for this ?  Multiple queries like option 1 or one query like in option 2 ? 
 
// Option 1

public void getIntegers(){       
        List<AggregateResult> Monday = [SELECT Count(id)cnt  From task WHERE Weekday__c = 'Monday'];	
        	mo = Integer.valueOf(Monday[0].get('cnt')); 
        List<AggregateResult> Tuesday = [SELECT Count(id)cnt  From task WHERE Weekday__c = 'Tuesday'];
        	tu = Integer.valueOf(Tuesday[0].get('cnt')); 
        List<AggregateResult> Wednesday = [SELECT Count(id)cnt  From task WHERE Weekday__c = 'Wednesday'];
        	we = Integer.valueOf(Wednesday[0].get('cnt')); 
        List<AggregateResult> Thursday = [SELECT Count(id)cnt  From task WHERE Weekday__c = 'Thursday'];
        	th = Integer.valueOf(Thursday[0].get('cnt')); 
        List<AggregateResult> Friday = [SELECT Count(id)cnt  From task WHERE Weekday__c = 'Friday'];
        	fr = Integer.valueOf(Friday[0].get('cnt')); 
    }
    
// Option 2

    public void getCalls(){
        List<Task> tskList = [SELECT Id, Weekday__c FROM Task ];
        for(task t : tskList){
            if(t.Weekday__c.equals('Monday')){
                mond = mond +1;
            } else if (t.Weekday__c.equals('Tuesday')){
                tues = tues + 1;             
            } else if (t.Weekday__c.equals('Wednesday')){
                wedn = wedn + 1;             
            } else if (t.Weekday__c.equals('Thursday')){
                thur = thur + 1;                
            } else if (t.Weekday__c.equals('Friday')){
                frid = frid + 1;  
            }
        }      
    }

 
Hey guys,
i am starting to freak out ^^  i have created multiple records in my testsetup methode. Now, i want to test my controller methode in different ways...Null, bulky, postive. I thought i have query the records i want to use in the specific test methode to test that the controller methode works like it should. 

Unfortunately, the controller methode catches all records  in my testsetup methode... 
Controller methode:
    public List<Opportunity>getOpportuntiies(){
        List <Opportunity> oppList = [SELECT Name, Account.Name, Stagename, CloseDate, z_Vertragsbeginn__c FROM Opportunity WHERE OwnerId =:UserInfo.getUserId() AND IsClosed = false AND z_Vertragsbeginn__c <= Last_Month LIMIT 100 ];
        
        numOpps = oppList.size();
        return oppList;        
    }


testsetup methode: 

 @testSetup static void setup () {
        
        Opportunity opp = new Opportunity ();
        opp.Name = 'test';
        opp.StageName = '40 - Demo Termin vereinbart';
        opp.Override_Region__c = 'München';
        opp.CloseDate = System.today();
        opp.z_Vertragsbeginn__c = System.today().addDays(-91);
        insert opp;
        
        Opportunity opp1 = new Opportunity ();
        opp1.Name = 'test';
        opp1.StageName = '40 - Demo Termin vereinbart';
        opp1.Override_Region__c = 'München';
        opp1.CloseDate = System.today();
     	opp1.z_Vertragsbeginn__c = System.today().addDays(-35);
        insert opp1;
        
        Opportunity opp2 = new Opportunity ();
        opp2.Name = 'test';
        opp2.StageName = '40 - Demo Termin vereinbart';
        opp2.Override_Region__c = 'München';
        opp2.CloseDate = System.today();
        opp2.z_Vertragsbeginn__c = System.today();
        insert opp2;
}



Null test 

@isTest static void getOpportuntiiesNull(){
        
        List<Opportunity> tstOpps = new List <Opportunity>();         
        
        tstOpps = [SELECT Name, Account.Name, Stagename, CloseDate, z_Vertragsbeginn__c 
                   FROM Opportunity WHERE OwnerId =:UserInfo.getUserId() AND IsClosed = false AND z_Vertragsbeginn__c = THIS_Month];
        
        system.assertEquals(1, tstOpps.size());
        TaskList tstCtrl = new TaskList();
        Test.startTest();
        system.assertEquals(0, tstCtrl.getOpportuntiies().size());
        Test.stopTest();
    }