• Mohini
  • NEWBIE
  • 10 Points
  • Member since 2020

  • Chatter
    Feed
  • 0
    Best Answers
  • 1
    Likes Received
  • 0
    Likes Given
  • 18
    Questions
  • 24
    Replies
Overall, this Apex class calculates and manages MCV Amount  (MCV Line Items object )records related to OpportunityLineItems, considering proration, rate increases, and other related attributes. It provides methods for creating, updating, and deleting MCV records based on changes in OpportunityLineItems. Both are md relation with opportunity.   I have added a method to calculate MCV Amount only for a specific product and to apply discount only to this product .. Now the existing trigger is not working with the updated method or the older method ,                                                                                            Apex :
/**
 * Kartik (NeuraFlash)
 * Service Class for OpportunityProducts related functionality
 */
public with sharing class OpportunityProductService {
	

	/**
	 * Calculate the MCVs for each of the Line item for next 18 months, consider prorates
	 * @param  lineItems [The line items for which we need to calculate the MCVs]
	 * @return           [description]
	 */
	
	@testVisible
	private static PriceBook2 standardPriceBook;

	public static String calculateMCVs(List<OpportunityLineItem> lineItems) {

		List<MCVStructure> mcvs = new List<MCVStructure>();
		Set<Id> opportunityIds  = new Set<Id>();
        Set<Id> RCSOpptIds = new Set<Id>();
		Map<Id,Opportunity> opportunityMap = new Map<Id,Opportunity>();
		Map<Id,Product2> pricebookEntryToProductMap = new Map<Id,Product2>();
		Map<Id,Product2> productMap = new Map<Id,Product2>();
        List<Opportunity> RCSOpptsToUpdate = new List<Opportunity>();
        

		if (!Test.isRunningTest())
			standardPriceBook = [Select Id, Name from PriceBook2 where isStandard = true LIMIT 1];

		for (PriceBookEntry pbe : [Select Id, Product2Id, Name, Product2.Upfront_Fee__c from PriceBookEntry where PriceBook2Id = :standardPriceBook.Id]) {
			pricebookEntryToProductMap.put(pbe.Id,new Product2(Id=pbe.Product2Id,Upfront_Fee__c=pbe.Product2.Upfront_Fee__c));
		}

		for (OpportunityLineItem oli : lineItems) {
			opportunityIds.add(oli.OpportunityId);
		}
        // MV -- Added Code for RCS
        for (AggregateResult aggRes : [SELECT COUNT(ID) numRCS, OpportunityId
              FROM OpportunityLineItem
            	where Product2Id IN (select Id from Product2 where isActive =true and family IN ('Recyclers', 'CompuSafe'))
                 and OpportunityId IN :opportunityIds
					and OpportunityId not in (select Id from Opportunity where Has_RCS_Product__c = true)
              GROUP BY OpportunityId limit 200]) {
            
            Id OpportunityId = (Id) aggRes.get('OpportunityId');
            Integer numRCS = (Integer) aggRes.get('numRCS');
                  
            if (numRCS > 0)
                RCSOpptIds.add(OpportunityId);
        }

		for (Opportunity opp : [Select Id, Name, Account.Name, Account.Rate_Increase__c, Account.Rate_Increase_terms__c, Term__c, Rate_Increase_Date__c, Has_RCS_Product__c from Opportunity where Id in :opportunityIds]) {
            //MV 07-24-2019 - If it's RCS Oppt, Set the flag to true
            if (RCSOpptIds.contains(opp.Id)) 
            {
                opp.Has_RCS_Product__c=true;
                RCSOpptsToUpdate.add(opp);
            }
			opportunityMap.put(opp.Id,opp);
		}
        
        update RCSOpptsToUpdate;

		for (OpportunityLineItem oli : lineItems) {
			
			if (oli.ServiceDate == null)
				oli.ServiceDate = oli.CreatedDate.date();

			// Prepare for MCV Calculation
			Double rateIncrease 		= opportunityMap.get(oli.OpportunityId).Account.Rate_Increase__c != null ? opportunityMap.get(oli.OpportunityId).Account.Rate_Increase__c : 0;
			String rateIncreaseTerms 	= opportunityMap.get(oli.OpportunityId).Rate_Increase_Date__c != null ? opportunityMap.get(oli.OpportunityId).Rate_Increase_Date__c : 'Anniversary';
			Integer term 				= opportunityMap.get(oli.OpportunityId).Term__c != null ? Integer.valueof(opportunityMap.get(oli.OpportunityId).Term__c) : 18; 

			// If the product has Upfront Fee checked on, skip calculating MCV for term 
			// and do it only for one Service Start Date.

			if (pricebookEntryToProductMap.get(oli.PricebookEntryId).Upfront_Fee__c) {
				
				Date startingMonth 			= oli.ServiceDate.toStartOfMonth();
				MCVStructure mcv 			= new MCVStructure(oli.Id,startingMonth,oli.TotalPrice,false);
				mcv.theOpportunityId 		= oli.OpportunityId;
				mcv.accountName 			= opportunityMap.get(oli.OpportunityId).Account.Name;
				mcv.productId   			= pricebookEntryToProductMap.get(oli.PricebookEntryId).Id;
				mcv.lineItem     			= oli;
                mcv.upfrontFeeProduct		= true;
				mcvs.add(mcv);
				// Skip into the next line item. 
				continue;
			}


			// Calculate the Pro-rated if the Service Start Date is in middle of the month.
			Date startingMonth 			= oli.ServiceDate.toStartOfMonth();
			Integer daysRemaining 		= oli.ServiceDate.daysBetween(oli.ServiceDate.addMonths(+1).toStartOfMonth());
			Integer daysInMonth 		= Date.daysInMonth(oli.ServiceDate.year(),oli.ServiceDate.month());
			Decimal proratedUnitPrice 	= 0;
			
			// If Trip rate, prorate based on number of days left over in a month
			if (oli.Monthly_or_Trip_Rate__c == 'Trip') {
				DaysWrapper dWrapper = getDaysInMonth(oli.ServiceDate.year(),oli.ServiceDate.month(),oli.ServiceDate.day());
				Integer numberOfTripsInMonth = getTotalTripsInMonth(oli,dWrapper);
				proratedUnitPrice = oli.TotalPrice * numberOfTripsInMonth;
			} else {
				proratedUnitPrice = (oli.TotalPrice/daysInMonth) * daysRemaining;
			}	

			MCVStructure mcv = new MCVStructure(oli.Id,startingMonth,proratedUnitPrice,false);
			mcv.theOpportunityId = oli.OpportunityId;
			mcv.accountName = opportunityMap.get(oli.OpportunityId).Account.Name;
			mcv.productId   = pricebookEntryToProductMap.get(oli.PricebookEntryId).Id;
			mcv.lineItem     = oli;
			mcvs.add(mcv);

			// Unit Price and Rate increase
			Decimal rateIncreaseUnitPrice = oli.TotalPrice + (oli.TotalPrice * rateIncrease/100);
			Decimal rateIncreaseUnitPriceBuffer = rateIncreaseUnitPrice;
			Boolean rateIncreaseApplied = false;
			Integer termYearFiller = 12 + (12 - oli.ServiceDate.month());

			// MCV for the term.
			for (Integer i=1;i<term;i++) {
				// Reset the Unit Price.
				Decimal unitPrice = oli.TotalPrice;
				// Reset the RateIncreaseUnitPrice
				if (!rateIncreaseApplied)
					rateIncreaseUnitPrice = oli.TotalPrice + (oli.TotalPrice * rateIncrease/100);
				else
					rateIncreaseUnitPrice = rateIncreaseUnitPriceBuffer;

				// The rate increase is based on 2 options
				// Anniversary - Anniversary is straight 12 months from date of service
				// Full Year of Service - The rate increase is Jan after the full year of Service. 
				Date serviceMonth = oli.ServiceDate.addMonths(i).toStartOfMonth();
				Integer yearOfServiceMonth = oli.ServiceDate.addMonths(12).month();

				if (rateIncreaseTerms == 'Anniversary') {		
						if (i > 12) { 
							// If Trip rate, get the number of trips based on selections on Opportunity Line Item
							if (oli.Monthly_or_Trip_Rate__c == 'Trip') {
								DaysWrapper dWrapper = getDaysInMonth(serviceMonth.year(),serviceMonth.month(),serviceMonth.day());
								Integer numberOfTripsInMonth = getTotalTripsInMonth(oli,dWrapper);
								rateIncreaseUnitPrice = rateIncreaseUnitPrice * numberOfTripsInMonth;
							}

							MCVStructure mcv1 = new MCVStructure(oli.Id,serviceMonth,rateIncreaseUnitPrice,true);
							mcv1.theOpportunityId = oli.OpportunityId;
							mcv1.accountName = opportunityMap.get(oli.OpportunityId).Account.Name;
							mcv1.productId   = pricebookEntryToProductMap.get(oli.PricebookEntryId).Id;
							mcv1.lineItem     = oli;
							mcvs.add(mcv1);

							// Compound Calculation update the rateIncrease
							if (Math.mod(i,12) == 0) {
								Integer termYear = i/12;
								rateIncreaseUnitPriceBuffer = rateIncreaseUnitPriceBuffer + (rateIncreaseUnitPriceBuffer * rateIncrease/100);
								rateIncreaseApplied = true;
							}
							// Skip into next term
							continue;
						}
				} else if (i > (12 + (12 - yearOfServiceMonth))) {
							
						// If Trip rate, get the number of trips based on selections on Opportunity Line Item
							if (oli.Monthly_or_Trip_Rate__c == 'Trip') {
								DaysWrapper dWrapper = getDaysInMonth(serviceMonth.year(),serviceMonth.month(),serviceMonth.day());
								Integer numberOfTripsInMonth = getTotalTripsInMonth(oli,dWrapper);
								rateIncreaseUnitPrice = rateIncreaseUnitPrice * numberOfTripsInMonth;
							}

							MCVStructure mcv1 = new MCVStructure(oli.Id,serviceMonth,rateIncreaseUnitPrice,true);
							mcv1.theOpportunityId = oli.OpportunityId;
							mcv1.accountName = opportunityMap.get(oli.OpportunityId).Account.Name;
							mcv1.productId   = pricebookEntryToProductMap.get(oli.PricebookEntryId).Id;
							mcv1.lineItem     = oli;
							mcvs.add(mcv1);
							
							// Compound Calculation, for 1st of Jan, the rate increase is applied 1 full year after the service
							// start date, so make sure the rate increase applies only after 2 terms. (1st term is already calculated
							// above)
							// Term year filler always ends on December. The next iteration is a January when the rate increase
							// needs to be applied.
							if (i == (termYearFiller + 12)) {
								rateIncreaseUnitPriceBuffer = rateIncreaseUnitPriceBuffer + (rateIncreaseUnitPriceBuffer * rateIncrease/100);
								rateIncreaseApplied = true;
								termYearFiller = termYearFiller + 12;
							}
							// Skip into next term
							continue;
				}


				// If Trip rate, get the number of trips based on selections on Opportunity Line Item
				if (oli.Monthly_or_Trip_Rate__c == 'Trip') {
					DaysWrapper dWrapper = getDaysInMonth(serviceMonth.year(),serviceMonth.month(),serviceMonth.day());
					Integer numberOfTripsInMonth = getTotalTripsInMonth(oli,dWrapper);
					unitPrice = unitPrice * numberOfTripsInMonth;
				}

				MCVStructure mcv1 = new MCVStructure(oli.Id,serviceMonth,unitPrice,false);
				mcv1.theOpportunityId = oli.OpportunityId;
				mcv1.accountName = opportunityMap.get(oli.OpportunityId).Account.Name;
				mcv1.productId   = pricebookEntryToProductMap.get(oli.PricebookEntryId).Id;
				mcv1.lineItem     = oli;
				mcvs.add(mcv1);
			}

		}

		createMCVs(mcvs,true); // Create the MCV Records

		return json.serializePretty(mcvs);

	}
    
    public static void calculateMcvAmountBluebeam(set<Id> olId){
        system.debug(olId);
        system.debug('inside function bluebeam');
        List<MCV_Line_Items__c> MLI=[select id,Discount__c,	MCV_Amount__c,Opportunity_Line_Item__c,Opportunity_Line_Item__r.UnitPrice  from MCV_Line_Items__c where Opportunity_Product_Id__c in:olId];
    	system.debug('mcv list'+MLI);  
        List<MCV_Line_Items__c> MLItoUpdate=new list<MCV_Line_Items__c>();
        for(MCV_Line_Items__c ml:MLI){
            if(ml.Discount__c==NULL)
            {
             Decimal disc= 0 * ml.MCV_Amount__c ;
            disc=disc/100;
            system.debug(disc);
            ml.MCV_Amount__c=ml.MCV_Amount__c- disc;
            system.debug(ml.MCV_Amount__c);
            MLItoUpdate.add(ml);
            }
            system.debug('inside for loop to update amount');
            Decimal disc=ml.Discount__c * ml.MCV_Amount__c ;
            disc=disc/100;
            system.debug(disc);
            ml.MCV_Amount__c=ml.MCV_Amount__c- disc;
            system.debug(ml.MCV_Amount__c);
            MLItoUpdate.add(ml);
        }
    update MLItoUpdate;
    }

	/**
	 * Delete the MCV's if the lineitems are deleted.
	 * @param lineItems Opportunity Line Items.
	 */
	public static void deleteMCVs(List<OpportunityLineItem> lineItems) {

		List<MCV_Line_Items__c> mcvLineItems = new List<MCV_Line_Items__c>();
        List<Opportunity> RCSOpptsToUpdate = new List<Opportunity>();
		
		Set<Id> lineItemIds = new Set<Id>();
        Set<Id> RCSOpptIds = new Set<Id>();
		
		for (OpportunityLineItem oli : lineItems) {
			lineItemIds.add(oli.Id);
            
		}

		mcvLineItems = [Select Id from MCV_Line_Items__c where Opportunity_Product_Id__c IN :lineItemIds];
        
        for (AggregateResult aggRes : [SELECT COUNT(ID) numRCS, OpportunityId
              FROM OpportunityLineItem
            	where Product2Id IN (select Id from Product2 where isActive =true and family IN ('Recyclers', 'CompuSafe'))
                 and Id IN :lineItemIds
					and OpportunityId not in (select Id from Opportunity where Has_RCS_Product__c = true)
              GROUP BY OpportunityId limit 200]) {
            
            Id OpportunityId = (Id) aggRes.get('OpportunityId');
            Integer numRCS = (Integer) aggRes.get('numRCS');
                  
            if (numRCS > 0)
                RCSOpptIds.add(OpportunityId);
        }
        
        if (RCSOpptIds.size() > 0)
        {
            RCSOpptsToUpdate = [Select Id, Has_RCS_Product__c from Opportunity where Id IN :RCSOpptIds];
            for (integer i=0;i<RCSOpptsToUpdate.size(); i++) {
                RCSOpptsToUpdate[i].Has_RCS_Product__c = true;
            }
            update RCSOpptsToUpdate;
        }

		delete mcvLineItems;

	}

	public static List<MCV_Line_Items__c> createMCVs(List<MCVStructure> mcvs, Boolean doInsert) {
		
		List<MCV_Line_Items__c> items = new List<MCV_Line_Items__c>();
		
		for (MCVStructure mcv : mcvs) {
			MCV_Line_Items__c lineItem = new MCV_Line_Items__c();
			lineItem.Date__c = mcv.theMonth;
			lineItem.MCV_Amount__c = mcv.mcvAmount;
			lineItem.Opportunity__c = mcv.theOpportunityId;
			lineItem.Opportunity_Product_Id__c = mcv.lineItem.Id;
			lineItem.Rate_Increase_Applied__c = mcv.hasRateIncreaseApplied;
			lineItem.Product__c = mcv.productId;
			lineItem.ATM_Deposit_Processing__c = mcv.lineItem.ATM_Deposit_Processing__c;
			lineItem.BDEX__c = mcv.lineItem.BDEX__c;
			lineItem.Brink_s_24x7_App__c = mcv.lineItem.Brink_s_24x7_App__c;
			lineItem.Cash_Forecasting__c = mcv.lineItem.Cash_Forecasting__c;
			lineItem.Cash_Vault_Services__c = mcv.lineItem.Cash_Vault_Services__c;
			lineItem.Cellular_Communication__c = mcv.lineItem.Cellular_Communication__c;
			lineItem.Cellular_Connectivity__c = mcv.lineItem.Cellular_Connectivity__c;
			lineItem.Check_Imaging__c = mcv.lineItem.Check_Imaging__c;
			lineItem.Coin_Processing__c = mcv.lineItem.Coin_Processing__c;
			lineItem.Coin__c = mcv.lineItem.Coin__c;
			lineItem.Conjunctive__c = mcv.lineItem.Conjunctive__c;
			lineItem.Customer_Success_Single_POC__c = mcv.lineItem.Customer_Success_Single_POC__c;
			lineItem.Daily_Credit_Bundle__c = mcv.lineItem.Daily_Credit_Bundle__c;
			lineItem.Daily_Credit__c = mcv.lineItem.Daily_Credit__c;
			lineItem.Device_Dashboard__c = mcv.lineItem.Device_Dashboard__c;
			lineItem.Enhanced_Service_Guarantee__c = mcv.lineItem.Enhanced_Service_Guarantee__c;
			lineItem.Envelope_Drop_Package__c = mcv.lineItem.Envelope_Drop_Package__c;
			lineItem.FI__c = mcv.lineItem.FI__c;
			lineItem.Inventory_Management__c = mcv.lineItem.Inventory_Management__c;
			lineItem.Location__c = mcv.lineItem.Location__c;
			lineItem.Monthly_or_Trip_Rate__c = mcv.lineItem.Monthly_or_Trip_Rate__c;
			lineItem.Retail__c = mcv.lineItem.Retail__c;
			lineItem.SmartDrop_Box__c = mcv.lineItem.SmartDrop_Box__c;
			lineItem.Standard_Warranty__c = mcv.lineItem.Standard_Warranty__c;
			lineItem.Trip_Rate_if_applicable__c = mcv.lineItem.Trip_Rate_if_applicable__c;
			lineItem.Web_based_Reporting_iInfo__c = mcv.lineItem.Web_based_Reporting_iInfo__c;
            lineItem.Upfront_Fee_Product__c = mcv.upfrontFeeProduct;
			items.add(lineItem);
		}
		
		//system.debug(items);

		if (doInsert)
			insert items;
		
		return items; 
				
	}

	public static Integer getTotalTripsInMonth(OpportunityLineItem oli, DaysWrapper dWrapper) {
		
		Integer totalTrips = 0;
		
		if (oli.Frequency__c == 'Monthly') {
				totalTrips = oli.SUN__c != null && oli.SUN__c && dWrapper.numberOfSundays > 0 ? totalTrips + 1 : totalTrips;
				totalTrips = oli.MON__c != null && oli.MON__c && dWrapper.numberOfMondays > 0 ? totalTrips + 1 : totalTrips;
				totalTrips = oli.TUES__c != null && oli.TUES__c && dWrapper.numberOfTuesdays > 0 ? totalTrips + 1 : totalTrips;
				totalTrips = oli.WED__c != null && oli.WED__c && dWrapper.numberOfWednesdays > 0 ? totalTrips + 1: totalTrips;
				totalTrips = oli.THURS__c != null && oli.THURS__c && dWrapper.numberOfThursdays > 0 ? totalTrips + 1: totalTrips;
				totalTrips = oli.FRI__c != null && oli.FRI__c && dWrapper.numberOfFridays > 0 ? totalTrips + 1 : totalTrips;
				totalTrips = oli.SAT__c != null && oli.SAT__c && dWrapper.numberOfSaturdays > 0 ? totalTrips + 1 : totalTrips;				
			} else {
				totalTrips = oli.SUN__c != null && oli.SUN__c ? totalTrips + dWrapper.numberOfSundays : totalTrips;
				totalTrips = oli.MON__c != null && oli.MON__c ? totalTrips + dWrapper.numberOfMondays : totalTrips;
				totalTrips = oli.TUES__c != null && oli.TUES__c ? totalTrips + dWrapper.numberOfTuesdays : totalTrips;
				totalTrips = oli.WED__c != null && oli.WED__c ? totalTrips + dWrapper.numberOfWednesdays : totalTrips;
				totalTrips = oli.THURS__c != null && oli.THURS__c ? totalTrips + dWrapper.numberOfThursdays : totalTrips;
				totalTrips = oli.FRI__c != null && oli.FRI__c ? totalTrips + dWrapper.numberOfFridays : totalTrips;
				totalTrips = oli.SAT__c != null && oli.SAT__c ? totalTrips + dWrapper.numberOfSaturdays : totalTrips;			
			}

			if (oli.Frequency__c == 'EOW')
				totalTrips = totalTrips/2;
		

		return totalTrips;
	}

	public static DaysWrapper getDaysInMonth(Integer year, Integer month, Integer dayOfMonth) {
		
		if (dayOfMonth == null)
			dayOfMonth = 1;

		DaysWrapper dWrapper = new DaysWrapper(year, month, dayOfMonth);
		Datetime monthStartDate = Datetime.newInstance(year, month, dayOfMonth);
		
		while (month == monthStartDate.month()) {	
		
			String day = monthStartDate.format('EEE');
			
			if (day == 'SUN')
				dWrapper.numberOfSundays += 1;
			if (day == 'MON')
				dWrapper.numberOfMondays += 1;
			if (day == 'TUE')
				dWrapper.numberOfTuesdays += 1;
			if (day == 'WED')
				dWrapper.numberOfWednesdays += 1;
			if (day == 'THU')
				dWrapper.numberOfThursdays += 1;
			if (day == 'FRI')
				dWrapper.numberOfFridays += 1;					
			if (day == 'SAT')
				dWrapper.numberOfSaturdays += 1;

			monthStartDate = monthStartDate.addDays(1);	
		}						

		return dWrapper;	
	}


	public class DaysWrapper {
		
		public Integer year;
		public Integer month;
		public Integer dayOfMonth;
		public Integer numberOfSundays;
		public Integer numberOfMondays;
		public Integer numberOfTuesdays;
		public Integer numberOfWednesdays;
		public Integer numberOfThursdays;
		public Integer numberOfFridays;
		public Integer numberOfSaturdays;

		public DaysWrapper(Integer year, Integer month, Integer dayOfMonth) {
			this.year = year;
			this.month = month; 
			this.dayOfMonth = dayOfMonth;
			this.numberOfSundays = 0;
			this.numberOfMondays = 0;
			this.numberOfTuesdays = 0;
			this.numberOfWednesdays = 0;
			this.numberOfThursdays = 0;
			this.numberOfFridays = 0;
			this.numberOfSaturdays = 0;
		}
	}

	public class MCVStructure {
		public OpportunityLineItem lineItem     {get;set;}
		public Id theOpportunityLineItemId 		{get;set;}
		public Id theOpportunityId 				{get;set;}
		public String accountName				{get;set;}
		public Id productId						{get;set;}
		public Date theMonth 					{get;set;}
		public Decimal mcvAmount 				{get;set;}
		public Boolean hasRateIncreaseApplied 	{get;set;}
        public Boolean upfrontFeeProduct	 	{get;set;}

		public MCVStructure (Id theOpportunityLineItemId, Date theMonth, Decimal mcvAmount, Boolean hasRateIncreaseApplied) {
			this.theOpportunityLineItemId = theOpportunityLineItemId;
			this.theMonth = theMonth;
			this.mcvAmount = mcvAmount;
			this.hasRateIncreaseApplied = hasRateIncreaseApplied;
            this.upfrontFeeProduct = false;
		}
	}

}
 
Apex Trigger:
/**
 * Created by Kartik (NeuraFlash)
 * Apex Trigger to create MCV line items
 */
trigger OpportunityProductTrigger on OpportunityLineItem (after insert, after update, before delete) {
    //system.debug('inside trigger, loop ahead');
    set<id> OLID=new set<Id>();
    integer i=0;
    for(OpportunityLineItem Oli:trigger.new ){
        
        if(Oli.ProductCode=='Blubeem'&& oli.UnitPrice != null){
            system.debug('inside trigger bluebeem product');
            OLID.add(Oli.Id);
            i=1;
        }
    }
    
	
    if (Trigger.isInsert && Trigger.isAfter) {
          
        // Call the service class to create MCV Records
        OpportunityProductService.calculateMCVs(trigger.new);
        if(i==1){
        system.debug('calling function for blue beam');
        OpportunityProductService.calculateMcvAmountBluebeam(OLID);}
    system.debug('inside After insert');
        system.debug(trigger.new);
    } 
    
    else if (Trigger.isUpdate && Trigger.isAfter) {
         
        // Delete the existing MCVs
        OpportunityProductService.deleteMCVs(trigger.new);
        // Create new ones
       
        OpportunityProductService.calculateMCVs(trigger.new);
         if(i==1){
        system.debug('calling function for blue beam');
        OpportunityProductService.calculateMcvAmountBluebeam(OLID);
          }
    system.debug('inside After update');
    }
    
     
    else if (Trigger.isDelete) {
        system.debug('inside Delete');
        OpportunityProductService.deleteMCVs(trigger.old);
    }
    
   /* if(i==1){
        system.debug('calling function for blue beam');
        OpportunityProductService.calculateMcvAmountBluebeam(OLID);}*/
    
    }
 
New Method Implemented :
public static void calculateMcvAmountBluebeam(set<Id> olId){
        system.debug(olId);
        system.debug('inside function bluebeam');
        List<MCV_Line_Items__c> MLI=[select id,Discount__c,	MCV_Amount__c,Opportunity_Line_Item__c,Opportunity_Line_Item__r.UnitPrice  from MCV_Line_Items__c where Opportunity_Product_Id__c in:olId];
    	system.debug('mcv list'+MLI);  
        List<MCV_Line_Items__c> MLItoUpdate=new list<MCV_Line_Items__c>();
        for(MCV_Line_Items__c ml:MLI){
            if(ml.Discount__c==NULL)
            {
             Decimal disc= 0 * ml.MCV_Amount__c ;
            disc=disc/100;
            system.debug(disc);
            ml.MCV_Amount__c=ml.MCV_Amount__c- disc;
            system.debug(ml.MCV_Amount__c);
            MLItoUpdate.add(ml);
            }
            system.debug('inside for loop to update amount');
            Decimal disc=ml.Discount__c * ml.MCV_Amount__c ;
            disc=disc/100;
            system.debug(disc);
            ml.MCV_Amount__c=ml.MCV_Amount__c- disc;
            system.debug(ml.MCV_Amount__c);
            MLItoUpdate.add(ml);
        }
    update MLItoUpdate;
    }

Please help me with trigger to calculate  to calculate dicount for mcv amount only for blubeem products , for create , update and delete .. The prorate should work .
  • August 06, 2023
  • Like
  • 0
1.If opportunity record is closed dont make any change 
2. Opportunity is parent and sub object is child (lookup). Once any of the sub record stage is closed won , the field of sub (Revenue , cost and probability) gets copied to the parent opportunity
class : 

global class UserReport implements Database.Batchable<SObject>, Database.AllowsCallouts, Database.Stateful {
  global  blob MyBlob;
    Set<String> nums = new Set<String>{'1%','2%','3%','4%','5%','6%','7%','8%','9%'};
   public List<String> searchstring = new List<String> {'Sales Manager','Sales User'};
    private List<String> fieldNames = new List<String> {
         'Name', 'Registry_ID_EBS__c','OwnerId', 'Owner.Email', 'Owner.IsActive'
    };
      
     global String csvContent = '';
                
    global Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator([Select Id, Name, Registry_ID_EBS__c, OwnerId, Owner.Email, Owner.IsActive,Owner.profile.Name From Account where Owner.profile.Name IN ('Sales Manager', 'Sales User') AND Registry_ID_EBS__c like :nums ]);
    }
    
    global void execute(Database.BatchableContext context, List<Account> records) {
        Map<Id, User> owners = new Map<Id, User>();
        for (Account record : records) {
            owners.put(record.OwnerId, null);
        }
        owners.remove(null);
        owners.putAll([Select Id, Name, Email, IsActive From User Where Id IN :owners.keySet()]);
        
       /*
        for (String fieldName : fieldNames) {
            if (fieldName == 'OwnerId') {
                csvContent += '"Owner Name",';
            } else if (fieldName == 'Owner.Email') {
                csvContent += '"Owner Email",';
            } else if (fieldName == 'Owner.IsActive') {
                csvContent += '"Owner Active",';
            } else {
                csvContent += '"' + fieldName + '"' + ',';
            }
        }
        csvContent += '\n';*/
        for (Account record : records) {
            for (String fieldName : fieldNames) {
                if (fieldName == 'OwnerId') {
                    String ownerName = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerName = String.valueOf(owners.get(record.OwnerId).Name).replace('"', '""');
                    }
                    csvContent += '"' + ownerName + '"' + ',';
                } else if (fieldName == 'Owner.Email') {
                    String ownerEmail = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerEmail = String.valueOf(owners.get(record.OwnerId).Email).replace('"', '""');
                    }
                    csvContent += '"' + ownerEmail + '"' + ',';
                } else if (fieldName == 'Owner.IsActive') {
                    String ownerIsActive = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerIsActive = String.valueOf(owners.get(record.OwnerId).IsActive).replace('"', '""');
                    }
                    csvContent += '"' + ownerIsActive + '"' + ',';
                } else {
                    Object fieldValueObj = record.get(fieldName);
                    if (fieldValueObj != null) {
                        String fieldValue = String.valueOf(fieldValueObj).replace('"', '""');
                        csvContent += '"' + fieldValue + '"' + ',';
                    } else {
                        csvContent += ',';
                    }
                }
            }
            csvContent += '\n';
           //system.debug('csvContent'+csvContent);
        }
        String Header = 'Customer Name, EBS Registry Id, Account Owner, Account Owner Email, Account Owner IsActive';
        String FinalcsvContent = Header + '\n' + csvContent ;
        MyBlob = blob.valueOf(FinalcsvContent); 
        system.debug('MyBlob1'+FinalcsvContent);

    }

   global void finish(Database.BatchableContext context) {
        system.debug('MyBlob2'+MyBlob);
    String emailAddress1 = 'mousumi.chatterjee@continuserve.com';
    Messaging.EmailFileAttachment csvAttachment = new Messaging.EmailFileAttachment();
    String myName = 'AccountList.csv';
    csvAttachment.setFileName(myName);
    csvAttachment.setBody(MyBlob);
       csvAttachment.setContentType('application/csv');
       system.debug('ss'+MyBlob);
    Messaging.SingleEmailMessage myEmail = new Messaging.SingleEmailMessage();
    String[] toAddresses = new String[]{emailAddress1};
    String subject = 'UserID and List CSV';
    myEmail.setSubject(subject);
    myEmail.setToAddresses(toAddresses);
    myEmail.setPlainTextBody('User Alias Report');
    myEmail.setHtmlBody('Hi All'+','+'</br><br/>'+ 'Please find attached the sales user detail report from Salesforce production CRM.' +'</br><br/'+'Thanks'+','+'</br>'+'Brinks Team');
   Messaging.EmailFileAttachment[] attachments = new Messaging.EmailFileAttachment[]{csvAttachment};
myEmail.setFileAttachments(attachments);

    Messaging.SendEmailResult[] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[]{myEmail});
}
}



 test class - 42%


@isTest
public class TestUserReport {
static String str = 'Name,Registry_ID_EBS__c,OwnerId,Owner.Email,Owner.IsActive \n';       

    public static String[] csvFileLines;
    public static Blob csvFileBody;

    static testmethod void testfileupload(){
        Test.startTest();       
        csvFileBody = Blob.valueOf(str);
        String csvAsString = csvFileBody.toString();
        csvFileLines = csvAsString.split('\n'); 

       UserReport result = new UserReport();
       
       // result .csvAttachment();
        Test.stopTest();
    } 

    static testmethod void testfileuploadNegative(){
        Test.startTest();       
        csvFileBody = Blob.valueOf(str);
        String csvAsString = csvFileBody.toString();
        csvFileLines = csvAsString.split('\n'); 

     UserReport result = new UserReport();
       Id batchJobId = Database.executeBatch(new UserReport(), 200);
        Test.stopTest();
    }
}
  • March 27, 2023
  • Like
  • 0
The batch apex is sending account details as attachment and sending email and the test class is only covering 37% .Please helo me to get 75% code coverage
Apex Class:
global class UserReport implements Database.Batchable<SObject>, Database.AllowsCallouts, Database.Stateful {
  global  blob MyBlob;
   public List<String> searchstring = new List<String> {'Sales Manager','Sales User'};
    private List<String> fieldNames = new List<String> {
        'Id', 'Name', 'Registry_ID_EBS__c','OwnerId', 'Owner.Email', 'Owner.IsActive'
    };
      
     global String csvContent = '';
                
    global Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator([Select Id, Name, Registry_ID_EBS__c, OwnerId, Owner.Email, Owner.IsActive,Owner.profile.Name From Account where Owner.profile.Name IN ('Sales Manager', 'Sales User') ]);
    }
    
    global void execute(Database.BatchableContext context, List<Account> records) {
        Map<Id, User> owners = new Map<Id, User>();
        for (Account record : records) {
            owners.put(record.OwnerId, null);
        }
        owners.remove(null);
        owners.putAll([Select Id, Name, Email, IsActive From User Where Id IN :owners.keySet()]);
        
       
        for (String fieldName : fieldNames) {
            if (fieldName == 'OwnerId') {
                csvContent += '"Owner Name",';
            } else if (fieldName == 'Owner.Email') {
                csvContent += '"Owner Email",';
            } else if (fieldName == 'Owner.IsActive') {
                csvContent += '"Owner Active",';
            } else {
                csvContent += '"' + fieldName + '"' + ',';
            }
        }
        csvContent += '\n';
        for (Account record : records) {
            for (String fieldName : fieldNames) {
                if (fieldName == 'OwnerId') {
                    String ownerName = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerName = String.valueOf(owners.get(record.OwnerId).Name).replace('"', '""');
                    }
                    csvContent += '"' + ownerName + '"' + ',';
                } else if (fieldName == 'Owner.Email') {
                    String ownerEmail = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerEmail = String.valueOf(owners.get(record.OwnerId).Email).replace('"', '""');
                    }
                    csvContent += '"' + ownerEmail + '"' + ',';
                } else if (fieldName == 'Owner.IsActive') {
                    String ownerIsActive = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerIsActive = String.valueOf(owners.get(record.OwnerId).IsActive).replace('"', '""');
                    }
                    csvContent += '"' + ownerIsActive + '"' + ',';
                } else {
                    Object fieldValueObj = record.get(fieldName);
                    if (fieldValueObj != null) {
                        String fieldValue = String.valueOf(fieldValueObj).replace('"', '""');
                        csvContent += '"' + fieldValue + '"' + ',';
                    } else {
                        csvContent += ',';
                    }
                }
            }
            csvContent += '\n';
           //system.debug('csvContent'+csvContent);
        }
        MyBlob = blob.valueOf(csvContent); 
          system.debug('MyBlob1'+MyBlob);

    }

   global void finish(Database.BatchableContext context) {
        system.debug('MyBlob2'+MyBlob);
    String emailAddress1 = 'selvin.paul@continuserve.com';
    Messaging.EmailFileAttachment csvAttachment = new Messaging.EmailFileAttachment();
    String myName = 'AccountList.csv';
    csvAttachment.setFileName(myName);
    csvAttachment.setBody(MyBlob);
       csvAttachment.setContentType('application/csv');
       system.debug('ss'+MyBlob);
    Messaging.SingleEmailMessage myEmail = new Messaging.SingleEmailMessage();
    String[] toAddresses = new String[]{emailAddress1};
    String subject = 'UserID and List CSV';
    myEmail.setSubject(subject);
    myEmail.setToAddresses(toAddresses);
    myEmail.setPlainTextBody('User Alias Report');
    myEmail.setHtmlBody('Hi All'+','+'</br><br/>'+ 'Please find attached the sales user detail report from Salesforce production CRM.' +'</br><br/'+'Thanks'+','+'</br>'+'Brinks Team');
   Messaging.EmailFileAttachment[] attachments = new Messaging.EmailFileAttachment[]{csvAttachment};
myEmail.setFileAttachments(attachments);

    Messaging.SendEmailResult[] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[]{myEmail});
}
}
Test Class:

@isTest
public class UserReportTest {
static String str = 'Name,Registry_ID_EBS__c,OwnerId,Owner.Email,Owner.IsActive \n';       

    public static String[] csvFileLines;
    public static Blob csvFileBody;

    static testmethod void testfileupload(){
        Test.startTest();       
        csvFileBody = Blob.valueOf(str);
        String csvAsString = csvFileBody.toString();
        csvFileLines = csvAsString.split('\n'); 

       UserReport result = new UserReport();
       
       // result .csvAttachment();
        Test.stopTest();
    } 

    static testmethod void testfileuploadNegative(){
        Test.startTest();       
        csvFileBody = Blob.valueOf(str);
        String csvAsString = csvFileBody.toString();
        csvFileLines = csvAsString.split('\n'); 

     UserReport result = new UserReport();
       Id batchJobId = Database.executeBatch(new UserReport(), 200);
        Test.stopTest();
    }
}
  • March 17, 2023
  • Like
  • 0
My trigger is working good for autopopulationg Account Id field  when account lookup field  is selected, But it is not letting me  update a record .
For example if  the account is stephan , it does not updates to Luke when updated and saves older value . Please help me with what is wrong here.

trigger LeadTriggerPardot on Lead (before insert,before update) {
    
    List<String> Ids = new List<String>();
    List<Account> accounts = new List<Account>();
    Map<String,Id> mapAccount = new Map<String,Id>();
    List<String> AccIds = new List<String>();
    List<Account> acc = new List<Account>();
    Map<Id,String> mapAcc = new Map<Id,String>();
   
    Id leadRecordTypeId = Schema.SObjectType.Lead.getRecordTypeInfosByName().get('lead2.4').getRecordTypeId();
    Id leadRecordTypeId1 = Schema.SObjectType.Lead.getRecordTypeInfosByName().get('Inside Sales').getRecordTypeId();
    for(Lead o : trigger.new){
     if(o.PartnerID__c !=null){
        Ids.add(o.PartnerID__c);
    } }
    for(Account a : [SELECT Id, PartnerID__c, Name FROM Account WHERE PartnerID__c IN :Ids]){
    
    mapAccount.put(a.PartnerID__c, a.Id);
     
    }
     for(Lead o : trigger.new){

        AccIds.add(o.Partner_Account_24__c);
    } 
    for(Account a : [SELECT Id, PartnerID__c, Name FROM Account WHERE Id IN :AccIds]){
    
    mapAcc.put(a.Id,a.PartnerID__c);
     
    }
   
    for(Lead l:  trigger.new){
    if(l.RecordTypeId == leadRecordTypeId || l.RecordTypeId==leadRecordTypeId1){
       if(l.PartnerID__c!=null){
           if( mapAccount.containsKey(l.PartnerID__c))
           {
            l.Partner_Account_24__c = mapAccount.get(l.PartnerID__c);
    }
}
          if(l.PartnerID__c == null || l.Partner_Account_24__c!=null){
           if( mapAcc.containsKey(l.Partner_Account_24__c))
           {
            l.PartnerID__c = mapAcc.get(l.Partner_Account_24__c);
    }
           
      }     
           
      }      
    }    
    
   
}
  • August 03, 2022
  • Like
  • 0
.Scenrio : Trigger rolls up child revenue and cost record as average for similar product type and sum for different product type:.
Please helo me write a test class for this 

Trigger :trigger RollupSubAmt  on Sub_Opportunity__c (after insert, after update,after delete,after undelete) {
     Set<Id> oppIdSet = new Set<Id>();
    Map<Id, List<AggregateResult>> revenuecostAmountMap = new Map<Id, List<AggregateResult>>();
    //Map<Id, Double> costTypeMap = new  Map<Id, Double>();
     List<Opportunity> opptyListToUpdate = new List<Opportunity>();
     if(Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete){
          for(Sub_Opportunity__c subopp : Trigger.new){
             if(subopp.Opportunity__c != null){
                oppIdSet.add(subopp.Opportunity__c);
             }      
          }
         RollupSubAmtHandler.afterOperation(oppIdSet);
     }
    
     If(Trigger.isDelete){
       for(Sub_Opportunity__c opp : Trigger.old){
            if(opp.Opportunity__c!= null){
               oppIdSet.add(opp.Opportunity__c); 
            }       
        }
         RollupSubAmtHandler.afterOperation(oppIdSet);
      }
     
}
Apex :
public class RollupSubAmtHandler {
    
    Public Static void afterOperation(Set<Id> setofOpportunityId)
    {
        Map<Id, List<AggregateResult>> revenuecostAmountMap = new Map<Id, List<AggregateResult>>();
        List<Opportunity> opptyListToUpdate = new List<Opportunity>();
   
       for(AggregateResult res : [SELECT Opportunity__c Opp, Product_Type__c value, AVG(Actual_Revenue_Rollup__c)revAvg , AVG(Actual_Cost_Rollup__c)costAvg FROM Sub_Opportunity__c  WHERE Opportunity__c IN : setofOpportunityId GROUP BY Opportunity__c, Product_Type__c]) {
        //opptyListToUpdate.add(new Opportunity(Id=(Id)res.get('Opportunity__c'), Actual_Revenue2__c= (Double)res.get('revAvg')));
        
          Id oppId = (ID)res.get('Opp');
          system.debug('revenuecostAmountMap=>'+ revenuecostAmountMap);
           If(revenuecostAmountMap.containsKey(oppId))
           {
              revenuecostAmountMap.get(oppId).add(res);
              
            } 
             else
             {
                 revenuecostAmountMap.put(oppId, new List<AggregateResult> { res });
             }
         
     } 
        System.debug('revenuecostAmountMap.size()=>>'+ revenuecostAmountMap.size());
            System.debug('revenuecostAmountMap=>>'+revenuecostAmountMap);
    
    for(Id opportunityId : revenuecostAmountMap.keySet())
    {
        Double sumOfRevenueAmount = calculateRevenue(revenuecostAmountMap.get(opportunityId));
        Double sumOfCostAmount = calculateCost(revenuecostAmountMap.get(opportunityId));
        Opportunity opportunityRecord = New Opportunity();
        opportunityRecord.Id = opportunityId;
        opportunityRecord.Actual_Cost2__c = sumOfCostAmount ;
        opportunityRecord.Actual_Revenue2__c = sumOfRevenueAmount ;
         opptyListToUpdate.add(opportunityRecord);
    }
    
    update opptyListToUpdate;
    
    
    }
    public Static Double calculateRevenue(List<AggregateResult> revenueList)
    {
        Double sumofrevenue = 0.0;
        for(AggregateResult ar : revenueList)
        {
            system.debug('each aggregate revenue value => '+ (Double)ar.get('revAvg'));
            sumofrevenue += (Double)ar.get('revAvg');
        }
        return sumofrevenue;
    }
    public Static Double calculateCost(List<AggregateResult> costList)
    {
        Double sumofcost = 0.0;
        for(AggregateResult ar : costList)
        {
            system.debug('each aggregate cost value => '+ (Double)ar.get('costAvg'));
            sumofcost += (Double)ar.get('costAvg');
        }
        return sumofcost;

    } 
}


- Please help me with the apex handler . I have 2 objects opportunity (parent) and sub -opportunity (child)objects . I have two fields in child object revenue and cost. There is a picklist field in sub opportunity called prod type. If the sub opportunity has similar  prod type, the revenue and cost should get averaged at opportunity object (Revenue field and cost field field) . For different prod type , the revenue should be sumed and displayed at oopportunity revenue field. Similarly for cost. Please help me how I can dynamically check the prod type and do average or sum for sub opportunity by product type and display in opportunity object revenue field.

Trigger handler:
public class SubOpportunityTriggerHandler {
    
    public void afterUpdate(List<Sub_Opportunity__c> newSubOpp){
        Set<ID> SubId = new Set<ID>();
        for (Sub_Opportunity__c sub : (List<Sub_Opportunity__c>)Trigger.New) {           
                SubId.add(sub.id);
            }    
        RollupCalculation(SubId);
        
    }
     public void afterinsert(List<Sub_Opportunity__c> newSubOpp){
        
        for (Sub_Opportunity__c opp : (List<Sub_Opportunity__c>)Trigger.New) {
                      
        }
    }
    public void afterdelete(List<Sub_Opportunity__c> newSubOpp){
        
        for (Sub_Opportunity__c opp : (List<Sub_Opportunity__c>)Trigger.New) {
                       
        }
    }
   
    public void afterundelete(List<Sub_Opportunity__c> newSubOpp){
        
        for (Sub_Opportunity__c opp : (List<Sub_Opportunity__c>)Trigger.New) {
                        
 
- Please help me with the apex handler . I have 2 objects opportunity (parent) and sub -opportunity (child)objects . I have two fields in child object revenue and cost. There is a picklist field in sub opportunity called prod type. If the sub opportunity has similar  prod type, the revenue and cost should get averaged at opportunity object (Revenue field and cost field field) . For different prod type , the revenue should be sumed and displayed at oopportunity revenue field. Similarly for cost. Please help me how I can dynamically check the prod type and do average or sum for sub opportunity by product type and display in opportunity object revenue field.

Trigger handler:
public class SubOpportunityTriggerHandler {
    
    public void afterUpdate(List<Sub_Opportunity__c> newSubOpp){
        Set<ID> SubId = new Set<ID>();
        for (Sub_Opportunity__c sub : (List<Sub_Opportunity__c>)Trigger.New) {           
                SubId.add(sub.id);
            }    
        RollupCalculation(SubId);
        
    }
     public void afterinsert(List<Sub_Opportunity__c> newSubOpp){
        
        for (Sub_Opportunity__c opp : (List<Sub_Opportunity__c>)Trigger.New) {
                      
        }
    }
    public void afterdelete(List<Sub_Opportunity__c> newSubOpp){
        
        for (Sub_Opportunity__c opp : (List<Sub_Opportunity__c>)Trigger.New) {
                       
        }
    }
   
    public void afterundelete(List<Sub_Opportunity__c> newSubOpp){
        
        for (Sub_Opportunity__c opp : (List<Sub_Opportunity__c>)Trigger.New) {
                        
        }
    }  
    public static void RollupCalculation(Set<ID> subId){
        
    }
}
how to dynamically search a picklist values
There is a picklist field Prod Type in child object ,sub opportunity . Based on similar Prod Type values the child object sub opportunity's field "revenue" should get averaged and for differnt product types values the child object "Sub opportunity " revenue field should be sumed at the parent object that is opportunity.
Please help me to achive this in my trigger 

trigger RolllupSubAmt  on Sub_Opportunity__c ( after insert, after update,after delete,after undelete) {
     Set<Id> oppIdSet=new Set<Id>();
     List<Opportunity> opptyListToUpdate=new List<Opportunity>();
     if(Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete){
          for(Sub_Opportunity__c subopp : Trigger.new){
             if(subopp.Opportunity__c!= null){
                oppIdSet.add(subopp.Opportunity__c);
             }      
          }
     }
     If(Trigger.isDelete){
       for(Sub_Opportunity__c opp : Trigger.old){
            if(opp.Opportunity__c!= null){
               oppIdSet.add(opp.Opportunity__c); 
            }       
        }
      }
     for(AggregateResult res : [SELECT Opportunity__c,avg(Actual_Revenue_Rollup__c)can FROM Sub_Opportunity__c WHERE Opportunity__c IN :oppIdSet GROUP BY  Opportunity__c ]) {
        opptyListToUpdate.add(new Opportunity(Id=(Id)res.get('Opportunity__c'), Actual_Revenue2__c=(Double)res.get('can')));
    }
    try{
        update opptyListToUpdate;
     }catch(DmlException de){
        System.debug(de);
     }
}
There is a picklist field Prod Type in child object ,sub opportunity . Based on similar Prod Type values the child object sub opportunity's field "revenue" should get averaged and for differnt product types values the child object "Sub opportunity " revenue field should be sumed at the parent object that is opportunity.
Please help me to achive this in my trigger 

trigger RolllupSubAmt  on Sub_Opportunity__c ( after insert, after update,after delete,after undelete) {
     Set<Id> oppIdSet=new Set<Id>();
     List<Opportunity> opptyListToUpdate=new List<Opportunity>();
     if(Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete){
          for(Sub_Opportunity__c subopp : Trigger.new){
             if(subopp.Opportunity__c!= null){
                oppIdSet.add(subopp.Opportunity__c);
             }      
          }
     }
     If(Trigger.isDelete){
       for(Sub_Opportunity__c opp : Trigger.old){
            if(opp.Opportunity__c!= null){
               oppIdSet.add(opp.Opportunity__c); 
            }       
        }
      }
     for(AggregateResult res : [SELECT Opportunity__c,avg(Actual_Revenue_Rollup__c)can FROM Sub_Opportunity__c WHERE Opportunity__c IN :oppIdSet GROUP BY  Opportunity__c ]) {
        opptyListToUpdate.add(new Opportunity(Id=(Id)res.get('Opportunity__c'), Actual_Revenue2__c=(Double)res.get('can')));
    }
    try{
        update opptyListToUpdate;
     }catch(DmlException de){
        System.debug(de);
     }
}
Hi there.. I need help with a trigger which averages sub opportunities revenue field  when product type is same else it sums the revenues  at the parent (opprtunity object).
The trigger  which I have written below only sums. Please help me so that based on the similar product types the revenue gets averages else sumed up.

trigger RolllupSubAmt  on Sub_Opportunity__c ( after insert, after update,after delete,after undelete) {
     Set<Id> oppIdSet=new Set<Id>();
     List<Opportunity> opptyListToUpdate=new List<Opportunity>();
     if(Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete){
          for(Sub_Opportunity__c subopp : Trigger.new){
             if(subopp.Opportunity__c!= null){
                oppIdSet.add(subopp.Opportunity__c);
             }      
          }
     }
     If(Trigger.isDelete){
       for(Sub_Opportunity__c opp : Trigger.old){
            if(opp.Opportunity__c!= null){
               oppIdSet.add(opp.Opportunity__c); 
            }       
        }
      }
     for(AggregateResult res : [SELECT Opportunity__c,sum(Actual_Revenue_Rollup__c)can FROM Sub_Opportunity__c WHERE Opportunity__c IN :oppIdSet GROUP BY  Opportunity__c ]) {
        opptyListToUpdate.add(new Opportunity(Id=(Id)res.get('Opportunity__c'), Actual_Revenue2__c=(Double)res.get('can')));
    }
    try{
        update opptyListToUpdate;
     }catch(DmlException de){
        System.debug(de);
     }
}
Scenario :    opportunity (primary)
                     Sub opportunity(master detailed with primary
                      Product (mater detailed with sub oppty)
Product object revenue and cost sum is  rolling  up at sub opportunity and the probability is  getting averaged for product at sub opportunity object. Product  has product type IS and OS.
I need your help here … at the opportunity object  if there are 2  sub opportunity records  with IS product types then further rollup for revenue , cost and probability  at primary opportunity will be averaged. Same for OS.. if there are more than 1 sub opportunity at opportunity object  the revenue , cost and probability  rollups will be averaged.The IS and OS  sub opportunity will always be added
 for revenue and cost and Probability will be averaged.ut 
Below  table is an example to make you undertand. Please help me.with the developments to achieve this . 



User-added image
Scenario : This trigger with the apex class helps in calculating roll up of average (cost, amount and probability ) from product child object to sub-oppty parent object. Please help me with the test class for this . Your help will be greatly helpful.

trigger AvgCalculateTrigger on Sub_Opportunity_Product__c (after insert, after update, after delete) {
    
    if( Trigger.isInsert || Trigger.isAfter || Trigger.isDelete ){
        if( Trigger.isAfter ){
           AvgCalculate.avgCalculate();
           AvgCalculate.avgCalculate1();
            AvgCalculate.avgCalculate2();
           
           
        }
    }
        
}





Apex Class

public class AvgCalculate {

    public static void avgCalculate (){
        Set<Id> subopptyIds = new Set<Id>();
        List<Sub_Opportunity__c> subopptyToUpdate = new List<Sub_Opportunity__c>();
      
        List< Sub_Opportunity_Product__c> sub = Trigger.isInsert || Trigger.isUpdate ? Trigger.New : Trigger.Old;
        for(Sub_Opportunity_Product__c  ct : sub ){
            subopptyIds.add( ct.Sub_Opportunity__c /*lookup field value of utilityrecord */ );
        }

        for( AggregateResult ag : [ SELECT Sub_Opportunity__c, AVG( Cost__c ) avg FROM Sub_Opportunity_Product__c
                                    GROUP BY Sub_Opportunity__c ] ){
             subopptyToUpdate.add( new Sub_Opportunity__c( 
                Id = (Id)ag.get('Sub_Opportunity__c'), 
                 Actual_Cost2__c = (Decimal)ag.get('avg') ) );                            
        }
         
      
         
         
              if(subopptyToUpdate.size() > 0 ){
            update  subopptyToUpdate;
        }
        
       
    }
    public static void avgCalculate1 (){
        Set<Id> subopptyIds1= new Set<Id>();
        List<Sub_Opportunity__c> subopptyToUpdate1 = new List<Sub_Opportunity__c>();
      
        List< Sub_Opportunity_Product__c> sub1 = Trigger.isInsert || Trigger.isUpdate ? Trigger.New : Trigger.Old;
        for(Sub_Opportunity_Product__c  ct : sub1 ){
            subopptyIds1.add( ct.Sub_Opportunity__c /*lookup field value of utilityrecord */ );
        }

        for( AggregateResult ag1 : [ SELECT Sub_Opportunity__c, AVG( Amount__c ) avg FROM Sub_Opportunity_Product__c
                                    GROUP BY Sub_Opportunity__c ] ){
             subopptyToUpdate1.add( new Sub_Opportunity__c( 
                Id = (Id)ag1.get('Sub_Opportunity__c'), 
                 Actual_Revenue2__c = (Decimal)ag1.get('avg') ) );                            
        }
         
         if(subopptyToUpdate1.size() > 0 ){
            update  subopptyToUpdate1;
        }
       
    }  
      public static void avgCalculate2 (){
        Set<Id> subopptyIds2= new Set<Id>();
        List<Sub_Opportunity__c> subopptyToUpdate2 = new List<Sub_Opportunity__c>();
      
        List< Sub_Opportunity_Product__c> sub2 = Trigger.isInsert || Trigger.isUpdate ? Trigger.New : Trigger.Old;
        for(Sub_Opportunity_Product__c  ct : sub2 ){
            subopptyIds2.add( ct.Sub_Opportunity__c /*lookup field value of utilityrecord */ );
        }

        for( AggregateResult ag2 : [ SELECT Sub_Opportunity__c, AVG( Probability__c ) avgprob FROM Sub_Opportunity_Product__c
                                    GROUP BY Sub_Opportunity__c ] ){
             subopptyToUpdate2.add( new Sub_Opportunity__c( 
                Id = (Id)ag2.get('Sub_Opportunity__c'), 
                 Probability__c = (Decimal)ag2.get('avgprob') ) );                            
        }
         
         if(subopptyToUpdate2.size() > 0 ){
            update  subopptyToUpdate2;
        }
       
    }  
  
 }
 
Scenario : I have written a trigger to update average of cost , amount and probability of child object product at parent object sub opportunity level (Actual Cost , Actual Amount and Actual Probability ) fields. I have written three separate methods for the same , Please help me to write inside one method.
Apex Trigger:


trigger AvgCalculateTrigger on Sub_Opportunity_Product__c (after insert, after update, after delete) {
    
    if( Trigger.isInsert || Trigger.isAfter || Trigger.isDelete ){
        if( Trigger.isAfter ){
           AvgCalculate.avgCalculate();
           AvgCalculate.avgCalculate1();
            AvgCalculate.avgCalculate2();
           
           
        }
    }
        
}





Apex Class

public class AvgCalculate {

    public static void avgCalculate (){
        Set<Id> subopptyIds = new Set<Id>();
        List<Sub_Opportunity__c> subopptyToUpdate = new List<Sub_Opportunity__c>();
      
        List< Sub_Opportunity_Product__c> sub = Trigger.isInsert || Trigger.isUpdate ? Trigger.New : Trigger.Old;
        for(Sub_Opportunity_Product__c  ct : sub ){
            subopptyIds.add( ct.Sub_Opportunity__c /*lookup field value of utilityrecord */ );
        }

        for( AggregateResult ag : [ SELECT Sub_Opportunity__c, AVG( Cost__c ) avg FROM Sub_Opportunity_Product__c
                                    GROUP BY Sub_Opportunity__c ] ){
             subopptyToUpdate.add( new Sub_Opportunity__c( 
                Id = (Id)ag.get('Sub_Opportunity__c'), 
                 Actual_Cost2__c = (Decimal)ag.get('avg') ) );                            
        }
         
      
         
         
              if(subopptyToUpdate.size() > 0 ){
            update  subopptyToUpdate;
        }
        
       
    }
    public static void avgCalculate1 (){
        Set<Id> subopptyIds1= new Set<Id>();
        List<Sub_Opportunity__c> subopptyToUpdate1 = new List<Sub_Opportunity__c>();
      
        List< Sub_Opportunity_Product__c> sub1 = Trigger.isInsert || Trigger.isUpdate ? Trigger.New : Trigger.Old;
        for(Sub_Opportunity_Product__c  ct : sub1 ){
            subopptyIds1.add( ct.Sub_Opportunity__c /*lookup field value of utilityrecord */ );
        }

        for( AggregateResult ag1 : [ SELECT Sub_Opportunity__c, AVG( Amount__c ) avg FROM Sub_Opportunity_Product__c
                                    GROUP BY Sub_Opportunity__c ] ){
             subopptyToUpdate1.add( new Sub_Opportunity__c( 
                Id = (Id)ag1.get('Sub_Opportunity__c'), 
                 Actual_Revenue2__c = (Decimal)ag1.get('avg') ) );                            
        }
         
         if(subopptyToUpdate1.size() > 0 ){
            update  subopptyToUpdate1;
        }
       
    }  
      public static void avgCalculate2 (){
        Set<Id> subopptyIds2= new Set<Id>();
        List<Sub_Opportunity__c> subopptyToUpdate2 = new List<Sub_Opportunity__c>();
      
        List< Sub_Opportunity_Product__c> sub2 = Trigger.isInsert || Trigger.isUpdate ? Trigger.New : Trigger.Old;
        for(Sub_Opportunity_Product__c  ct : sub2 ){
            subopptyIds2.add( ct.Sub_Opportunity__c /*lookup field value of utilityrecord */ );
        }

        for( AggregateResult ag2 : [ SELECT Sub_Opportunity__c, AVG( Probability__c ) avgprob FROM Sub_Opportunity_Product__c
                                    GROUP BY Sub_Opportunity__c ] ){
             subopptyToUpdate2.add( new Sub_Opportunity__c( 
                Id = (Id)ag2.get('Sub_Opportunity__c'), 
                 Probability__c = (Decimal)ag2.get('avgprob') ) );                            
        }
         
         if(subopptyToUpdate2.size() > 0 ){
            update  subopptyToUpdate2;
        }
       
    }  
  
 }
 
 I have two  fields ,
Timing 1 field  one is picklist which is created for user to select manually , Timing 2 field is a formula which  populates if user selects a contract end date.  

The users should enter Timing 1 field only when Timing 2 is populated as "No'  as value (basically when no contract end date is entered , Timing 2 is no ).

How to achieve this ? Help me with the validations please
I have two Timing 1 field  one is picklisy which is created for user to select manually , Timing 2 field is a formula which  populates if user selects a contract end date.

The users should enter Timing 1 field only when Timing 2 is populated as "None'  (basically when no contract end date is entered , Timing 2 is none ).

How to achieve this ? Help me with the validations please

TRIGGER SCENARIO :

Partnerid is external id in Account .
In Lead Partnerid is a text datatype field which will have same value as Account PartnerId
Usecase1
:This trigger updates the account name lookup field on lead based on the partner id  on Lead object .

Usecase2:Also if account lookup is selected first  then it populates the partnerid field to the id number that is tied to the account selected 

Both the usecases are taken care by this trigger.

trigger LeadTriggerPardot on Lead (before insert,before update) {
    
    List<String> Ids = new List<String>();
    List<Account> accounts = new List<Account>();
    Map<String,Id> mapAccount = new Map<String,Id>();
    List<String> AccIds = new List<String>();
    List<Account> acc = new List<Account>();
    Map<Id,String> mapAcc = new Map<Id,String>();
   
    Id leadRecordTypeId = Schema.SObjectType.Lead.getRecordTypeInfosByName().get('lead2.4').getRecordTypeId();
    for(Lead o : trigger.new){
     if(o.PartnerID__c !=null){
        Ids.add(o.PartnerID__c);
    } }
    for(Account a : [SELECT Id, PartnerID__c, Name FROM Account WHERE PartnerID__c IN :Ids]){
    
    mapAccount.put(a.PartnerID__c, a.Id);
     
    }
     for(Lead o : trigger.new){

        AccIds.add(o.Partner_Account_24__c);
    } 
    for(Account a : [SELECT Id, PartnerID__c, Name FROM Account WHERE Id IN :AccIds]){
    
    mapAcc.put(a.Id,a.PartnerID__c);
     
    }
   
    for(Lead l:  trigger.new){
    if(l.RecordTypeId == leadRecordTypeId){
       if(l.PartnerID__c!=null){
           if( mapAccount.containsKey(l.PartnerID__c))
           {
            l.Partner_Account_24__c = mapAccount.get(l.PartnerID__c);
    }
}
          if(l.PartnerID__c == null || l.Partner_Account_24__c!=null){
           if( mapAcc.containsKey(l.Partner_Account_24__c))
           {
            l.PartnerID__c = mapAcc.get(l.Partner_Account_24__c);
    }
           
      }     
           
      }      
    }    
    
   
}

Test Class:
@isTest
public class TestLeadTriggerPardot {
   
    @isTest static void LeadPardot (){
      
                Account acc = new Account(
                Name = 'Test Temp Account',
                PartnerID__c = '6789'
                );
            insert acc; 
        
              
        
        Lead ld = new Lead(
        PartnerID__c = '6789',
        Partner_Account_24__c = 'Test Temp Account',
        LastName = 'Test Lead',
        Company = 'ABC',
        LeadSource ='Phone'
            );
        insert ld;
        
      
          }
    Static testMethod void insertLeadItem()
    
      {   
        
        
        Lead l=[select id, Partner_Account_24__c from Lead where PartnerID__c = '6789'];
        system.assertequals(l.Partner_Account_24__c, null);
      }
        
        Static testMethod void insertLeadItem_Null()
    
      {   
      
        Lead l=[select id,Partner_Account_24__c from Lead where  PartnerID__c  = '6789'];
         Account a =[select id , PartnerID__c,Name from Account where PartnerID__c = '6789'];
       
       l.PartnerID__c  = '6789';
        update l;
        
      Lead lead =[select id ,Partner_Account_24__c from Lead where Id=:l.id];
        system.assertequals(lead.Partner_Account_24__c, a.PartnerID__c);
      }

}




 
trigger LeadTriggerPardot on Lead (before insert,before update) {
    
    List<String> Ids = new List<String>();
    List<Account> accounts = new List<Account>();
    Map<String,Id> mapAccount = new Map<String,Id>();
    List<String> AccIds = new List<String>();
    List<Account> acc = new List<Account>();
    Map<Id,String> mapAcc = new Map<Id,String>();
   
    Id leadRecordTypeId = Schema.SObjectType.Lead.getRecordTypeInfosByName().get('lead2.4').getRecordTypeId();
    for(Lead o : trigger.new){
     if(o.PartnerID__c !=null){
        Ids.add(o.PartnerID__c);
    } }
    for(Account a : [SELECT Id, PartnerID__c, Name FROM Account WHERE PartnerID__c IN :Ids]){
    
    mapAccount.put(a.PartnerID__c, a.Id);
     
    }
     for(Lead o : trigger.new){

        AccIds.add(o.Partner_Account_24__c);
    } 
    for(Account a : [SELECT Id, PartnerID__c, Name FROM Account WHERE Id IN :AccIds]){
    
    mapAcc.put(a.Id,a.PartnerID__c);
     
    }
   
    for(Lead l:  trigger.new){
    if(l.RecordTypeId == leadRecordTypeId){
       if(l.PartnerID__c!=null){
           if( mapAccount.containsKey(l.PartnerID__c))
           {
            l.Partner_Account_24__c = mapAccount.get(l.PartnerID__c);
    }
}
          if(l.PartnerID__c == null || l.Partner_Account_24__c!=null){
           if( mapAcc.containsKey(l.Partner_Account_24__c))
           {
            l.PartnerID__c = mapAcc.get(l.Partner_Account_24__c);
    }
           
      }     
           
      }      
    }    
    
   
}
Scenario :    opportunity (primary)
                     Sub opportunity(master detailed with primary
                      Product (mater detailed with sub oppty)
Product object revenue and cost sum is  rolling  up at sub opportunity and the probability is  getting averaged for product at sub opportunity object. Product  has product type IS and OS.
I need your help here … at the opportunity object  if there are 2  sub opportunity records  with IS product types then further rollup for revenue , cost and probability  at primary opportunity will be averaged. Same for OS.. if there are more than 1 sub opportunity at opportunity object  the revenue , cost and probability  rollups will be averaged.The IS and OS  sub opportunity will always be added
 for revenue and cost and Probability will be averaged.ut 
Below  table is an example to make you undertand. Please help me.with the developments to achieve this . 



User-added image
class : 

global class UserReport implements Database.Batchable<SObject>, Database.AllowsCallouts, Database.Stateful {
  global  blob MyBlob;
    Set<String> nums = new Set<String>{'1%','2%','3%','4%','5%','6%','7%','8%','9%'};
   public List<String> searchstring = new List<String> {'Sales Manager','Sales User'};
    private List<String> fieldNames = new List<String> {
         'Name', 'Registry_ID_EBS__c','OwnerId', 'Owner.Email', 'Owner.IsActive'
    };
      
     global String csvContent = '';
                
    global Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator([Select Id, Name, Registry_ID_EBS__c, OwnerId, Owner.Email, Owner.IsActive,Owner.profile.Name From Account where Owner.profile.Name IN ('Sales Manager', 'Sales User') AND Registry_ID_EBS__c like :nums ]);
    }
    
    global void execute(Database.BatchableContext context, List<Account> records) {
        Map<Id, User> owners = new Map<Id, User>();
        for (Account record : records) {
            owners.put(record.OwnerId, null);
        }
        owners.remove(null);
        owners.putAll([Select Id, Name, Email, IsActive From User Where Id IN :owners.keySet()]);
        
       /*
        for (String fieldName : fieldNames) {
            if (fieldName == 'OwnerId') {
                csvContent += '"Owner Name",';
            } else if (fieldName == 'Owner.Email') {
                csvContent += '"Owner Email",';
            } else if (fieldName == 'Owner.IsActive') {
                csvContent += '"Owner Active",';
            } else {
                csvContent += '"' + fieldName + '"' + ',';
            }
        }
        csvContent += '\n';*/
        for (Account record : records) {
            for (String fieldName : fieldNames) {
                if (fieldName == 'OwnerId') {
                    String ownerName = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerName = String.valueOf(owners.get(record.OwnerId).Name).replace('"', '""');
                    }
                    csvContent += '"' + ownerName + '"' + ',';
                } else if (fieldName == 'Owner.Email') {
                    String ownerEmail = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerEmail = String.valueOf(owners.get(record.OwnerId).Email).replace('"', '""');
                    }
                    csvContent += '"' + ownerEmail + '"' + ',';
                } else if (fieldName == 'Owner.IsActive') {
                    String ownerIsActive = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerIsActive = String.valueOf(owners.get(record.OwnerId).IsActive).replace('"', '""');
                    }
                    csvContent += '"' + ownerIsActive + '"' + ',';
                } else {
                    Object fieldValueObj = record.get(fieldName);
                    if (fieldValueObj != null) {
                        String fieldValue = String.valueOf(fieldValueObj).replace('"', '""');
                        csvContent += '"' + fieldValue + '"' + ',';
                    } else {
                        csvContent += ',';
                    }
                }
            }
            csvContent += '\n';
           //system.debug('csvContent'+csvContent);
        }
        String Header = 'Customer Name, EBS Registry Id, Account Owner, Account Owner Email, Account Owner IsActive';
        String FinalcsvContent = Header + '\n' + csvContent ;
        MyBlob = blob.valueOf(FinalcsvContent); 
        system.debug('MyBlob1'+FinalcsvContent);

    }

   global void finish(Database.BatchableContext context) {
        system.debug('MyBlob2'+MyBlob);
    String emailAddress1 = 'mousumi.chatterjee@continuserve.com';
    Messaging.EmailFileAttachment csvAttachment = new Messaging.EmailFileAttachment();
    String myName = 'AccountList.csv';
    csvAttachment.setFileName(myName);
    csvAttachment.setBody(MyBlob);
       csvAttachment.setContentType('application/csv');
       system.debug('ss'+MyBlob);
    Messaging.SingleEmailMessage myEmail = new Messaging.SingleEmailMessage();
    String[] toAddresses = new String[]{emailAddress1};
    String subject = 'UserID and List CSV';
    myEmail.setSubject(subject);
    myEmail.setToAddresses(toAddresses);
    myEmail.setPlainTextBody('User Alias Report');
    myEmail.setHtmlBody('Hi All'+','+'</br><br/>'+ 'Please find attached the sales user detail report from Salesforce production CRM.' +'</br><br/'+'Thanks'+','+'</br>'+'Brinks Team');
   Messaging.EmailFileAttachment[] attachments = new Messaging.EmailFileAttachment[]{csvAttachment};
myEmail.setFileAttachments(attachments);

    Messaging.SendEmailResult[] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[]{myEmail});
}
}



 test class - 42%


@isTest
public class TestUserReport {
static String str = 'Name,Registry_ID_EBS__c,OwnerId,Owner.Email,Owner.IsActive \n';       

    public static String[] csvFileLines;
    public static Blob csvFileBody;

    static testmethod void testfileupload(){
        Test.startTest();       
        csvFileBody = Blob.valueOf(str);
        String csvAsString = csvFileBody.toString();
        csvFileLines = csvAsString.split('\n'); 

       UserReport result = new UserReport();
       
       // result .csvAttachment();
        Test.stopTest();
    } 

    static testmethod void testfileuploadNegative(){
        Test.startTest();       
        csvFileBody = Blob.valueOf(str);
        String csvAsString = csvFileBody.toString();
        csvFileLines = csvAsString.split('\n'); 

     UserReport result = new UserReport();
       Id batchJobId = Database.executeBatch(new UserReport(), 200);
        Test.stopTest();
    }
}
  • March 27, 2023
  • Like
  • 0
The batch apex is sending account details as attachment and sending email and the test class is only covering 37% .Please helo me to get 75% code coverage
Apex Class:
global class UserReport implements Database.Batchable<SObject>, Database.AllowsCallouts, Database.Stateful {
  global  blob MyBlob;
   public List<String> searchstring = new List<String> {'Sales Manager','Sales User'};
    private List<String> fieldNames = new List<String> {
        'Id', 'Name', 'Registry_ID_EBS__c','OwnerId', 'Owner.Email', 'Owner.IsActive'
    };
      
     global String csvContent = '';
                
    global Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator([Select Id, Name, Registry_ID_EBS__c, OwnerId, Owner.Email, Owner.IsActive,Owner.profile.Name From Account where Owner.profile.Name IN ('Sales Manager', 'Sales User') ]);
    }
    
    global void execute(Database.BatchableContext context, List<Account> records) {
        Map<Id, User> owners = new Map<Id, User>();
        for (Account record : records) {
            owners.put(record.OwnerId, null);
        }
        owners.remove(null);
        owners.putAll([Select Id, Name, Email, IsActive From User Where Id IN :owners.keySet()]);
        
       
        for (String fieldName : fieldNames) {
            if (fieldName == 'OwnerId') {
                csvContent += '"Owner Name",';
            } else if (fieldName == 'Owner.Email') {
                csvContent += '"Owner Email",';
            } else if (fieldName == 'Owner.IsActive') {
                csvContent += '"Owner Active",';
            } else {
                csvContent += '"' + fieldName + '"' + ',';
            }
        }
        csvContent += '\n';
        for (Account record : records) {
            for (String fieldName : fieldNames) {
                if (fieldName == 'OwnerId') {
                    String ownerName = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerName = String.valueOf(owners.get(record.OwnerId).Name).replace('"', '""');
                    }
                    csvContent += '"' + ownerName + '"' + ',';
                } else if (fieldName == 'Owner.Email') {
                    String ownerEmail = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerEmail = String.valueOf(owners.get(record.OwnerId).Email).replace('"', '""');
                    }
                    csvContent += '"' + ownerEmail + '"' + ',';
                } else if (fieldName == 'Owner.IsActive') {
                    String ownerIsActive = '';
                    if (record.OwnerId != null && owners.containsKey(record.OwnerId)) {
                        ownerIsActive = String.valueOf(owners.get(record.OwnerId).IsActive).replace('"', '""');
                    }
                    csvContent += '"' + ownerIsActive + '"' + ',';
                } else {
                    Object fieldValueObj = record.get(fieldName);
                    if (fieldValueObj != null) {
                        String fieldValue = String.valueOf(fieldValueObj).replace('"', '""');
                        csvContent += '"' + fieldValue + '"' + ',';
                    } else {
                        csvContent += ',';
                    }
                }
            }
            csvContent += '\n';
           //system.debug('csvContent'+csvContent);
        }
        MyBlob = blob.valueOf(csvContent); 
          system.debug('MyBlob1'+MyBlob);

    }

   global void finish(Database.BatchableContext context) {
        system.debug('MyBlob2'+MyBlob);
    String emailAddress1 = 'selvin.paul@continuserve.com';
    Messaging.EmailFileAttachment csvAttachment = new Messaging.EmailFileAttachment();
    String myName = 'AccountList.csv';
    csvAttachment.setFileName(myName);
    csvAttachment.setBody(MyBlob);
       csvAttachment.setContentType('application/csv');
       system.debug('ss'+MyBlob);
    Messaging.SingleEmailMessage myEmail = new Messaging.SingleEmailMessage();
    String[] toAddresses = new String[]{emailAddress1};
    String subject = 'UserID and List CSV';
    myEmail.setSubject(subject);
    myEmail.setToAddresses(toAddresses);
    myEmail.setPlainTextBody('User Alias Report');
    myEmail.setHtmlBody('Hi All'+','+'</br><br/>'+ 'Please find attached the sales user detail report from Salesforce production CRM.' +'</br><br/'+'Thanks'+','+'</br>'+'Brinks Team');
   Messaging.EmailFileAttachment[] attachments = new Messaging.EmailFileAttachment[]{csvAttachment};
myEmail.setFileAttachments(attachments);

    Messaging.SendEmailResult[] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[]{myEmail});
}
}
Test Class:

@isTest
public class UserReportTest {
static String str = 'Name,Registry_ID_EBS__c,OwnerId,Owner.Email,Owner.IsActive \n';       

    public static String[] csvFileLines;
    public static Blob csvFileBody;

    static testmethod void testfileupload(){
        Test.startTest();       
        csvFileBody = Blob.valueOf(str);
        String csvAsString = csvFileBody.toString();
        csvFileLines = csvAsString.split('\n'); 

       UserReport result = new UserReport();
       
       // result .csvAttachment();
        Test.stopTest();
    } 

    static testmethod void testfileuploadNegative(){
        Test.startTest();       
        csvFileBody = Blob.valueOf(str);
        String csvAsString = csvFileBody.toString();
        csvFileLines = csvAsString.split('\n'); 

     UserReport result = new UserReport();
       Id batchJobId = Database.executeBatch(new UserReport(), 200);
        Test.stopTest();
    }
}
  • March 17, 2023
  • Like
  • 0
My trigger is working good for autopopulationg Account Id field  when account lookup field  is selected, But it is not letting me  update a record .
For example if  the account is stephan , it does not updates to Luke when updated and saves older value . Please help me with what is wrong here.

trigger LeadTriggerPardot on Lead (before insert,before update) {
    
    List<String> Ids = new List<String>();
    List<Account> accounts = new List<Account>();
    Map<String,Id> mapAccount = new Map<String,Id>();
    List<String> AccIds = new List<String>();
    List<Account> acc = new List<Account>();
    Map<Id,String> mapAcc = new Map<Id,String>();
   
    Id leadRecordTypeId = Schema.SObjectType.Lead.getRecordTypeInfosByName().get('lead2.4').getRecordTypeId();
    Id leadRecordTypeId1 = Schema.SObjectType.Lead.getRecordTypeInfosByName().get('Inside Sales').getRecordTypeId();
    for(Lead o : trigger.new){
     if(o.PartnerID__c !=null){
        Ids.add(o.PartnerID__c);
    } }
    for(Account a : [SELECT Id, PartnerID__c, Name FROM Account WHERE PartnerID__c IN :Ids]){
    
    mapAccount.put(a.PartnerID__c, a.Id);
     
    }
     for(Lead o : trigger.new){

        AccIds.add(o.Partner_Account_24__c);
    } 
    for(Account a : [SELECT Id, PartnerID__c, Name FROM Account WHERE Id IN :AccIds]){
    
    mapAcc.put(a.Id,a.PartnerID__c);
     
    }
   
    for(Lead l:  trigger.new){
    if(l.RecordTypeId == leadRecordTypeId || l.RecordTypeId==leadRecordTypeId1){
       if(l.PartnerID__c!=null){
           if( mapAccount.containsKey(l.PartnerID__c))
           {
            l.Partner_Account_24__c = mapAccount.get(l.PartnerID__c);
    }
}
          if(l.PartnerID__c == null || l.Partner_Account_24__c!=null){
           if( mapAcc.containsKey(l.Partner_Account_24__c))
           {
            l.PartnerID__c = mapAcc.get(l.Partner_Account_24__c);
    }
           
      }     
           
      }      
    }    
    
   
}
  • August 03, 2022
  • Like
  • 0
.Scenrio : Trigger rolls up child revenue and cost record as average for similar product type and sum for different product type:.
Please helo me write a test class for this 

Trigger :trigger RollupSubAmt  on Sub_Opportunity__c (after insert, after update,after delete,after undelete) {
     Set<Id> oppIdSet = new Set<Id>();
    Map<Id, List<AggregateResult>> revenuecostAmountMap = new Map<Id, List<AggregateResult>>();
    //Map<Id, Double> costTypeMap = new  Map<Id, Double>();
     List<Opportunity> opptyListToUpdate = new List<Opportunity>();
     if(Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete){
          for(Sub_Opportunity__c subopp : Trigger.new){
             if(subopp.Opportunity__c != null){
                oppIdSet.add(subopp.Opportunity__c);
             }      
          }
         RollupSubAmtHandler.afterOperation(oppIdSet);
     }
    
     If(Trigger.isDelete){
       for(Sub_Opportunity__c opp : Trigger.old){
            if(opp.Opportunity__c!= null){
               oppIdSet.add(opp.Opportunity__c); 
            }       
        }
         RollupSubAmtHandler.afterOperation(oppIdSet);
      }
     
}
Apex :
public class RollupSubAmtHandler {
    
    Public Static void afterOperation(Set<Id> setofOpportunityId)
    {
        Map<Id, List<AggregateResult>> revenuecostAmountMap = new Map<Id, List<AggregateResult>>();
        List<Opportunity> opptyListToUpdate = new List<Opportunity>();
   
       for(AggregateResult res : [SELECT Opportunity__c Opp, Product_Type__c value, AVG(Actual_Revenue_Rollup__c)revAvg , AVG(Actual_Cost_Rollup__c)costAvg FROM Sub_Opportunity__c  WHERE Opportunity__c IN : setofOpportunityId GROUP BY Opportunity__c, Product_Type__c]) {
        //opptyListToUpdate.add(new Opportunity(Id=(Id)res.get('Opportunity__c'), Actual_Revenue2__c= (Double)res.get('revAvg')));
        
          Id oppId = (ID)res.get('Opp');
          system.debug('revenuecostAmountMap=>'+ revenuecostAmountMap);
           If(revenuecostAmountMap.containsKey(oppId))
           {
              revenuecostAmountMap.get(oppId).add(res);
              
            } 
             else
             {
                 revenuecostAmountMap.put(oppId, new List<AggregateResult> { res });
             }
         
     } 
        System.debug('revenuecostAmountMap.size()=>>'+ revenuecostAmountMap.size());
            System.debug('revenuecostAmountMap=>>'+revenuecostAmountMap);
    
    for(Id opportunityId : revenuecostAmountMap.keySet())
    {
        Double sumOfRevenueAmount = calculateRevenue(revenuecostAmountMap.get(opportunityId));
        Double sumOfCostAmount = calculateCost(revenuecostAmountMap.get(opportunityId));
        Opportunity opportunityRecord = New Opportunity();
        opportunityRecord.Id = opportunityId;
        opportunityRecord.Actual_Cost2__c = sumOfCostAmount ;
        opportunityRecord.Actual_Revenue2__c = sumOfRevenueAmount ;
         opptyListToUpdate.add(opportunityRecord);
    }
    
    update opptyListToUpdate;
    
    
    }
    public Static Double calculateRevenue(List<AggregateResult> revenueList)
    {
        Double sumofrevenue = 0.0;
        for(AggregateResult ar : revenueList)
        {
            system.debug('each aggregate revenue value => '+ (Double)ar.get('revAvg'));
            sumofrevenue += (Double)ar.get('revAvg');
        }
        return sumofrevenue;
    }
    public Static Double calculateCost(List<AggregateResult> costList)
    {
        Double sumofcost = 0.0;
        for(AggregateResult ar : costList)
        {
            system.debug('each aggregate cost value => '+ (Double)ar.get('costAvg'));
            sumofcost += (Double)ar.get('costAvg');
        }
        return sumofcost;

    } 
}
Hi there.. I need help with a trigger which averages sub opportunities revenue field  when product type is same else it sums the revenues  at the parent (opprtunity object).
The trigger  which I have written below only sums. Please help me so that based on the similar product types the revenue gets averages else sumed up.

trigger RolllupSubAmt  on Sub_Opportunity__c ( after insert, after update,after delete,after undelete) {
     Set<Id> oppIdSet=new Set<Id>();
     List<Opportunity> opptyListToUpdate=new List<Opportunity>();
     if(Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete){
          for(Sub_Opportunity__c subopp : Trigger.new){
             if(subopp.Opportunity__c!= null){
                oppIdSet.add(subopp.Opportunity__c);
             }      
          }
     }
     If(Trigger.isDelete){
       for(Sub_Opportunity__c opp : Trigger.old){
            if(opp.Opportunity__c!= null){
               oppIdSet.add(opp.Opportunity__c); 
            }       
        }
      }
     for(AggregateResult res : [SELECT Opportunity__c,sum(Actual_Revenue_Rollup__c)can FROM Sub_Opportunity__c WHERE Opportunity__c IN :oppIdSet GROUP BY  Opportunity__c ]) {
        opptyListToUpdate.add(new Opportunity(Id=(Id)res.get('Opportunity__c'), Actual_Revenue2__c=(Double)res.get('can')));
    }
    try{
        update opptyListToUpdate;
     }catch(DmlException de){
        System.debug(de);
     }
}
Scenario :    opportunity (primary)
                     Sub opportunity(master detailed with primary
                      Product (mater detailed with sub oppty)
Product object revenue and cost sum is  rolling  up at sub opportunity and the probability is  getting averaged for product at sub opportunity object. Product  has product type IS and OS.
I need your help here … at the opportunity object  if there are 2  sub opportunity records  with IS product types then further rollup for revenue , cost and probability  at primary opportunity will be averaged. Same for OS.. if there are more than 1 sub opportunity at opportunity object  the revenue , cost and probability  rollups will be averaged.The IS and OS  sub opportunity will always be added
 for revenue and cost and Probability will be averaged.ut 
Below  table is an example to make you undertand. Please help me.with the developments to achieve this . 



User-added image
Scenario : I have written a trigger to update average of cost , amount and probability of child object product at parent object sub opportunity level (Actual Cost , Actual Amount and Actual Probability ) fields. I have written three separate methods for the same , Please help me to write inside one method.
Apex Trigger:


trigger AvgCalculateTrigger on Sub_Opportunity_Product__c (after insert, after update, after delete) {
    
    if( Trigger.isInsert || Trigger.isAfter || Trigger.isDelete ){
        if( Trigger.isAfter ){
           AvgCalculate.avgCalculate();
           AvgCalculate.avgCalculate1();
            AvgCalculate.avgCalculate2();
           
           
        }
    }
        
}





Apex Class

public class AvgCalculate {

    public static void avgCalculate (){
        Set<Id> subopptyIds = new Set<Id>();
        List<Sub_Opportunity__c> subopptyToUpdate = new List<Sub_Opportunity__c>();
      
        List< Sub_Opportunity_Product__c> sub = Trigger.isInsert || Trigger.isUpdate ? Trigger.New : Trigger.Old;
        for(Sub_Opportunity_Product__c  ct : sub ){
            subopptyIds.add( ct.Sub_Opportunity__c /*lookup field value of utilityrecord */ );
        }

        for( AggregateResult ag : [ SELECT Sub_Opportunity__c, AVG( Cost__c ) avg FROM Sub_Opportunity_Product__c
                                    GROUP BY Sub_Opportunity__c ] ){
             subopptyToUpdate.add( new Sub_Opportunity__c( 
                Id = (Id)ag.get('Sub_Opportunity__c'), 
                 Actual_Cost2__c = (Decimal)ag.get('avg') ) );                            
        }
         
      
         
         
              if(subopptyToUpdate.size() > 0 ){
            update  subopptyToUpdate;
        }
        
       
    }
    public static void avgCalculate1 (){
        Set<Id> subopptyIds1= new Set<Id>();
        List<Sub_Opportunity__c> subopptyToUpdate1 = new List<Sub_Opportunity__c>();
      
        List< Sub_Opportunity_Product__c> sub1 = Trigger.isInsert || Trigger.isUpdate ? Trigger.New : Trigger.Old;
        for(Sub_Opportunity_Product__c  ct : sub1 ){
            subopptyIds1.add( ct.Sub_Opportunity__c /*lookup field value of utilityrecord */ );
        }

        for( AggregateResult ag1 : [ SELECT Sub_Opportunity__c, AVG( Amount__c ) avg FROM Sub_Opportunity_Product__c
                                    GROUP BY Sub_Opportunity__c ] ){
             subopptyToUpdate1.add( new Sub_Opportunity__c( 
                Id = (Id)ag1.get('Sub_Opportunity__c'), 
                 Actual_Revenue2__c = (Decimal)ag1.get('avg') ) );                            
        }
         
         if(subopptyToUpdate1.size() > 0 ){
            update  subopptyToUpdate1;
        }
       
    }  
      public static void avgCalculate2 (){
        Set<Id> subopptyIds2= new Set<Id>();
        List<Sub_Opportunity__c> subopptyToUpdate2 = new List<Sub_Opportunity__c>();
      
        List< Sub_Opportunity_Product__c> sub2 = Trigger.isInsert || Trigger.isUpdate ? Trigger.New : Trigger.Old;
        for(Sub_Opportunity_Product__c  ct : sub2 ){
            subopptyIds2.add( ct.Sub_Opportunity__c /*lookup field value of utilityrecord */ );
        }

        for( AggregateResult ag2 : [ SELECT Sub_Opportunity__c, AVG( Probability__c ) avgprob FROM Sub_Opportunity_Product__c
                                    GROUP BY Sub_Opportunity__c ] ){
             subopptyToUpdate2.add( new Sub_Opportunity__c( 
                Id = (Id)ag2.get('Sub_Opportunity__c'), 
                 Probability__c = (Decimal)ag2.get('avgprob') ) );                            
        }
         
         if(subopptyToUpdate2.size() > 0 ){
            update  subopptyToUpdate2;
        }
       
    }  
  
 }
 
 I have two  fields ,
Timing 1 field  one is picklist which is created for user to select manually , Timing 2 field is a formula which  populates if user selects a contract end date.  

The users should enter Timing 1 field only when Timing 2 is populated as "No'  as value (basically when no contract end date is entered , Timing 2 is no ).

How to achieve this ? Help me with the validations please

TRIGGER SCENARIO :

Partnerid is external id in Account .
In Lead Partnerid is a text datatype field which will have same value as Account PartnerId
Usecase1
:This trigger updates the account name lookup field on lead based on the partner id  on Lead object .

Usecase2:Also if account lookup is selected first  then it populates the partnerid field to the id number that is tied to the account selected 

Both the usecases are taken care by this trigger.

trigger LeadTriggerPardot on Lead (before insert,before update) {
    
    List<String> Ids = new List<String>();
    List<Account> accounts = new List<Account>();
    Map<String,Id> mapAccount = new Map<String,Id>();
    List<String> AccIds = new List<String>();
    List<Account> acc = new List<Account>();
    Map<Id,String> mapAcc = new Map<Id,String>();
   
    Id leadRecordTypeId = Schema.SObjectType.Lead.getRecordTypeInfosByName().get('lead2.4').getRecordTypeId();
    for(Lead o : trigger.new){
     if(o.PartnerID__c !=null){
        Ids.add(o.PartnerID__c);
    } }
    for(Account a : [SELECT Id, PartnerID__c, Name FROM Account WHERE PartnerID__c IN :Ids]){
    
    mapAccount.put(a.PartnerID__c, a.Id);
     
    }
     for(Lead o : trigger.new){

        AccIds.add(o.Partner_Account_24__c);
    } 
    for(Account a : [SELECT Id, PartnerID__c, Name FROM Account WHERE Id IN :AccIds]){
    
    mapAcc.put(a.Id,a.PartnerID__c);
     
    }
   
    for(Lead l:  trigger.new){
    if(l.RecordTypeId == leadRecordTypeId){
       if(l.PartnerID__c!=null){
           if( mapAccount.containsKey(l.PartnerID__c))
           {
            l.Partner_Account_24__c = mapAccount.get(l.PartnerID__c);
    }
}
          if(l.PartnerID__c == null || l.Partner_Account_24__c!=null){
           if( mapAcc.containsKey(l.Partner_Account_24__c))
           {
            l.PartnerID__c = mapAcc.get(l.Partner_Account_24__c);
    }
           
      }     
           
      }      
    }    
    
   
}

Test Class:
@isTest
public class TestLeadTriggerPardot {
   
    @isTest static void LeadPardot (){
      
                Account acc = new Account(
                Name = 'Test Temp Account',
                PartnerID__c = '6789'
                );
            insert acc; 
        
              
        
        Lead ld = new Lead(
        PartnerID__c = '6789',
        Partner_Account_24__c = 'Test Temp Account',
        LastName = 'Test Lead',
        Company = 'ABC',
        LeadSource ='Phone'
            );
        insert ld;
        
      
          }
    Static testMethod void insertLeadItem()
    
      {   
        
        
        Lead l=[select id, Partner_Account_24__c from Lead where PartnerID__c = '6789'];
        system.assertequals(l.Partner_Account_24__c, null);
      }
        
        Static testMethod void insertLeadItem_Null()
    
      {   
      
        Lead l=[select id,Partner_Account_24__c from Lead where  PartnerID__c  = '6789'];
         Account a =[select id , PartnerID__c,Name from Account where PartnerID__c = '6789'];
       
       l.PartnerID__c  = '6789';
        update l;
        
      Lead lead =[select id ,Partner_Account_24__c from Lead where Id=:l.id];
        system.assertequals(lead.Partner_Account_24__c, a.PartnerID__c);
      }

}