0
votes

Hello Acumatica Community! I am running into an issue that I hope you can help with.

Users are creating service orders from opportunities. They are using project quotes. When the service order is created, I need to not include certain lines, for example, services. I tried finding a method to override when the service order is being created, but I was unsuccessful. So I tried using the RowInserting event and set e.Cancel = true. However, doing this gives me an error Object reference not set to an instance of the object. I can only assume that the CreateServiceOrder method is trying to update the row after I cancelled the insertion.

Then I tried using the RowUpdated event. When debugging, it appears that the row is removed from the cache (not put into the dirty queue, just removed). However, when the service order is finished creating, the row is still in the grid. I tried using RequestRefresh on the view, but to no avail. The gist of the code is below. Any help would be greatly appreciated, as always!

public bool _isCreating = false;
protected virtual void FSSODet_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e)
{
    var row = e.Row as FSSODet;
    if (row == null) return;

    if (row.LastModifiedByScreenID == "CR304000" && row.RefNbr.Contains("<NEW>"))
    {
        if (!_isCreating)
        {
            _isCreating = true;
            InventoryItem item = 
                PXSelect<InventoryItem, 
                    Where<InventoryItem.inventoryID,
                        Equal<Required<FSSODet.inventoryID>>>>
                .SelectSingleBound(Base, new object[] { }, row.InventoryID);
            var itemExt = item.GetExtension<InventoryItemExt>();
            if (!(item?.StkItem ?? false))
            {
                cache.Delete(row);
                //Base.ServiceOrderDetails.Delete(row);
                Base.ServiceOrderDetails.Cache.RaiseRowDeleting(row);
                Base.ServiceOrderDetails.Cache.RaiseRowDeleted(row);
                Base.ServiceOrderDetails.View.RequestRefresh();
            }
            _isCreating = false;
        }
    }
}
1

1 Answers

1
votes

The code file which powers the process to create Service Orders from Opportunity Quotes, is called SM_OpportunityMaintExtension. You can find this graph inside the folder \CodeRepository\PX.Objects.FS.

To accomplish your goal, you will extend the method named CreateServiceOrderDocument. So create a graph extension and be sure to create a delegate for that method.

Notice inside the base method, the lines which loop through the CROpportunityProducts. Here is where you can add your custom code (i.e pick & choose which items to push to the Service Order) Example below, only pushes the CROpportunity item, if the DiscountAmount = 0

public delegate void CreateServiceOrderDocumentDelegate(OpportunityMaint graphOpportunityMaint, CROpportunity crOpportunityRow, FSCreateServiceOrderFilter fsCreateServiceOrderFilterRow);
    [PXOverride]
    public void CreateServiceOrderDocument(OpportunityMaint graphOpportunityMaint, CROpportunity crOpportunityRow, FSCreateServiceOrderFilter fsCreateServiceOrderFilterRow,
        CreateServiceOrderDocumentDelegate baseMethod)
    {            

        if (graphOpportunityMaint == null
                || crOpportunityRow == null
                    || fsCreateServiceOrderFilterRow == null)
        {
            return;
        }

        ServiceOrderEntry graphServiceOrderEntry = PXGraph.CreateInstance<ServiceOrderEntry>();

        FSServiceOrder newServiceOrderRow = CRExtensionHelper.InitNewServiceOrder(fsCreateServiceOrderFilterRow.SrvOrdType, ID.SourceType_ServiceOrder.OPPORTUNITY);

        CRSetup crSetupRow = GetCRSetup();

        graphServiceOrderEntry.ServiceOrderRecords.Current = graphServiceOrderEntry.ServiceOrderRecords.Insert(newServiceOrderRow);

        CRExtensionHelper.UpdateServiceOrderHeader(graphServiceOrderEntry,
                                                   Base.Opportunity.Cache,
                                                   crOpportunityRow,
                                                   fsCreateServiceOrderFilterRow,
                                                   graphServiceOrderEntry.ServiceOrderRecords.Current,
                                                   Base.Opportunity_Contact.Current,
                                                   Base.Opportunity_Address.Current,
                                                   true);


        foreach (CROpportunityProducts crOpportunityProductsRow in graphOpportunityMaint.Products.Select())
        {
            if (crOpportunityProductsRow.DiscAmt == 0)  //only add the item to the service order if no discount!!!
            {
                InventoryItem inventoryItemRow = SharedFunctions.GetInventoryItemRow(graphServiceOrderEntry, crOpportunityProductsRow.InventoryID);

                if (inventoryItemRow.StkItem == true
                        && graphServiceOrderEntry.ServiceOrderTypeSelected.Current.PostTo == ID.SrvOrdType_PostTo.ACCOUNTS_RECEIVABLE_MODULE)
                {
                    throw new PXException(TX.Error.STOCKITEM_NOT_HANDLED_BY_SRVORDTYPE, inventoryItemRow.InventoryCD);
                }

                FSxCROpportunityProducts fsxCROpportunityProductsRow = graphOpportunityMaint.Products.Cache.GetExtension<FSxCROpportunityProducts>(crOpportunityProductsRow);
                CRExtensionHelper.InsertFSSODetFromOpportunity(graphServiceOrderEntry, graphOpportunityMaint.Products.Cache, crSetupRow, crOpportunityProductsRow, fsxCROpportunityProductsRow, inventoryItemRow);
            }
        }

        graphServiceOrderEntry.ServiceOrderRecords.Current.SourceRefNbr = crOpportunityRow.OpportunityID;

        if (!Base.IsContractBasedAPI)
        {
            throw new PXRedirectRequiredException(graphServiceOrderEntry, null);
        }            
    }