Skip to main content

Hi Team,

We have an issue with additional row getting added in a grid after selecting a value from selector.

Issue

  1. Selecting an inventory Id from a Selector
  1. After the selecting from the selector an additional row is added

    Any thoughts why there is an additional row populating?

HI @vibindas  Do you have any customizations in the SO301000 screen?

 


@Naveen Boga , yes and also upgraded recently to 2022R1 from 2019R1. It used to work in 2019.


@vibindas, Below are few option you can try to fix the issue,

  • Check if the issue is reproducible without the customization
  • If the issue is reproducible with the customization only, you can debug the customization to narrow down to the cause of the issue

@vibindas  Possible to share the source code here for our review?


sharing only the skeleton of the events related to CROpportunityProducts. Hope this helps...


namespace PX.Objects.CR
{
    public class MAKLQuoteMaintExt : PXGraphExtension<QuoteMaint>
    {
        PXDBInt(IsKey = true)]
        PXLineNbr(typeof(CRQuote.productCntr))]
        rPXUIField(DisplayName = "Line", Enabled = false)]
        protected virtual void CROpportunityProducts_LineNbr_CacheAttached(PXCache e) { }

        )PXMergeAttributes]
        tPXRemoveBaseAttribute(typeof(InventoryAttribute))]
        rInventory(typeof(Search5<InventoryItem.inventoryID,
                LeftJoin<INItemClass, On<INItemClass.itemClassID, Equal<InventoryItem.itemClassID>>,
                LeftJoin<PMTask, On<PMTask.taskID, Equal<MAKLXBINItemClassExt.usrMAKLCommonTaskID>>,
                LeftJoin<MAKLEdition, On<MAKLEdition.editionID, Equal<MAKLXBInventoryItemExt.usrMAKLEditionID>>,
                LeftJoin<MAKLEdition2, On<MAKLEdition2.editionID, Equal<Current<MAKLCRQuoteExt.usrMAKLEditionID>>>>>>>,
                Where2<Match<Current<AccessInfo.userName>>,
                    And<InventoryItem.itemStatus, NotEqual<InventoryItemStatus.inactive>,
                    And<InventoryItem.itemStatus, NotEqual<InventoryItemStatus.markedForDeletion>,
                    And2<Where<MAKLXBInventoryItemExt.usrMAKLIsInternal, Equal<False>,
                        Or<Exists<Select<Users,
                            Where<Users.pKID, Equal<Current<AccessInfo.userID>>,
                                And<Users.guest, Equal<False>>>>>>>,
                    And2<
                        Where<MAKLXBInventoryItemExt.usrMAKLEditionID, Equal<Current<MAKLCRQuoteExt.usrMAKLEditionID>>,
                            Or<MAKLXBInventoryItemExt.usrMAKLEditionID, IsNull,
                            Or<Current<MAKLCRQuoteExt.usrMAKLEditionID>, IsNull,
                            Or<MAKLEdition.isExclusive, Equal<False>,
                            Or<MAKLEdition2.isExclusive, Equal<False>>>>>>,
                        And<PMTask.taskCD, Equal<Current<CRQuote.opportunityClassID>>>>>>
                    >>,
                Aggregate<GroupBy<InventoryItem.inventoryID>>>),
            typeof(InventoryItem.inventoryCD), typeof(InventoryItem.descr), Filterable = true)]
        protected virtual void CROpportunityProducts_InventoryID_CacheAttached(PXCache e) { }

        vPXDBInt(IsKey = true)]
                protected virtual void MAKLOpportunityHistory_LineNbr_CacheAttached(PXCache e) { }

       

       yPXViewName(Messages.QuoteProducts)]
        PXFilterable]
        /PXImport(typeof(CRQuote))]
        public PXSelect<CROpportunityProducts,
            Where<CROpportunityProducts.quoteID, Equal<Current<CRQuote.quoteID>>>,
            OrderBy<Asc<MAKLCROpportunityProductsExt.usrMAKLSortOrder>>>
            Products;

        public override void Initialize()
        {
            base.Initialize();            
        }

       
          public virtual void CROpportunityProducts_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
        {
            if (InvokeBaseHandler != null) InvokeBaseHandler(sender, e);
            CROpportunityProducts row = (CROpportunityProducts)e.Row;
            if (row?.InventoryID == null) return;
            MAKLCROpportunityProductsExt rowE = PXCache<CROpportunityProducts>.GetExtension<MAKLCROpportunityProductsExt>(row);

            bool downgradeItem = rowE.UsrMAKLContrSourceLineNbr != null;
            bool sourceItem = false;
            switch (rowE.UsrMAKLSourceLineType)
            {
                case MAKLOpportunitySourceLineTypes.Bundle:
                case MAKLOpportunitySourceLineTypes.Margin:
                case MAKLOpportunitySourceLineTypes.Unit:
                    sourceItem = true;
                    break;
            }
            if (downgradeItem || sourceItem)
            {
                if (e.Row != null)
                    PXUIFieldAttribute.SetEnabled(sender, row, false);
            }
            else
            {
                
                InventoryItem item = PXSelect<InventoryItem, Where<InventoryItem.inventoryID, Equal<Required<InventoryItem.inventoryID>>>>
              .Select(Base, row.InventoryID);
                MAKLXBInventoryItemExt itemE = PXCache<InventoryItem>.GetExtension<MAKLXBInventoryItemExt>(item);
                if (e.Row == null) return;

                PXUIFieldAttribute.SetEnabled<CROpportunityProducts.curyUnitPrice>(sender, row,
                    (itemE.UsrMAKLIsAdhoc == true || itemE.UsrMAKLIsOverridable == true) && row?.IsFree != true);

                PXUIFieldAttribute.SetEnabled<CROpportunityProducts.manualDisc>(sender, row, row.IsFree != true);

                bool autoFreeItem = row.ManualDisc != true && row.IsFree == true;

                if (autoFreeItem)
                {
                    PXUIFieldAttribute.SetEnabled(sender, row, false);
                    PXUIFieldAttribute.SetEnabled<CROpportunityProducts.siteID>(sender, row);
                }
                PXUIFieldAttribute.SetEnabled<CROpportunityProducts.quantity>(sender, row, !autoFreeItem);
                PXUIFieldAttribute.SetEnabled<CROpportunityProducts.isFree>(sender, row, !autoFreeItem && row.InventoryID != null);

                
            }

            if (rowE.UsrMAKLSourceLineType == MAKLOpportunitySourceLineTypes.Bundle)
            {
                PXUIFieldAttribute.SetEnabled<CROpportunityProducts.discPct>(sender, row, true);
                PXUIFieldAttribute.SetEnabled<CROpportunityProducts.discountID>(sender, row, true);
                PXUIFieldAttribute.SetEnabled<MAKLCROpportunityProductsExt.usrMAKLDiscountDuration>(sender, row, true);
            }

            if (rowE.UsrMAKLContrSourceLineNbr != null)
            {
                CROpportunityProducts nextDowngrade = PXSelect<CROpportunityProducts,
                    Where<CROpportunityProducts.quoteID, Equal<Required<CROpportunityProducts.quoteID>>,
                        And<CROpportunityProducts.inventoryID, Equal<Required<CROpportunityProducts.inventoryID>>,
                        And<CROpportunityProducts.lineNbr, Greater<Required<CROpportunityProducts.lineNbr>>,
                        And<CROpportunityProducts.quantity, Less<decimal0>>>>>>
                    .Select(Base, row.QuoteID, row.InventoryID, row.LineNbr);
                PXUIFieldAttribute.SetEnabled<CROpportunityProducts.quantity>(sender, row, nextDowngrade == null && !sourceItem);
            }

            CROpportunityProducts child = PXSelect<CROpportunityProducts,
                Where<CROpportunityProducts.quoteID, Equal<Required<CROpportunityProducts.quoteID>>,
                    And2<Where<MAKLCROpportunityProductsExt.usrMAKLSourceLineType, Equal<MAKLOpportunitySourceLineTypes.unit>,
                        Or<MAKLCROpportunityProductsExt.usrMAKLSourceLineType, Equal<MAKLOpportunitySourceLineTypes.parent>>>,
                    And<MAKLCROpportunityProductsExt.usrMAKLSourceLineNbr, Equal<Required<MAKLCROpportunityProductsExt.usrMAKLSourceLineNbr>>>>>>
                .Select(Base, row.QuoteID, row.LineNbr);
            PXUIFieldAttribute.SetEnabled<CROpportunityProducts.inventoryID>(sender, row, child == null && !sourceItem && !downgradeItem);

        }

      
        public virtual void CROpportunityProducts_RowInserted(PXCache sender, PXRowInsertedEventArgs e, PXRowInserted InvokeBaseHandler)
        {
            if (e.Row == null) return;
            CROpportunityProducts row = (CROpportunityProducts)e.Row;
            ResetManualFlags();
            MAKLCROpportunityProductsExt rowE = PXCache<CROpportunityProducts>.GetExtension<MAKLCROpportunityProductsExt>(row);

            UpdateQuoteEdition(row);

            MAKLCRQuoteExt quoteE = Quote.Cache.GetExtension<MAKLCRQuoteExt>(Quote.Current);
            CROpportunityClass opClass = (CROpportunityClass)PXSelectorAttribute.Select<CRQuote.opportunityClassID>(Quote.Cache, Quote.Current);
            MAKLCROpportunityClassExt opClassE = PXCache<CROpportunityClass>.GetExtension<MAKLCROpportunityClassExt>(opClass);
            bool diffQty = opClassE.UsrMAKLUpsellMethod == MAKLUpsellMethod.Pricelist && quoteE.UsrMAKLType != MAKLOpportunityType.NewSale;

            if (row.Quantity < 0)
            {
                DoDowngrade(row, 0, e.ExternalCall);
            }
            else
            {
                UpdateUpsellDetail(row, row.Quantity);
            }

            AddAutoexplodeLines(row);
            AddUnitLines(row, diffQty);
            DoBundleTree(row, null, MAKLBundleType.Child, diffQty);
            DoBundleTree(row, null, MAKLBundleType.Dependency, diffQty);
            AddMarginLines(row, diffQty);

            if (rowE.UsrMAKLContrSourceLineNbr == null)
            {
                UpdateOtherQuoteLinesPrice(row, Math.Max(row.CuryUnitPrice ?? 0, rowE.UsrMAKLCuryClippedUnitPrice ?? 0));
            }

            if (e.ExternalCall == true)
            {
                Products.View.RequestRefresh();
                UndoRemoveCredit(Quote.Current);
                RemoveCredit(Quote.Current);
            }

            if (InvokeBaseHandler != null) InvokeBaseHandler(sender, new PXRowInsertedEventArgs(Products.Locate(row), e.ExternalCall));
        }


        public virtual void CROpportunityProducts_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e, PXRowUpdated InvokeBaseHandler)
        {
            if (e.Row == null) return;
            CROpportunityProducts row = (CROpportunityProducts)e.Row;
            CROpportunityProducts oldrow = (CROpportunityProducts)e.OldRow;

            MAKLCROpportunityProductsExt rowE = PXCache<CROpportunityProducts>.GetExtension<MAKLCROpportunityProductsExt>(row);
            MAKLCROpportunityProductsExt oldrowE = PXCache<CROpportunityProducts>.GetExtension<MAKLCROpportunityProductsExt>(oldrow);
            MAKLCRQuoteExt quoteE = Quote.Cache.GetExtension<MAKLCRQuoteExt>(Quote.Current);

            CROpportunityClass opClass = (CROpportunityClass)PXSelectorAttribute.Select<CRQuote.opportunityClassID>(Quote.Cache, Quote.Current);
            MAKLCROpportunityClassExt opClassE = PXCache<CROpportunityClass>.GetExtension<MAKLCROpportunityClassExt>(opClass);
            bool diffQty = opClassE.UsrMAKLUpsellMethod == MAKLUpsellMethod.Pricelist && quoteE.UsrMAKLType != MAKLOpportunityType.NewSale;

            if (row.Quantity < 0 && (row.Quantity - oldrow.Quantity < 0 || row.InventoryID != oldrow.InventoryID)
                || !sender.ObjectsEqual<MAKLCROpportunityProductsExt.usrMAKLContrSourceLineNbr>(row, oldrow))
            {
                decimal? oldQuantity = (rowE.UsrMAKLSourceLineType != MAKLOpportunitySourceLineTypes.Margin && oldrow.Quantity < 0
                    || rowE.UsrMAKLSourceLineType == MAKLOpportunitySourceLineTypes.Margin && oldrow.Quantity > 0)
                    ? oldrow.Quantity : 0;
                DoDowngrade(row, oldQuantity, e.ExternalCall);
            }
            else
            {
                UpdateUpsellDetail(row, row.Quantity - oldrow.Quantity);
            }

            if (rowE.UsrMAKLSourceLineType != MAKLOpportunitySourceLineTypes.Margin)
            {
                if (!sender.ObjectsEqual<CROpportunityProducts.inventoryID>(row, oldrow))
                {
                    RemoveAutoexplodeLines(row);
                    AddAutoexplodeLines(row);
                }
                else if (!sender.ObjectsEqual<CROpportunityProducts.quantity, CROpportunityProducts.uOM>(row, oldrow)
                    || !diffQty)
                {
                    AddUnitLines(row, diffQty);
                    if (!sender.ObjectsEqual<CROpportunityProducts.quantity, CROpportunityProducts.uOM>(row, oldrow))
                    {
                        UpdateAutoexplodeLines(row);
                    }
                }

                bool removeMargin = diffQty && row.Quantity < 0 && oldrow.Quantity >= 0 || !diffQty && row.Quantity == 0;
                if (!removeMargin && !diffQty && row.UOM != oldrow.UOM)
                {
                    bool isInt = int.TryParse(row.UOM, out int newUOM);
                    isInt &= int.TryParse(oldrow.UOM, out int oldUOM);
                    removeMargin = isInt && newUOM < oldUOM;
                }
                if (removeMargin)
                {
                    RemoveNonRecurringMargin(row, diffQty);
                }
            }

            DoBundleTree(row, oldrow.Quantity, MAKLBundleType.Child, diffQty);
            DoBundleTree(row, oldrow.Quantity, MAKLBundleType.Dependency, diffQty);

            if (InvokeBaseHandler != null) InvokeBaseHandler(sender, new PXRowUpdatedEventArgs(Products.Cache.Locate(row), oldrow, e.ExternalCall));

            row = (CROpportunityProducts)Products.Cache.Locate(row);
            rowE = PXCache<CROpportunityProducts>.GetExtension<MAKLCROpportunityProductsExt>(row);
            if (row.InventoryID == null) return;

            if (rowE.UsrMAKLSourceLineType != MAKLOpportunitySourceLineTypes.Margin)
            {
                if (!sender.ObjectsEqual<CROpportunityProducts.inventoryID>(row, oldrow))
                {
                    RemoveMarginLines(row);
                    AddMarginLines(row, diffQty);
                }
                else if (!sender.ObjectsEqual<CROpportunityProducts.curyUnitPrice, CROpportunityProducts.curyDiscAmt, CROpportunityProducts.quantity,
                        CROpportunityProducts.discPct, CROpportunityProducts.descr, CROpportunityProducts.uOM>(row, oldrow)
                        && rowE.UsrMAKLSourceLineType != MAKLOpportunitySourceLineTypes.Margin)
                {
                    UpdateMarginLines(row);

                    if (opClassE.UsrMAKLUpsellMethod == MAKLUpsellMethod.AmountDiff && quoteE.UsrMAKLType == MAKLOpportunityType.Upsell) //Greentree upsale only
                    {
                        UpdateUnitLines(row);
                    }
                }

                if (e.ExternalCall == true)
                {
                    if (rowE.UsrMAKLContrSourceLineNbr == null && Math.Max(row.CuryUnitPrice ?? 0, rowE.UsrMAKLCuryClippedUnitPrice ?? 0)
                         != Math.Max(oldrow.CuryUnitPrice ?? 0, oldrowE.UsrMAKLCuryClippedUnitPrice ?? 0))
                    {
                        UpdateOtherQuoteLinesPrice(row, Math.Max(row.CuryUnitPrice ?? 0, rowE.UsrMAKLCuryClippedUnitPrice ?? 0));
                    }

                    if (rowE.UsrMAKLContrSourceLineNbr != null && row.Quantity != oldrow.Quantity)
                    {
                        RepriceOtherQuoteLines(row);
                    }

                    if (quoteE.UsrMAKLIsNoCredit == true)
                    {
                        UndoRemoveCredit(Quote.Current);
                        RemoveCredit(Quote.Current);
                    }
                }
            }

            ResetManualFlags();

            if (!sender.ObjectsEqual<CROpportunityProducts.discPct, CROpportunityProducts.discountID, CROpportunityProducts.discountSequenceID,
                    MAKLCROpportunityProductsExt.usrMAKLFreeDuration, MAKLCROpportunityProductsExt.usrMAKLPriceDuration,
                    MAKLCROpportunityProductsExt.usrMAKLDiscountDuration>(row, oldrow))
            {
                Products.Cache.SetDefaultExt<MAKLCROpportunityProductsExt.usrMAKLIsPreapproved>(row);
            }

            if (e.ExternalCall == true)
            {
                Products.View.RequestRefresh();
            }
        }        

        public void AddUnitLines(CROpportunityProducts row, bool diffQty)
        {
            if (row == null) return;
            CRQuote quote = Quote.Current;
            if (quote == null) return;
            MAKLCRQuoteExt quoteE = quote.GetExtension<MAKLCRQuoteExt>();
            if (quoteE.UsrMAKLType == MAKLOpportunityType.NewSale) return;
            MAKLCROpportunityProductsExt rowE = PXCache<CROpportunityProducts>.GetExtension<MAKLCROpportunityProductsExt>(row);
            if (rowE.UsrMAKLSourceLineType != MAKLOpportunitySourceLineTypes.Unit
                && (row.Quantity == 1 || (!diffQty && row.Quantity >= 0)))
            {
                InventoryItem item = (InventoryItem)PXSelectorAttribute.Select<CROpportunityProducts.inventoryID>(Products.Cache, row);
                if (item?.BaseUnit != item?.SalesUnit || !diffQty)
                {
                    CROpportunityProducts previous = PXSelect<CROpportunityProducts,
                        Where<CROpportunityProducts.quoteID, Equal<Current<CRQuote.quoteID>>,
                            And<MAKLCROpportunityProductsExt.usrMAKLSourceLineType, Equal<MAKLOpportunitySourceLineTypes.unit>,
                            And<MAKLCROpportunityProductsExt.usrMAKLSourceLineNbr, Equal<Required<MAKLCROpportunityProductsExt.usrMAKLSourceLineNbr>>>>>>
                            .Select(Base, row.LineNbr);
                    if (previous != null) return;

                    List<MAKLUpsellQuoteDetails> downLines = GetDowngradeableLines(row.InventoryID);
                    foreach (MAKLUpsellQuoteDetails downLine in downLines)
                    {
                        CROpportunityProducts unitDowngrade = Products.Insert();
                        MAKLCROpportunityProductsExt unitDowngradeE = PXCache<CROpportunityProducts>.GetExtension<MAKLCROpportunityProductsExt>(unitDowngrade);
                        unitDowngradeE.UsrMAKLSourceLineType = MAKLOpportunitySourceLineTypes.Unit;
                        unitDowngradeE.UsrMAKLSourceLineNbr = row.LineNbr;
                        unitDowngrade.Quantity = -downLine.CurQuantity;
                        if (item?.BaseUnit != item?.SalesUnit)
                        {
                            unitDowngrade.UOM = downLine.UOM;
                        }
                        if (rowE.UsrMAKLSourceLineType != MAKLOpportunitySourceLineTypes.Bundle)
                        {
                            unitDowngrade.InventoryID = row.InventoryID;
                        }
                        else
                        {
                            CROpportunityProducts srcLine = PXSelect<CROpportunityProducts,
                                Where<CROpportunityProducts.quoteID, Equal<Current<CRQuote.quoteID>>,
                                    And<CROpportunityProducts.lineNbr, Equal<Required<CROpportunityProducts.lineNbr>>>>>
                                    .Select(Base, rowE.UsrMAKLSourceLineNbr);
                            unitDowngrade.InventoryID = srcLine?.InventoryID ?? row.InventoryID;
                        }

                        Products.Update(unitDowngrade);
                    }
                }
            }
        }

        public void RemoveUnitLines(CROpportunityProducts row)
        {
            if (row == null) return;

            foreach (CROpportunityProducts unitline in PXSelect<CROpportunityProducts,
                Where<CROpportunityProducts.quoteID, Equal<Required<CROpportunityProducts.quoteID>>,
                    And<MAKLCROpportunityProductsExt.usrMAKLSourceLineNbr, Equal<Required<CROpportunityProducts.lineNbr>>,
                    And<MAKLCROpportunityProductsExt.usrMAKLSourceLineType, Equal<MAKLOpportunitySourceLineTypes.unit>>>>>
                .Select(Base, row.QuoteID, row.LineNbr))
            {
                Products.Delete(unitline);
            }
        }

     

        public enum BundleItem
        {
            Parent,
            Child
        }

        public List<XRBBundleComp> GetBundle(int? InventoryID, BundleItem side, string BundleType, bool? FixedQty)
        {
            if (InventoryID == null) return new List<XRBBundleComp>();
            PXSelectBase<XRBBundleComp> sel = new PXSelect<XRBBundleComp,
                Where<MAKLXRBBundleCompExt.usrMAKLBundleType, Equal<Required<MAKLXRBBundleCompExt.usrMAKLBundleType>>>>(Base);
            if (side == BundleItem.Parent)
            {
                sel.WhereAnd<Where<XRBBundleComp.bundleInventoryID, Equal<Required<XRBBundleComp.bundleInventoryID>>>>();
            }
            else
            {
                sel.WhereAnd<Where<XRBBundleComp.inventoryID, Equal<Required<XRBBundleComp.inventoryID>>>>();
            }
            if (FixedQty != null)
            {
                sel.WhereAnd<Where<MAKLXRBBundleCompExt.usrMAKLFixedQty, Equal<Required<MAKLXRBBundleCompExt.usrMAKLFixedQty>>>>();
            }
            return sel.Select(BundleType, InventoryID, FixedQty).RowCast<XRBBundleComp>().ToList();
        }

        public List<XRBBundleComp> GetBundleTrans(int? InventoryID, BundleItem side, string BundleType, bool? FixedQty)
        {
            if (InventoryID == null) return new List<XRBBundleComp>();
            List<XRBBundleComp> bundle = GetBundle(InventoryID, side, BundleType, FixedQty);
            if (bundle.Count == 0)
            {
                bundle = GetBundle(GetILFBundle(InventoryID)?.BundleInventoryID, side, BundleType, FixedQty);
            }
            return bundle;
        }        

        public class MAKLQuoteMaintSalesPriceGraphExt : PXGraphExtension<QuoteMaint.SalesPrice, QuoteMaint>
        {
            public virtual void CROpportunityProducts_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
            {
                Base.GetExtension<MAKLQuoteMaintExt>().CROpportunityProducts_RowSelected(sender, e, InvokeBaseHandler);
            }
        }

        public class MAKLQuoteMaintDiscountGraphExt : PXGraphExtension<QuoteMaint.Discount, QuoteMaint>
        {
            public virtual void CROpportunityProducts_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
            {

            }
        }
    }
}


@Naveen Boga , I have shared piece of code relevant to CROpportunityProducts


Hi @vibindas were you able to find a solution? Thank you!


@Chris Hackett , yes I added a check at event  “CROpportunityProducts_RowInserting” 

 CROpportunityProducts row = (CROpportunityProducts)e.Row;
            if (row.InventoryID == null)
            {
                e.Cancel = true;
            }         

the additional row had the inventory id null, this check prevents the additional row from getting added to the cache.


Thank you for sharing your solution with the community @vibindas !


Reply