function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Andrew LikensAndrew Likens 

Click button to create opportunity line items on a custom object related list

Hello,

I'm looking to create a button that when clicked, will create an opportunity line item on a custom object related to the opportunity as a related list. Very similar to syncing opp line items and quote line items. My custom object is called "Product__c" and has fields Quantity, Description, Amount, etc., same as opp line items. The Product__c object is a child of "Virtual_Request__C" object that has a lookup to the opportunity. I want the Product__c fields to match the standard opp line item fields.

I'm unsure if a trigger is used here or apex code because I want the action to occur from a button click. Any help is greatly appreciated!
Saurabh BSaurabh B
Hi Andrew, just to make sure I understand the requirements, when 'Product__c' gets created under 'Virtual_Request__C', what information will that contain? is that going to be a blank record?

Trigger fires on a DML operations (Insert, update, delete etc.). If you need this to fire via button, Batch class can be called from a button.
Andrew LikensAndrew Likens
Thanks for the reply! Product__c is a related list under the Virtual_Request__c object. Essentially, all I want is to click on a button on the opportunity line item related list and have the opportunity line item(s) be created as a Product__c on the Virtual_Request__c object.

OppLineItem.Amount = Product__c.Amount
OppLineItem.Quantity = Product__c.Quantity
OppLineItem.Description = Product__c.Description
And so on.....

Hope this provides clarification.
Saurabh BSaurabh B
OK. So you mean, if Opportunity has 2 Opportunity Line Items, then both of those should get copied over as "Product__c" records under "Virtual_Request__c" object  ... is that correct?
Andrew LikensAndrew Likens
Correct :)
Saurabh BSaurabh B
Hi Andrew, here is your Batch class that will create new "Products" on "Virtual_Request__c" object. All information in the newly created Products will be fetched from Opportunity Line Items availbale on the Opportunity that is related to "Virtual_Request__c". I have tested this in my Dev org and it appears to work fine.

Batch Class:
global class UpdateProductBatch implements Database.Batchable<sObject>{

        global Database.QueryLocator start(Database.BatchableContext BC){
		String query = 'SELECT Id FROM Opportunity' ;
         return Database.getQueryLocator(query);
        }
      
       global void execute(Database.BatchableContext BC, List<Opportunity>scope){
           
           List <Product__c> ProdList = New  List <Product__c>  ();
           Set <Id> oppidsets = New Set <Id> ();
		Map <Id,ID> VRMap = New Map  <Id,ID> ();
           
           For (Opportunity O : Scope) {
              oppidsets.add(O.ID) ; 
           }   
     
          List <Virtual_Request__C> VRList = [SELECT ID, Opportunity__c FROM Virtual_Request__C WHERE Opportunity__c IN: oppidsets];
                         system.debug('VRList'+ VRList);
     
                      For (Virtual_Request__C VR : VRList) {
                          If (VR.Opportunity__c != null)
                          VRMap.put(VR.Opportunity__c, VR.ID);
               				}
  
           List <OpportunityLineItem> OLIList = [SELECT Id,Name,OpportunityId,Description,Quantity,TotalPrice FROM OpportunityLineItem WHERE OpportunityId  IN : oppidsets ];
           system.debug('OLIList'+ OLIList);
           For (OpportunityLineItem OLI : OLIList) {

   				 Product__c P = New Product__c ();
               	P.Name = OLI.name;
               	P.Quantity__c = OLI.Quantity;          
               	P.Amount__c = OLI.TotalPrice;
               	P.Description__c = OLI.Description;
                P.Virtual_Request__C = VRMap.get(OLI.OpportunityId);
				ProdList.add(P);
           }               
             insert ProdList;
           }
    
       global void finish(Database.BatchableContext BC){

       }
    }

After you create/save this Batch Class, you should create a Javascript - Detail Page Button on your "Virtual_Request__C" object. ** Do not forget to add button on the layout after it is created.

Button:
{!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}

{!REQUIRESCRIPT("/soap/ajax/29.0/apex.js")}

var scr="UpdateProductBatch sat = new UpdateProductBatch(); " + 
" database.executebatch(sat); ";
var result = sforce.apex.executeAnonymous(scr);

alert("Creating New Products from Opportunity Line Items ... ");

Hope this helps.

-Saurabh

 
Andrew LikensAndrew Likens
Thank you so much for this! However, I'm receiving the following error:

Compile Error: Argument type of global method must also be global: List<Opportunity> at line 8 column 20
Saurabh BSaurabh B
Wierd. I didnt recieve any errors in my Dev org. Are you copying code as it is or/ are you making any edits to the code?
Andrew LikensAndrew Likens
Copied the code. Yep, it is weird.
Saurabh BSaurabh B
Below is the updated code. Can you try now? Also, make sure API version of class is 38 ..
 
global class UpdateProductBatch implements Database.Batchable<sObject>{

        global Database.QueryLocator start(Database.BatchableContext BC){
		String query = 'SELECT Id FROM Opportunity' ;
         return Database.getQueryLocator(query);
        }
      
       global void execute(Database.BatchableContext BC, List <sObject> scope){
           
           List <Product__c> ProdList = New  List <Product__c>  ();
           Set <Id> oppidsets = New Set <Id> ();
		Map <Id,ID> VRMap = New Map  <Id,ID> ();
           
           For (Opportunity O : (List<Opportunity>) Scope) {
              oppidsets.add(O.ID) ; 
           }   
     
          List <Virtual_Request__C> VRList = [SELECT ID, Opportunity__c FROM Virtual_Request__C WHERE Opportunity__c IN: oppidsets];
                         system.debug('VRList'+ VRList);
     
                      For (Virtual_Request__C VR : VRList) {
                          If (VR.Opportunity__c != null)
                          VRMap.put(VR.Opportunity__c, VR.ID);
               				}
  
           List <OpportunityLineItem> OLIList = [SELECT Id,Name,OpportunityId,Description,Quantity,TotalPrice FROM OpportunityLineItem WHERE OpportunityId  IN : oppidsets ];
           system.debug('OLIList'+ OLIList);
           For (OpportunityLineItem OLI : OLIList) {

   				 Product__c P = New Product__c ();
               	P.Name = OLI.name;
               	P.Quantity__c = OLI.Quantity;          
               	P.Amount__c = OLI.TotalPrice;
               	P.Description__c = OLI.Description;
                P.Virtual_Request__C = VRMap.get(OLI.OpportunityId);
				ProdList.add(P);
           }               
             insert ProdList;
           }
    
       global void finish(Database.BatchableContext BC){

       }
    }

 
Andrew LikensAndrew Likens
Thank you for all your efforts on this! Receiving another error now. It's on version 38.

Error: Compile Error: Variable does not exist: ID at line 15 column 29
Andrew LikensAndrew Likens
Hello, did you get a chance to review my latest error? Thanks.