I am trying to add Service Contracts and the Contract Line Items from Order Products. Also I am adding Entitlements and Referencing Proforma Invoices at same time. Following is my Code...

public class GenerateServiceContract {
    public static void fetchOrderItems(List<Id> orderId) {
        List<Order> relatedOrder = [SELECT Id, AccountId, Account.Name, Opportunity__c, Order_Name__c, PriceBook2Id FROM Order WHERE Id = :orderId FOR UPDATE];
        List<OrderItem> oproduct = [SELECT Id, PriceBookEntryId, Product2Id, Product_Name__c, Quantity, Contact_Name__c, UnitPrice, Department__c, Deposit_Amount__c FROM OrderItem WHERE OrderId = :orderId ORDER BY UnitPrice DESC];

        Set<String> itemDepartment = new Set<String>();
        Map<String, Id> contractIds = new Map<String, Id>();
        Id singleContractId;
        Integer indexOf = 1;
        for (OrderItem oitem: oproduct) {
            if (oitem.Deposit_Amount__c != 0) {
                addContractLineItems(singleContractId, relatedOrder[0].AccountId, oitem.Id);
                updateProformaInvoices(singleContractId, contractIds.get(oitem.Department__c), oitem.Id);
            if (itemDepartment.contains(oitem.Department__c) && oitem.Deposit_Amount__c == 0) {
                addContractLineItems(contractIds.get(oitem.Department__c), relatedOrder[0].AccountId, oitem.Id);
                updateProformaInvoices(relatedOrder[0].Id, contractIds.get(oitem.Department__c), oitem.Id);
            } else {
                if (oitem.Deposit_Amount__c == 0) {
                    ServiceContract scontract = new ServiceContract(
                        OpportunityId__c = relatedOrder[0].Opportunity__c,
                        Name = oitem.Product_Name__c +' - '+ relatedOrder[0].Account.Name,
                        AccountId = relatedOrder[0].AccountId,
                        PriceBook2Id = relatedOrder[0].PriceBook2Id
                    insert scontract;
                    contractIds.put(oitem.Department__c, scontract.id);
                    addContractLineItems(scontract.id, scontract.AccountId, oitem.Id);
                    updateProformaInvoices(relatedOrder[0].Id, scontract.id, oitem.Id);
                    if (indexOf == 1) {
                        singleContractId = scontract.id;

    public static void addContractLineItems(Id contractId, Id accountId, Id orderItemId) {
        List<OrderItem> oproduct = [SELECT Id, PriceBookEntryId, Product2Id, Quantity, Contact_Name__c, UnitPrice, Deposit_Amount__c, Department__c FROM OrderItem WHERE Id = :orderItemId LIMIT 1];

        ContractLineItem citems = new ContractLineItem(
            ServiceContractId = contractId,
            PriceBookEntryId = oproduct[0].PriceBookEntryId,
            Quantity = oproduct[0].Quantity,
            UnitPrice = oproduct[0].UnitPrice,
            Deposit_Amount__c = oproduct[0].Deposit_Amount__c

        try {
            insert citems;
            addEntitlements(contractId, accountId, citems.Id);
        } catch (Exception e) {}

    public static void addEntitlements(Id serviceContractId, Id accountId, Id contractItemId) {
        List<ContractLineItem> cproducts = [SELECT Id FROM ContractLineItem WHERE ServiceContractId = :serviceContractId AND Id = :contractItemId];

        Entitlement entitlement = new Entitlement(
            AccountId = accountId,
            ServiceContractId = serviceContractId,
            ContractLineItemId = contractItemId,
            Name = 'Need to visit the Client'

        try {
            insert entitlement;
        } catch (Exception e) {}
    public static void updateProformaInvoices(Id orderId, Id serviceContractId, Id orderItemId) {
        List<Proforma_Invoice__c> pinvoice = [SELECT Id, Service_Contract__c FROM Proforma_Invoice__c WHERE Order__c = :orderId AND Order_Product__c = :orderItemId];
        Proforma_Invoice__c[] recordsToUpdate = new Proforma_Invoice__c[0];
        for (Proforma_Invoice__c pinv: pinvoice) {
            recordsToUpdate.add(new Proforma_Invoice__c(
                Id = pinv.Id,
                Service_Contract__c = serviceContractId
        update recordsToUpdate;

Before this code was working fine and even now on production it is working fine, but in Sandbox now it is giving this error "Insert failed first error: UNABLE_TO_LOCK_ROW, unable to obtain exclusive access to this record or 1 records: 01s4J000002l5eqQAA: []".

The error it shows on line where Service Contract is adding "insert scontract".

Can anyone please help me with this issue as I tried the solutions online but no luck.

  • If I remove Account Id and PriceBookId from insert then the error is removed. But I need these two attributes as they are lookup fields. Is there any solution for this...anyone. Sep 8 at 13:13

You are doing DML in Loop which is not a good practice and also may lock rows. You should add all your records in Maps and then insert/update them after the loop so that you do not lock anything.

  • Thank you Luisma for your response. I am fully aware of the fact that we shouldn't do DML in loop. But my requirement to add products with similar department to single service contract make me do this. I don't know how to do it without loop. Is there a way to avoid this error in current situation??? Sep 8 at 11:43

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.