Solved

Customize Matrix Item grid

  • 29 September 2023
  • 22 replies
  • 208 views

Userlevel 3
Badge +1

I’ve been asked to provide an estimate for a new customization.  I’ve done several advance things in Acumatica but this one I’m wondering if a) is this possible? and/or b) should it even be attempted?

  1. They want to use Matrix Items with 8 attributes in a template.  
  2. They want to be able to add cost/labor to each attribute value and have the price calculated during entry and saved directly to AR prices when item is created

Add custom fields to Attribute values:

 

Use these values to calculate a price during matrix entry:

 

This does not look like traditional graph extension with overrides.  I’ve tracked down some code PX.Objects\IN\Matrix\GraphExtensions\HeaderAndAttributesExt.cs 

which looks like where the fieldupdating event is being hooked up to each attribute value but I can’t see a way to sub-class or extend this abstract class.

I guess I’m at the point where I just need to hear if this is a fools errand and/or if there is some other possible way to accomplish this.  Customer does not want/need e-commerce integration nor do they want to purchase the product configurator.

icon

Best answer by Zoltan Febert 11 October 2023, 02:08

View original

22 replies

Userlevel 6
Badge +3

Hi @rjean09 

I customized Matrix Items popup before, but it was a total different requirement. Now I do not have any Acumatica Instance where I can try my idea, so I just share it with you, and I hope it will be useful.

using PX.Data;
using PX.Objects.IN.Matrix.DAC.Unbound;

// Namespace is important to be this
namespace PX.Objects.IN.GraphExtensions.SOOrderEntryExt
{
public class SOMatrixEntryExt : MatrixEntryExt
{
protected void _(Events.RowUpdated<MatrixInventoryItem> e)
{
// Maybe you can do something here?
}

protected override MatrixAttributeValues GetMatrixAttributeValues()
{
// Maybe you can do something here?
return null;
}
}
}

Please note the Namespace must be the same.

Userlevel 3
Badge +1

Hi @rjean09 

I customized Matrix Items popup before, but it was a total different requirement. Now I do not have any Acumatica Instance where I can try my idea, so I just share it with you, and I hope it will be useful.

using PX.Data;
using PX.Objects.IN.Matrix.DAC.Unbound;

// Namespace is important to be this
namespace PX.Objects.IN.GraphExtensions.SOOrderEntryExt
{
public class SOMatrixEntryExt : MatrixEntryExt
{
protected void _(Events.RowUpdated<MatrixInventoryItem> e)
{
// Maybe you can do something here?
}

protected override MatrixAttributeValues GetMatrixAttributeValues()
{
// Maybe you can do something here?
return null;
}
}
}

Please note the Namespace must be the same.

Thanks!  Funny I already had a sub-class for MatrixEntryExt but just wasn’t sure where to go next. This gives me hope.

Userlevel 3
Badge +1

I have my “new price” calculating in the matrix item grid row and now I need to grab that to set on sales order and inventory item base price and create sales prices for base and 3 price classes.  It looks like I need to override the ShowMatrixPanel action in PX.Objects.IN.Matrix.GraphExtensions.SmartPanelExt and AddItemsToOrder method, however, I can’t seem to figure out how to create a graph extension for this with the Graph and MainItemType types.  I would also like to default the view to Table View (instead of Matrix View) and also default the to a specific matrix item template.  It looks like I might be able to do this in ShowMatrixPanel if I can figure out how to extend or subclass and override that action.  

Any help appreciated!

Userlevel 6
Badge +3

Extend MatrixEntryExt instead of SmartPanelExt. Remember, you still need to use the correct namesapce.

using System;
using PX.Data;
using PX.Objects.IN.Matrix.DAC.Unbound;
using PX.Objects.SO;

namespace PX.Objects.IN.GraphExtensions.SOOrderEntryExt
{
public class MyMatrixEntryExtExtension : PXGraphExtension<MatrixEntryExt, SOOrderEntry>
{
[PXOverride]
protected virtual void AddItemsToOrder(int? siteID, Action<int?> baseMethod)
{
baseMethod?.Invoke(siteID); // if you need
// your code
}
}
}

 

Userlevel 3
Badge +1

Extend MatrixEntryExt instead of SmartPanelExt. Remember, you still need to use the correct namesapce.

using System;
using PX.Data;
using PX.Objects.IN.Matrix.DAC.Unbound;
using PX.Objects.SO;

namespace PX.Objects.IN.GraphExtensions.SOOrderEntryExt
{
public class MyMatrixEntryExtExtension : PXGraphExtension<MatrixEntryExt, SOOrderEntry>
{
[PXOverride]
protected virtual void AddItemsToOrder(int? siteID, Action<int?> baseMethod)
{
baseMethod?.Invoke(siteID); // if you need
// your code
}
}
}

 

With only the code above (not adding any of my own code yet) I get the following error:

 

FYI, this is build 23.109.0023

UPDATE: got rid of this error by declaring override of AddItemsToOrder as public. Not sure if that is correct but it seems to be working.  I will continue and update with my progress. 

Thanks Zoltan!

Userlevel 6
Badge +3

I don’t get that error, anyway, you can overwrite it in the first class I gave you as well.

I tried it on 22R2, I can confirm the debugger stopped on base.AddItemsToOrder

using PX.Data;
using PX.Objects.IN.Matrix.DAC.Unbound;

namespace PX.Objects.IN.GraphExtensions.SOOrderEntryExt
{
// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
public class SOMatrixEntryExt : MatrixEntryExt
{
protected void _(Events.RowUpdated<MatrixInventoryItem> e)
{
// Maybe you can do something here?
}

protected override MatrixAttributeValues GetMatrixAttributeValues()
{
// Maybe you can do something here?
return null;
}

protected override void AddItemsToOrder(int? siteID)
{
base.AddItemsToOrder(siteID);
}
}
}

 

Userlevel 3
Badge +1

It isn’t hitting the breakpoint for me on base.AddItemsToOrder.  The RowUpdated event is still working fine.  I’ll switch back to the other extension with the public override and try again.

Userlevel 3
Badge +1

The issue I am having now is that AddItemsToOrder has a PXLongOperation in it and I need to somehow wait for that to finish before I run my code after the invoke of the base method as I need the inventory items to exist so I can add to ARSalesPrice.

What would be ideal is if I could add code right after CreateMatrixItemsHelper.CreateUpdateMatrixItems is run from inside AddItemsToorder.

 

Userlevel 6
Badge +3

First, I would try to inherit a class from CreateMatrixItemsHelper. CreateUpdateMatrixItems is a public virtual function, so it shouldn’t be a problem.

After, you can override GetCreateMatrixItemsHelper function, it is in SmartPanelExt graph.

public class MyCreateMatrixItemsHelper : CreateMatrixItemsHelper
{
public MyCreateMatrixItemsHelper(PXGraph graph) : base(graph) { }

public override void CreateUpdateMatrixItems(InventoryItemMaintBase graph, InventoryItem templateItem, IEnumerable<MatrixInventoryItem> itemsToCreateUpdate,
bool create, Action<MatrixInventoryItem, InventoryItem> beforeSave = null)
{
base.CreateUpdateMatrixItems(graph, templateItem, itemsToCreateUpdate, create, beforeSave);
}
}

// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
public class SmartPanelExtTest : MatrixEntryExt
{
protected override CreateMatrixItemsHelper GetCreateMatrixItemsHelper(PXGraph graph)
{
return new MyCreateMatrixItemsHelper(graph);
}
}

If it doesn’t work, you can also wait for long operation:

PXLongOperation.WaitCompletion(Base.UID);

Userlevel 3
Badge +1

 

 

Thanks again Zoltan. You have helped me get very close.  The GetCreateMatrixItemsHelper method was exactly what I needed.

So I now have my sales prices creating for each price class after the base.CreateUpateMatrixItems method is called.  That is working fantastic.

However, now the client wants me to update the LastCost on the new SKU at the same time.  I have added this code:

 

INItemCost itemCost = new INItemCost()
{
InventoryID = item.InventoryID,
LastCostDate = DateTime.Now,
LastCost = cost,
CuryID = "USD",
QtyOnHand = 0M,
TotalCost = 0M,
MinCost = 0M,
MaxCost = 0M
};

itemGraph.ItemCosts.Insert(itemCost);
itemGraph.Persist();

But it gives me this error:

The item has a warehouse and all UOM is set to EA.  Valuation is set to FIFO.  I can enter Last Cost on the same Inventory Item Price/Cost tab on the screen and it saves fine.  Any ideas?

 

Userlevel 3
Badge +1

If I do a slight variation where I update the LastCost and LastCostDate AFTER the insert I don’t get an error, however, I still don’t get any Last Cost data to save anywhere.  INItemCost, INItemStats, INCostStatus are all empty for the newly added InventoryItem.

 

INItemCost itemCost = new INItemCost()
{
InventoryID = item.InventoryID,
CuryID = "USD",
QtyOnHand = 0M,
TotalCost = 0M,
MinCost = 0M,
MaxCost = 0M
};

itemGraph.ItemCosts.Insert(itemCost);
itemCost.LastCost = cost;
itemCost.LastCostDate = DateTime.Now;

// itemGraph.Persist();
itemGraph.Save.Press();

 

Userlevel 6
Badge +3

Hi @rjean09,

It looks like you modify LastCost after inserting the record, but it never arrives the cache.
Please see my comments, you need to implement only one of them.

INItemCost itemCost = new INItemCost()
{
InventoryID = item.InventoryID,
CuryID = "USD",
QtyOnHand = 0M,
TotalCost = 0M,
MinCost = 0M,
MaxCost = 0M
// LastCost and LastCostDate are not here.
};

itemGraph.ItemCosts.Insert(itemCost);
itemCost.LastCost = cost;
itemCost.LastCostDate = DateTime.Now;
// itemGraph.ItemCosts.Update(itemCost); is missing.

// itemGraph.Persist();
itemGraph.Save.Press();

 

Userlevel 3
Badge +1

Guess I never pasted the error in before.  Unfortunately, simply by adding the update to push to the cache the error is back:

 

Userlevel 6
Badge +3

This error message comes from this file: App_Data/CodeRepository/PX.Objects/IN/GraphExtensions/InventoryItemMaintBaseExt/UnitsOfMeasure.cs, from ValidateUnitConversions function:

if (baseConversions.Count() != 1)
throw new PXException(Messages.BaseConversionNotFound,...

Maybe you already have an ItemCost record, and you need to update it, instead of inserting a new one?

Userlevel 3
Badge +1

So it appears that INUnit is not populated after CreateUpdateMatrixItems and that is the problem.

INUnit is there after the full AddOrderItems stack is run.  So I just need to find out where that gets added and if I can add it myself without causing an issue.

Userlevel 3
Badge +1

Update: INUnit IS populated before it gets to my code.  So not sure why ValidateUnitConversions would not find it.

Userlevel 6
Badge +3

ValidateUnitConversions checks if there is only one INUnit exists. If you insert a second one with your code it will find two, and will throw an error. Have you tried to get the INUnit record and update it, instead of inserting a new one?

Userlevel 3
Badge +1

Not trying to add to INUnit, just INItemCost.  I set a breakpoint and verified only 1 INUnit exists in cache and in database before my code runs (After CreateUpdateMatrixItems)

Ignore my earlier comment where I was thinking this was not the case.  Once I realized it was there I never actually tried adding to INUnit.

Userlevel 6
Badge +3

Sorry, I thought we are talking about INUnitCost.

var itemCost = INItemCost.PK.Find(itemGraph, item.InventoryID, "USD");
itemCost.LastCost = cost;
itemCost.LastCostDate = DateTime.Now;

itemGraph.ItemCosts.Update(itemCost);
itemGraph.Save.Press();

 

Userlevel 3
Badge +1

Problem solved.  Bonehead mistake. 

I had:

graph.Item.Current = item

instead of

itemGraph.Item.Current = item

So I was setting Item.Current on the wrong instance of the InventoryItemMaint graph.  

Thanks again for all your help.  Really appreciate it. 

I am going to mark your earlier reply (before all this LastCost fiasco) as the best answer.  If we ever meet at an Acumatica conference I will buy you a beer (or two or three) 😄

Userlevel 3
Badge +1

For anyone else interested, setting the defaults on the Matrix Item popup was relatively easy using Events.CacheAttached:

setting matrix popup defaults

Changing SmartPanelType to default to “E” causes it to open in Table View instead of Matrix View

Userlevel 6
Badge +3

@rjean09 You are very welcome, it was a nice two weeks of effort :)
Welcome to the club, now you can use the “I Customized the Matrix” badge :)

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