i am trying To display two fields from two different objects in a single column of a table & creating new records with the help of them.
actually i am trying to create a customize product line item visualforce page almost similar to the standard one, so here i need to add the products with some more information so for that i have created few more fields in opportunity line item, i have already created the selct product page in which i am selecting the products and the i am redirecting to the next page with those selected productn so now on this page i'll be writing a wrapper class which will help me to show these products with opportunity line item custom fields that i need to fill on this page but after filling them how i can create a records containing table products with corresponding values in opportunity line item. plz someone help me out.
[SalesForce] To display two fields from two different objects in a single column of a table & creating new records with the help of them
Related Solutions
As the error states, you need to specify the opportunity id. Presumably, you'll find the opportunity attached to the order.
That probably looks like this:
trigger CreateOpportunityProduct on Order_Line_Item__c(after insert, after update){
if(trigger.isUpdate)
{
map<id, order__c> orders = new map<id, order__c>();
List<ID> pricebookID=new List<ID>();
List<ID> opportunityID=new List<ID>();
List<OpportunityLineItem> newopportunitylineitemlist=new List< OpportunityLineItem>();
for(order_line_item__c record: trigger.new) {
orders.put(record.order__c, null);
}
orders.putall([select id, opportunity__c from order__c where id in :orders.keyset()]);
for(Order_Line_Item__c orderlist: Trigger.new){
OpportunityLineItem Oppitem=new OpportunityLineItem();
Oppitem.Quantity=orderlist.Quantity__c;
Oppitem.UnitPrice=orderlist.UnitPrice__c;
oppitem.opportunityid = orders.get(orderlist.order__c).opportunity__c;
pricebookID.add(Oppitem.PriceBookEntryId);
opportunityID.add(Oppitem.OpportunityId);
newopportunitylineitemlist.add(Oppitem);
}
List<Order__c> orderlist= new List<Order__c>([Select Id,Opportunities__c From Order__c Where Opportunities__c IN:opportunityID]);
List<PricebookEntry> pricebookentrylist = new List<PricebookEntry>([Select Id,Product2Id From PricebookEntry Where Id IN:pricebookID]);
if(newopportunitylineitemlist.size()>0)
insert(newopportunitylineitemlist);
}
}
Adjust field names as necessary.
I think easiest would be to do a bit more work in after insert, set the Id of the Order Line Item on the Opportunity Line Item. You probably have there something similar to this:
OpportunityLineItem oli = new OpportunityLineItem(OpportunityId = ...,
PricebookEntryId = ...,
Quantity = orderLineItem.Quantity__c,
UnitPrice = orderLineItem.Price__c
);
items.add(oli);
// (...)
insert items;
Simply add 1 more field there:
OpportunityLineItem oli = new OpportunityLineItem(OpportunityId = ...,
PricebookEntryId = ...,
Quantity = orderLineItem.Quantity__c,
UnitPrice = orderLineItem.Price__c,
Source_order_line_item__c = orderLineItem.Id,
);
items.add(oli);
Then in after update you can fetch all matching Opp Line Items:
List<OpportunityLineItem> olis = [SELECT Id, Source_order_line_item__c
FROM OpportunityLineItem
WHERE Source_order_line_item__c IN :trigger.newMap().keyset()];
And go through them
for(OpportunityLineItem oli : olis){
Order_Line_Item__c matchingOrderLine = trigger.newMap().get(oli.Source_order_line_item__c);
oli.Quantity = matchingOrderLine.Quantity__c;
oli.UnitPrice = matchingOrderLine.Price__c;
// etc
}
update olis;
You probably could even improve the last part by querying with "dot" directly (if it will be after update trigger so the new values are saved to database):
SELECT Id, Source_order_line_item__r.Quantity__c, Source_order_line_item__r.Price__c
FROM OpportunityLineItem
WHERE Source_order_line_item__c IN :trigger.newMap().keyset()
No need to use trigger.newMap() anymore, directly overwrite the values
for(OpportunityLineItem oli : olis){
oli.Quantity = oli.Source_order_line_item__r.Quantity__c;
oli.UnitPrice = oliSource_order_line_item__r.Price__c;
}
update olis;
If you don't want to do this extra step during insert (or are worried about existing data) it gets much trickier because how do you know that this line on Opportunity was based on that line on Order? You'd have to somehow consider them matching if for example Product (or PricebookEntry) + Quantity + Price
match (you could have multiple lines on the order about the same product). But then the whole point of update is that values can change ;) So you would have to be matching OppLineItems in DB with trigger.old but write values from trigger.new. Hardcore...
It's doable but a lot can go wrong in code like this. Just identifying the source reference can save you a lot of grief later on. And since it'll be a lookup you could easily build reports that list values side by side to look for problems.
Last edit I'm not touching it anymore, you're doing it wrong and it'll haunt you.
/* On update of opportunity line item(s)
try to find matching Order_Line_Item__c and update it.
there's a lookup(Opportunity) on Order__c and Order_Line_Item__c has lookup(Product2)
I really struggle to understand why you DON'T want to set "source line item Id" on order line item,
similarly how you DO set "source Opp Id" on Order... True, we can't make lookups to Opp Line Items but you could have Text(18) field marked as external Id and life would be simpler.
It is a really tricky piece of logic and I don't guarantee it'll work. Having a helper field with source would make stuff much easier.
Or you could just say "screw it" and on update of line items delete & recreate the order lines completely (you already have code to create them in the on insert trigger).
But ok. It's your maintenance nightmare.
Assumption - on given order there combination "opportunity id - product id - quantity" must be unique. If on 1 order you have 2 lines about same product and same quantity - I don't know which one to update.
*/
trigger syncOppLineItemToOrderLineItem (after update){
// 1. On Opp Line Item we don't have product links but the pricebook links. Need to get the product ids so let's start with getting a "dictionary".
Set<Id> pricebookEntries = new Set<Id>();
Set<Id> opportunityIds = new Set<Id>(); // we'll need these later too
for(OpportunityLineItem oli : trigger.old){
pricebookEntryToProduct.add(oli.PricebookEntryId);
opportunityIds.add(oli.OpportunityId);
}
for(OpportunityLineItem oli : trigger.new){
pricebookEntryToProduct.add(oli.PricebookEntryId);
}
Map<Id, Id> pricebookEntryToProduct = new Map<Id, Id>();
for(PricebookEntry pe : [SELECT Id, Product2Id FROM PricebookEntry WHERE Id IN :pricebookEntries]){
pricebookEntryToProduct.put(pe.Id, pe.Product2Id);
}
// 2. Build the keys consisting of "opportunity id - product id - quantity" (old values)
Map<String, Id> keysFromTriggerOld = new Map<String, Id>();
for(OpportunityLineItem oli : trigger.old){
keysFromTriggerOld.put(oli.OpportunityId + ' ' + pricebookEntryToProduct.get(oli.PricebookEntryId).Product2Id + ' ' + oli.Quantity, oli.Id);
}
System.debug(keysFromTriggerOld);
// 3. Fetch all Order Line Items that are based on Opportunities which are being modified here (that's why we needed the set)
// and that are related to products we know we can match.
List<Order_Line_Item__c> orderLines = [SELECT Order__r.Opportunity__c, Product__c, Quantity__c
FROM Order_Line_Item__c
WHERE Order__r.Opportunity__c IN :opportunityIds AND Product__c IN :pricebookEntryToProduct.values()];
// 4. So based on values from order lines we'll be able to match it to old OppLineItem. And the Id will be same as new OppLineItem (obviously).
// So we can go order line -> "key" -> old opp line -> id -> new opp line's values -> copy them to the order line.
for(Order_Line_Item__c oli : orderLines){
String key = oli.Order__r.Opportunity__c + ' ' + oli.Product__c + ' ' + oli.Quantity__c;
System.debug('Looking for ' + key);
if(keysFromTriggerOld.contains(key)){
Id oppLineItemId = keysFromTriggerOld.get(key);
System.debug('Found! ' + oppLineItemId);
OpportunityLineItem newValues = trigger.newMap(oppLineItemId);
oli.Product__c = pricebookEntryToProduct.get(newValues.PricebookEntryId); // serious black magic here
oli.Quantity__c = newValues.Quantity;
oli.Unit_Price__c = newValues.ListPrice;
// copy over more fields from "newValues" as needed
} else {
System.debug('Could not find the match: ' + oli);
}
}
// 5. Save. Uff.
update orderLines;
}
Best Answer
Create a wrapper class with product and new OLI
So you can bind the value using apex:inputField in VF page. And get the all list in controller and then you can create OLI
IN VF Page