Skip to main content
Answer

PXFormula on custom field in SOLine not populating unbound custom field in SOOrder

  • October 3, 2024
  • 9 replies
  • 205 views

Joe Schmucker
Captain II
Forum|alt.badge.img+3

On the Sales Order screen, I have a custom field in SOLine (UsrNSUnitCost) that is persisted to the db.  I have a custom unbound “total” field in the header (UsrTotalNSCost) to show the total for that field, computed as Qty * UsrNSUnitCost for all SO Lines on the order.

My PXFormula compiles and does not have any runtime errors, but the field is zero even when there are SO Lines with amounts in the custom field.

This is the DAC field for the SOOrder table:

public sealed class AABSOOrderExt : PXCacheExtension<PX.Objects.SO.SOOrder>
{
#region UsrTotalNSCost
[PXDecimal]
[PXUIField(DisplayName = "NS Total", Enabled = false)]
public decimal? UsrTotalNSCost { get; set; }
public abstract class usrTotalNSCost : PX.Data.BQL.BqlDecimal.Field<usrTotalNSCost> { }
#endregion
}

This is the DAC field for the SOLine table:

public sealed class AABSOLineExt : PXCacheExtension<PX.Objects.SO.SOLine>
{
#region UsrNSUnitCost
[PXDBDecimal]
[PXDefault(TypeCode.Decimal, "0.00", PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIField(DisplayName = "NS Unit Cost")]
[PXFormula(typeof(Mult<SOLine.orderQty, AABSOLineExt.usrNSUnitCost>), typeof(SumCalc<AABSOOrderExt.usrTotalNSCost>))]
public decimal? UsrNSUnitCost { get; set; }
public abstract class usrNSUnitCost : PX.Data.BQL.BqlDecimal.Field<usrNSUnitCost> { }
#endregion
}

The line in the grid has a value in the custom field:

 

The header shows zero:

One other thing.  I have the header field set as Enabled = false.  So why is the field editable?

I used the same formula that was used in the Acumatica training course.  The only difference I can see is that my header field is unbound.  

Should be so easy, but it never is.  

 

Best answer by Django

Just adding my two cents because I agree with you - there are these subtle things that I end up spending too much time on.

PXUnboundDefault will calculate the value when the record is retrieved from the database where as PXDefault will set the value when the record is saved to the database.

Buried within the framework development guide on page 251 (of the 2024R1 edition) is this gem:

“The PXFormula attribute defines the RowSelecting event handler to calculate values for unbound DAC fields. You do not have to define any event handlers; you only need to mark a field in the DAC with an attribute.”

I checked my current project which pushes a half-dozen calculations up to the header but I’m persisting all of my header fields and that might be why I don’t have to force any calculations into RowSelected like you’re finding.

It might be worth experimenting with persisting the total for the header field. It’s no skin off your back to store that field. Just make sure to force it to 0 in an override of OrderCreated.

My fields also became editable as well. I ended up forcing them back to disabled in SOOrder_RowSelected. I think it’s because of the calls to cache.AllowUpdate. If you look at the CuryOrderTotal field, you’ll see that the base ACM code will make a call to SetEnabled in the RowSelected event.

 

 

 

9 replies

darylbowman
Captain II
Forum|alt.badge.img+15
  1. Is CommitChanges = true on your custom SOLine field?
  2. Are you expecting the total to update when changing the field or when loading the screen?

Joe Schmucker
Captain II
Forum|alt.badge.img+3
  • Author
  • Captain II
  • October 3, 2024

Thanks @darylbowman   I just added commitchanges = true to the field.  It now updates the total when you change the value on the line.

Your q2 is correct.  I do need it to calculated the total when loading an existing record.  It is not doing that currently.

A while ago, Naveen made some code for me to update a total in the header with these lines:

 

        [PXDBScalar(typeof(Search<INSiteStatus.qtyOnHand, Where<INSiteStatus.inventoryID, Equal<INKitSpecStkDet.compInventoryID>,

                                                    And<INSiteStatus.subItemID, Equal<INKitSpecStkDet.compSubItemID>,

                                                    And<INSiteStatus.siteID, Equal<SiteIDBataviaProd>>>>>))]

        [PXUnboundDefault(typeof(Search<INSiteStatus.qtyOnHand,

                                                    Where<INSiteStatus.inventoryID, Equal<Current<INKitSpecStkDet.compInventoryID>>,

                                                        And<INSiteStatus.subItemID, Equal<Current<INKitSpecStkDet.compSubItemID>>,

                                                            And<INSiteStatus.siteID, Equal<SiteIDBataviaProd>>>>>), PersistingCheck = PXPersistingCheck.Nothing)]

 

The above examples are pulling a value from a Search, not a forumula.  I think I might need these attributes to calculate the total from the SOLines, but I’m not doing a Search.  I tried putting a Formula in the PXUnboundDefault as follows:

public sealed class AABSOOrderExt : PXCacheExtension<PX.Objects.SO.SOOrder>
{
#region UsrTotalNSCost
[PXDecimal]
[PXUIField(DisplayName = "NS Total", Enabled = false)]
[PXUnboundDefault(typeof(Mult<SOLine.orderQty, AABSOLineExt.usrNSUnitCost>), typeof(SumCalc<AABSOOrderExt.usrTotalNSCost>),
PersistingCheck = PXPersistingCheck.Nothing)]
public decimal? UsrTotalNSCost { get; set; }
public abstract class usrTotalNSCost : PX.Data.BQL.BqlDecimal.Field<usrTotalNSCost> { }
#endregion
}

At runtime, I get this error.
Error: A foreign key reference cannot be created from the type 'PX.Data.SumCalc`1[PX.Objects.SO.AABSOOrderExt+usrTotalNSCost]'.
Parameter name: type

Sorry this is so Acumatica 101.  I think Acumatica needs to create a training course on Formulas...I could really use it.

 


Joe Schmucker
Captain II
Forum|alt.badge.img+3
  • Author
  • Captain II
  • October 3, 2024

waiting for Chris to release my last post.  I must have used a b a d word that caused my post to require moderator approval.  


Joe Schmucker
Captain II
Forum|alt.badge.img+3
  • Author
  • Captain II
  • October 3, 2024

@darylbowman I’m itching to get this done before DEVCON restarts today.  My pending post has a lot more detail, but here is a short recap of that post:

  1. commitchanges = true fixed the updating when you change the amount on a line (yay!)
  2. I need the screen to compute the total of the details when you open an existing record. I tried a few things as I described in my pending post, but this one I can’t get to work either.

Thanks


darylbowman
Captain II
Forum|alt.badge.img+15

I suspected as much. I tried this exact scenario and despite by best attempts, couldn’t figure out a way to force this to calculate upon load. I eventually ran the calculation in RowSelected, and you have no idea how frustrated I have to be to do something like that.

I’d love a solution myself.

P.S. You aren’t trying to calculate the PO Unbilled Amount are you 😏


Joe Schmucker
Captain II
Forum|alt.badge.img+3
  • Author
  • Captain II
  • October 3, 2024

Fantastic.  We ended on the same page.  I have this exact customization on two customers.  In my previous project, I resolved <unhappily> to do it in rowselected.  When I was asked to do the same change for this new customer, I REALLY wanted to do it the right way.  I will just do it the wrong way and try to sleep at night knowing my sins.


Joe Schmucker
Captain II
Forum|alt.badge.img+3
  • Author
  • Captain II
  • October 3, 2024

I suspected as much. I tried this exact scenario and despite by best attempts, couldn’t figure out a way to force this to calculate upon load. I eventually ran the calculation in RowSelected, and you have no idea how frustrated I have to be to do something like that.

I’d love a solution myself.

P.S. You aren’t trying to calculate the PO Unbilled Amount are you 😏

Nope...not working with PO Unbilled amount.  Just summing a custom field in the lines to stick into the header as a total.  Super simple, but not so easy to do I guess.


Forum|alt.badge.img+7
  • Captain II
  • Answer
  • October 3, 2024

Just adding my two cents because I agree with you - there are these subtle things that I end up spending too much time on.

PXUnboundDefault will calculate the value when the record is retrieved from the database where as PXDefault will set the value when the record is saved to the database.

Buried within the framework development guide on page 251 (of the 2024R1 edition) is this gem:

“The PXFormula attribute defines the RowSelecting event handler to calculate values for unbound DAC fields. You do not have to define any event handlers; you only need to mark a field in the DAC with an attribute.”

I checked my current project which pushes a half-dozen calculations up to the header but I’m persisting all of my header fields and that might be why I don’t have to force any calculations into RowSelected like you’re finding.

It might be worth experimenting with persisting the total for the header field. It’s no skin off your back to store that field. Just make sure to force it to 0 in an override of OrderCreated.

My fields also became editable as well. I ended up forcing them back to disabled in SOOrder_RowSelected. I think it’s because of the calls to cache.AllowUpdate. If you look at the CuryOrderTotal field, you’ll see that the base ACM code will make a call to SetEnabled in the RowSelected event.

 

 

 


Joe Schmucker
Captain II
Forum|alt.badge.img+3
  • Author
  • Captain II
  • October 3, 2024

@Django Yup.  I do have a case where the header field is persisted and using the PX attributes works.  I think this limitation is due to the fact that my header field is not persisted.

I actually thought about making it a DB field.  If I do that, I would need to write code/SQL to update all the existing records.  I was hoping to not have to do that because I really don’t like doing “mass updates” on the DB.  It scares me…  :-)

Thanks for the idea.  I will work with the VAR to see if they would like me to do that.  Having it as a persisted value seems a lot more valuable as well.  That way it can be used on GI’s etc.