2

So in an attempt to convert an OpportunityLineItem into an OrderItem, I get the mysterious and vague INVALID_CROSS_REFERENCE_KEY Error on insert of an OrderItem list.

What's odd is my test class runs perfectly fine when doing the conversion. That's what is peculiar.

I will provide both the test code and the actual code to see if there are any gaps anywhere that I'm missing.

Here is some code to help convey what I am doing:

Code to convert OpportunityLineItem

public Map<Id, List<OrderItem>> ConvertOpportunityLineItemsToOrderItems(Set<Id> opportunityIdSet)
{
    if(opportunityIdSet == null || opportunityIdSet.size() == 0)
        return new Map<Id, List<OrderItem>>();

    Map<Id, List<OrderItem>> orderItems = new Map<Id, List<OrderItem>>();

    for(OpportunityLineItem lineItem : [SELECT PricebookEntryId, Quantity, UnitPrice, OpportunityId FROM OpportunityLineItem WHERE OpportunityId IN :opportunityIdSet])
    {
        if(orderItems.get(lineItem.OpportunityId) == null)
            orderItems.put(lineItem.OpportunityId, new List<OrderItem>());

        orderItems.get(lineItem.OpportunityId).add(new OrderItem(PricebookEntryId = lineItem.PricebookEntryId, Quantity = lineItem.Quantity, UnitPrice = lineItem.UnitPrice));
    }

    return orderItems;
}

Test Utility code to generate OpportunityLineItem records

public static List<OpportunityLineItem> CreateTestOpportunityLineItems(Integer numberOfRecords)
{
    sObject testOpportunity = TestsObjectGeneratorUtility.RetrieveGenerator(Opportunity.sObjectType).GenerateTestsObjects(1, true)[0];
    List<sObject> testProducts = TestsObjectGeneratorUtility.RetrieveGenerator(Product2.sObjectType).GenerateTestsObjects(numberOfRecords, true);

    List<PricebookEntry> testEntries = new List<PricebookEntry>();

    for(sObject testProduct : testProducts)
        testEntries.add(new PricebookEntry(Pricebook2Id = Test.getStandardPricebookId(), Product2Id = testProduct.Id, UnitPrice = 9001, IsActive = true));
    INSERT testEntries;

    List<OpportunityLineItem> lineItems = new List<OpportunityLineItem>();
    for(sObject testEntry : testEntries)    
        lineItems.add(new OpportunityLineItem(Discount = 0, PricebookEntryId = testEntry.Id, Quantity = 1, UnitPrice = 500, OpportunityId = testOpportunity.Id));
    INSERT lineItems;
    return lineItems;   
}

Code in Test method

This code runs to completion without an Exceptions.

TestUtilities.CreateTestOpportunityLineItems(3);
Opportunity testOpportunity = [SELECT Id FROM Opportunity LIMIT 1]; 

//Convert OpportunityLineItems
List<OrderItem> orderItems = (new OrderService()).ConvertOpportunityLineItemsToOrderItems(opportunityLineItemIds).get(testOpportunity.Id);

//Convert Opportunity to Order
Order testOrder = (new OrderService()).ConvertOpportunitiesToOrders(new Set<Id>{ testOpportunity.Id })[0];
INSERT testOrder;

for(OrderItem singleItem : orderItems)
    singleItem.OrderId = testOrder.Id;
INSERT orderItems;

Code in Anonymous Apex

This code fails with INVALID_CROSS_REFERENCE_KEY error

Id testingId = 'xxxxxxxxxxxxxxx';

Order newOrder = (new OrderService()).ConvertOpportunitiesToOrders(new Set<Id>{ testingId })[0];
INSERT newOrder;

List<OrderItem> orderItems = (new OrderService()).ConvertOpportunityLineItemsToOrderItems(new Set<Id>{ testingId }).get(testingId);
for(OrderItem singleItem : orderItems)
    singleItem.OrderId = newOrder.Id;
INSERT orderItems;

Here are some other notes:

  • As far as I can tell, the OpportunityLineItem does have entries in the Standard Pricebook
  • The OpportunityLineItem is available to be queried (otherwise, it wouldn't fail at all
  • The PricebookEntryId is available

I am at my wits end on this one. The error doesn't help at all in troubleshooting and this is the last feature I need to implement... Any help would be most appreciated.

  • 1
    1) as an aside ConvertOpportunityLineItemsToOrderItems should return an empty list if the input id set is null or empty. 2) Your logic in this class is problematic in other ways -- if the size of the opportunityidSet is > 1, the caller has no way of knowing which line items belong to which order parent to assign the orderId into the OrderItem collection – cropredy Apr 12 '15 at 21:37
  • 1
    3) Note also that anon Apex runs at V33 (current version) whereas classes run at their metadata level – cropredy Apr 12 '15 at 21:46
  • Thank you for the tips @crop1645. I will definitely add that logic to my method. Those asides are extremely helpful. That's what happens when you rush a Proof of Concept, I guess. – Programmable Medley Apr 12 '15 at 22:14
0

I finally found out what it was. Apparently, there was two Pricebooks. Once was call Standard and one was the Standard Pricebook. I actually set the Pricebook2Id on the order to the standard pricebook instead of the pricebook called Standard. Once I found that out, the rest was rather easy. Confusing, but none the less, informative.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.