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. Commented Sep 8, 2021 at 13:13

1 Answer 1


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??? Commented Sep 8, 2021 at 11:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .