Search code examples
c#acumatica

How to override action when field curyOrigDiscAmt value changes Acumatica ERP


I am customizing APInvoiceEntry graph, when it is modified in the Bills and Adjustments Screen (ID=AP301000).

The field curyOrigDiscAmt is set when items are added in the POItem portion of the graph. There is logic that calculates the discount based on payment type (eg Cash Prepayment) and what is set on the vendor class. enter image description here

This is the default behavior. However, after that runs, I have logic I want to run that adjusts this figure.

I thought I could simply put my logic in a "field changing" method. But none of the actions I can find are activated when the change to curyOrigDiscAmt happens.

So far, I have tried:

protected virtual void _(Events.FieldVerifying<APInvoice, APInvoice.curyOrigDiscAmt> e)
protected virtual void _(Events.FieldUpdated<APInvoice, APInvoice.curyOrigDiscAmt> e)
protected void APInvoice_CuryOrigDiscAmt_FieldUpdating(PXCache cache, PXFieldUpdatingEventArgs e)
protected virtual void _(Events.RowSelecting<APInvoice> e)

None of them fire when the field is changed. I need to reflected in the UI for the user to see, so it doesn't do any good to change it when the record is saved. I need it to happen right after the base code runs that does the calculation.

Where is that? How do I find it?

[EDIT -- Follow-up to Hugues Beauséjour's answer below]

Is there a way to just raise the events without having to change the CalcDisc() method at all? All I need are the events to be called.

In other words something sort of like:

protected override void CalcDisc(PXCache sender, PXFieldUpdatedEventArgs e)
 {
     base.CalcDisc(sender, e);
     base.RaiseEvents(EVENTLIST_TO_RAISE);
 }

I would rather not change the code at all if I could help it to keep it more bulletproof to future changes...


Solution

  • The value is computed in the Terms attribute decorating APInvoice.TermsID field:

    #region TermsID
    public abstract class termsID : PX.Data.BQL.BqlString.Field<termsID> { }
    
    /// <summary>
    /// The <see cref="PX.Objects.CS.Terms">credit terms</see> associated with the document (unavailable for prepayments and debit adjustments).\
    /// Defaults to the <see cref="Vendor.TermsID">credit terms of the vendor</see>.
    /// </summary>
    [PXDBString(10, IsUnicode = true)]
    [PXDefault(typeof(Search<Vendor.termsID,
        Where<Vendor.bAccountID, Equal<Current<APInvoice.vendorID>>,
            And<Current<APInvoice.docType>, NotEqual<APDocType.debitAdj>>>>),
        PersistingCheck = PXPersistingCheck.Nothing)]
    [PXUIField(DisplayName = "Terms", Visibility = PXUIVisibility.Visible)]
    [APTermsSelector]
    [Terms(typeof(APInvoice.docDate), typeof(APInvoice.dueDate), typeof(APInvoice.discDate), 
           typeof(APInvoice.curyOrigDocAmt), typeof(APInvoice.curyOrigDiscAmt))]
    public virtual string TermsID
    {
        get;
        set;
    }
    #endregion
    

    It is the last parameter of the TermsAttribute class constructor: CuryDiscBal

    public TermsAttribute(Type DocDate, Type DueDate, Type DiscDate, Type CuryDocBal, Type CuryDiscBal)
    {
        _DocDate = DocDate;
        _DueDate = DueDate;
        _DiscDate = DiscDate;
        _CuryDiscBal = CuryDiscBal;
        _CuryDocBal = CuryDocBal;
    }
    

    The final value is computed in the CalcDisc method of Terms attribute. It is assigned with SetValue method which does not raise events:

    protected virtual void CalcDisc(PXCache sender, PXFieldUpdatedEventArgs e)
    {
        if (_CuryDocBal != null && _CuryDiscBal != null &&
                sender.GetValue(e.Row, _FieldName) != null &&
            sender.GetValue(e.Row, _CuryDocBal.Name) != null && !sender.Graph.IsCopyPasteContext)
        {
            string TermsID = (string)sender.GetValue(e.Row, _FieldName);
            decimal CuryDocBal = (decimal)sender.GetValue(e.Row, _CuryDocBal.Name);
            decimal CuryDiscBal = 0m;
    
            Terms terms = SelectTerms(sender.Graph, TermsID);
            if (terms != null && terms.InstallmentType == TermsInstallmentType.Single && CuryDocBal > 0m)
            {
                CuryDiscBal = PXDBCurrencyAttribute.Round(sender, e.Row, CuryDocBal * (decimal)terms.DiscPercent / 100, CMPrecision.TRANCURY);
            }
    
            sender.SetValue(e.Row, _CuryDiscBal.Name, CuryDiscBal);
            PXUIFieldAttribute.SetEnabled(sender, e.Row, _CuryDiscBal.Name, (terms.InstallmentType == TermsInstallmentType.Single));
        }
    }
    

    To override it you could substitute the Terms attribute with a custom attribute based on the original TermsAttribute class. Then you override field APInvoice.TermsID and decorate it with the custom attribute to replace the original Terms. Changing the SetValue assignment to use SetValueExt should raise the field updating/updated events.