Solved

Change to a value in a table is not saving using a custom graph

  • 19 March 2022
  • 1 reply
  • 377 views

Userlevel 6
Badge +3

When a user saves a Purchase Order, the LastPrice in the POVendorInventory table is updated.  If there are multiple lines in the PO for the same item, they may have different Unit Costs for the same inventory item.  When the table is updated, the last record in the grid is what ends up in the field.

If there are multiple lines with the same inventory ID, my customer wants to update the LastPrice field with the LOWEST unit cost, not the last one to be processed.

To complicate this, they want to change the LastPrice field to the lowest Unit Cost if it is overridden in the Purchase Receipts screen.  Based on my testing, if you edit the Unit Cost on the Purchase Receipts screen, I don’t see that it updates the POVendorInventory table.  They want it to update the table if the Unit Cost is overridden.  Honestly, it seems like that should be standard business logic.  On the Purchase Receipts screen, you are entering the ACTUAL cost of the item.

Since the customer wants to update the LastPrice field in the POVendorInventory table when a Purchase Receipt is released, I created a custom graph to use in my override of the public class POReceiptLineExt : PXCacheExtension<POReceiptLine> extension.  The base graph does not provide access via a cache to the POVendorItemInventory table, so I did it through a custom graph that just accesses that table.  Maybe this is a stupid approach but it is the only way I can think of to do this.

My approach:

  1. override the ReleaseReceipt method  (public virtual void ReleaseReceipt(INReceiptEntry docgraph, AP.APInvoiceEntry invoiceGraph, POReceipt aDoc, DocumentList<INRegister> aINCreated, DocumentList<AP.APInvoice> aAPCreated, bool aIsMassProcess, ReleaseReceiptDelegate baseMethod))
  2. After the base method fires, if there is a valid PO Receipt number, pull the lines that are processed on the receipt.  Then, create a dictionary of unique items and catch the inventory ID and the lowest unit cost for that item.
  3. Create a custom graph JUST to make it so I can update the LastPrice field in the POVendorInventory table.
  4. Cycle through the dictionary created in 2 above and update the records in the POVendorInventory table.

The problem?  Everything works find and in debug, it creates a listing of records to update, updates the values in the LastPrice field, BUT, it does not save the change to the DB.

I am including the entire custom graph below as well as the entire method override.  The thing that is not working is the last section of the override.  The Actions.PressSave doesn’t seem to actually save the change to the DB.  

If anyone has any advice that would be great.  

Thanks!

Joe Schmucker

CODE:

CUSTOM GRAPH:

using PX.Data;
using PX.Objects.PO;

namespace SOItemNumberChanger
{
    public class ICSUpdateLastPrice : PXGraph<ICSUpdateLastPrice>
    {
        public PXSave<POVendorInventory> Save;
        public PXCancel<POVendorInventory> Cancel;

        public PXSelect<POVendorInventory, 
            Where<POVendorInventory.vendorID, 
                Equal<Required<POReceiptLine.vendorID>>,
                And<POVendorInventory.inventoryID, 
                    Equal<Required<POVendorInventory.inventoryID>>>>> ItemsView;

    }
}
 

OVERRIDE DELEGATE

namespace PX.Objects.PO
{


    // Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
    // Acuminator disable once PX1011 InheritanceFromPXCacheExtension [Justification]
    public class POReceiptLineExt : PXCacheExtension<POReceiptLine>
    {
        [PXDecimal(2)]
        [PXUIField(DisplayName = "Last Vendor Price")]
        public virtual decimal? UsrLastVendorPrice { get; set; }
        public abstract class usrLastVendorPrice : PX.Data.BQL.BqlDecimal.Field<usrLastVendorPrice> { }
    }


    // Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
    public class POReceiptEntry_Extension : PXGraphExtension<POReceiptEntry>
  {

        public delegate void ReleaseReceiptDelegate(INReceiptEntry docgraph,
                                                    AP.APInvoiceEntry invoiceGraph,
                                                    POReceipt aDoc,
                                                    DocumentList<INRegister> aINCreated,
                                                    DocumentList<AP.APInvoice> aAPCreated,
                                                    bool aIsMassProcess);
        [PXOverride]
        public virtual void ReleaseReceipt(INReceiptEntry docgraph,
                                           AP.APInvoiceEntry invoiceGraph,
                                           POReceipt aDoc,
                                           DocumentList<INRegister> aINCreated,
                                           DocumentList<AP.APInvoice> aAPCreated,
                                           bool aIsMassProcess,
                                           ReleaseReceiptDelegate baseMethod)
        {

            baseMethod(docgraph, invoiceGraph, aDoc, aINCreated, aAPCreated, aIsMassProcess);

           // POReceipt pOReceipt = aDoc;

            if (aDoc.ReceiptNbr != null)
            {

                Dictionary<int?, decimal?> keyValuePairs = new Dictionary<int?, decimal?>();

                foreach (POReceiptLine pOReceiptLine in SelectFrom<POReceiptLine>.Where<POReceiptLine.receiptNbr
                    .IsEqual<@P.AsString>>.View.Select(Base, aDoc.ReceiptNbr))
                {
                    if (keyValuePairs.TryGetValue(pOReceiptLine.InventoryID, out decimal? existingItem))
                    {
                        if (pOReceiptLine.UnitCost < existingItem)
                        {
                            keyValuePairs.Remove(pOReceiptLine.InventoryID);
                            keyValuePairs.Add(pOReceiptLine.InventoryID, pOReceiptLine.UnitCost);
                        }
                    }
                    else
                    {
                        keyValuePairs.Add(pOReceiptLine.InventoryID, pOReceiptLine.UnitCost);
                    }

                }

                using (var ts = new PXTransactionScope())
                {
                    var graph = PXGraph.CreateInstance<ICSUpdateLastPrice>();

                    foreach (KeyValuePair<int?, decimal?> item in keyValuePairs)
                    {
                        graph.ItemsView.Current = PXSelect<POVendorInventory, Where<POVendorInventory.vendorID, 
                            Equal<Required<POReceiptLine.vendorID>>,
                                And<POVendorInventory.inventoryID, Equal<Required<POVendorInventory.inventoryID>>>>>
                                .Select(Base, Base.Document.Current.VendorID, item.Key);
   
                        if (graph.ItemsView.Current != null)
                        {
                            graph.ItemsView.Current.LastPrice = item.Value;
                            graph.Actions.PressSave();
                        }
                    }
                    ts.Complete();
                }
            }
        }

}

 

icon

Best answer by Joe Schmucker 19 March 2022, 23:22

View original

1 reply

Userlevel 6
Badge +3

I figured out how to do it.  Thank you Acumatica Training class.

To get it to work, I added this view to the extension:

public SelectFrom<POVendorInventory>.View UpdateLastPriceView;

Then, I changed the foreach loop to be this very simple few lines of code:

foreach (KeyValuePair<int?, decimal?> kvp in keyValuePairs)
{
POVendorInventory currentItem = PXSelect<POVendorInventory,
Where<POVendorInventory.vendorID,
    Equal<Required<POReceiptLine.vendorID>>,
      And<POVendorInventory.inventoryID, Equal<Required<POVendorInventory.inventoryID>>>>>
    .Select(Base, new object[] { Base.Document.Current.VendorID, kvp.Key });

if (currentItem != null)
  {
   currentItem.LastPrice = kvp.Value;
    UpdateLastPriceView.Update(currentItem);
    UpdateLastPriceView.Cache.Persist(PXDBOperation.Update);
  }
}

Only took 5 hours and a few hundred PO’s for legos.

 

 

Reply


About Acumatica ERP system
Acumatica Cloud ERP provides the best business management solution for transforming your company to thrive in the new digital economy. Built on a future-proof platform with open architecture for rapid integrations, scalability, and ease of use, Acumatica delivers unparalleled value to small and midmarket organizations. Connected Business. Delivered.
© 2008 — 2024  Acumatica, Inc. All rights reserved