Skip to main content
Question

Issue with ClientID Synchronization Across Tabs in Custom Screen

  • 24 October 2024
  • 1 reply
  • 23 views

Hello everyone,

I'm facing an issue with a custom Acumatica screen that involves managing customer records (SanitationCustomer). I have a custom graph (SanitationCustomerMaint) and DAC (SanitationCustomer) that allow users to select a different ClientID using a selector. The main problem occurs when switching between tabs and updating the ClientID.

Here is the specific issue:

  1. When I update the ClientID from the General tab, the customer information is correctly updated for fields such as name, address, city, etc., and all the related views are refreshed accordingly.

     

  2. However, when I switch to a different tab (e.g., Brewers or Invoices) and change the ClientID, the new ClientID appears to be set, but when I navigate back to the
    General tab, the customer information shown is still from the previous ClientID.

 

Additionally, if I save a new record to a related view (e.g., AssignedBreweries), it gets associated with the previous ClientID instead of the newly selected one.
 

using System;
using PX.Data;
using PX.Data.BQL.Fluent;
using PX.Data.BQL;
using PX.Web.UI;

namespace Assainissement
{
    public class SanitationCustomerMaint : PXGraph<SanitationCustomerMaint, SanitationCustomer>
    {
        #region Views

        public PXSelect<SanitationCustomer> Customers;

        public SelectFrom<ClientAvailability>
            .Where<ClientAvailability.clientID.IsEqual<SanitationCustomer.clientID.FromCurrent>>.View ClientAvailabilities;

        public SelectFrom<SanitationContact>
            .Where<SanitationContact.clientID.IsEqual<SanitationCustomer.clientID.FromCurrent>>.View Contacts;

        public SelectFrom<SanitationActivity>
            .Where<SanitationActivity.clientID.IsEqual<SanitationCustomer.clientID.FromCurrent>>.View Activities;

        public SelectFrom<ClientBrewery>
            .InnerJoin<Brewery>.On<ClientBrewery.breweryID.IsEqual<Brewery.breweryID>>
            .Where<ClientBrewery.clientID.IsEqual<SanitationCustomer.clientID.FromCurrent>>.View AssignedBreweries;

        public SelectFrom<BreweryBeerLine>
            .InnerJoin<Beer>.On<BreweryBeerLine.beerID.IsEqual<Beer.beerID>>
            .Where<BreweryBeerLine.clientID.IsEqual<SanitationCustomer.clientID.FromCurrent>
                .And<Beer.breweryID.IsEqual<SanitationCustomer.breweryID.FromCurrent>>>.View AssignedBeers;

        public SelectFrom<SanitizerBillingReport>
            .Where<SanitizerBillingReport.clientID.IsEqual<SanitationCustomer.clientID.FromCurrent>>
            .OrderBy<SanitizerBillingReport.date.Desc>.View Invoices;

        #endregion

        #region Events

        // Assurez-vous que le ClientID est renseigné à l'insertion dans les tables dépendantes
        protected void _(Events.RowInserted<ClientAvailability> e)
        {
            if (e.Row != null && Customers.Current != null)
            {
                e.Row.ClientID = Customers.Current.ClientID;
            }
        }

        protected void _(Events.RowInserted<SanitationActivity> e)
        {
            if (e.Row != null && Customers.Current != null)
            {
                e.Row.ClientID = Customers.Current.ClientID;
            }
        }

        protected void _(Events.RowInserted<SanitationContact> e)
        {
            if (e.Row != null && Customers.Current != null)
            {
                e.Row.ClientID = Customers.Current.ClientID;
            }
        }

        protected void _(Events.RowInserted<SanitizerBillingReport> e)
        {
            if (e.Row != null && Customers.Current != null)
            {
                e.Row.ClientID = Customers.Current.ClientID;

                // Récupérer le prix basé sur la quantité nettoyée
                PriceGridTable priceGrid = SelectFrom<PriceGridTable>
                    .Where<PriceGridTable.breweryID.IsEqual<@P.AsInt>
                        .And<PriceGridTable.minQuantity.IsLessEqual<@P.AsInt>>
                        .And<PriceGridTable.maxQuantity.IsGreaterEqual<@P.AsInt>
                             .Or<PriceGridTable.maxQuantity.IsNull>>>
                    .OrderBy<Asc<PriceGridTable.minQuantity>>
                    .View.Select(this, e.Row.BreweryID, e.Row.TotalCleaned, e.Row.TotalCleaned).TopFirst;

                if (priceGrid != null)
                {             
                    e.Row.TotalPrice = priceGrid.PricePerUnit * e.Row.TotalCleaned;
                }
                else
                {
                    e.Row.TotalPrice = 0;
                }
            }
        }

        protected void _(Events.RowInserted<ClientBrewery> e)
        {
            if (e.Row != null && Customers.Current != null)
            {
                e.Row.ClientID = Customers.Current.ClientID;
            }
        }

        protected void _(Events.RowInserted<BreweryBeerLine> e)
        {
            if (e.Row != null && Customers.Current != null)
            {
                e.Row.ClientID = Customers.Current.ClientID;
            }
        }

        // Événement déclenché lorsqu'un champ est mis à jour dans SanitationCustomer
        protected virtual void _(Events.FieldUpdated<SanitationCustomer, SanitationCustomer.breweryID> e)
        {
            if (e.Row != null)
            {
                AssignedBeers.View.RequestRefresh();  // Rafraîchir la vue des bières assignées
            }
        }


       protected virtual void _(Events.FieldUpdated<SanitationCustomer, SanitationCustomer.clientID> e)
        {
            if (e.Row != null)
            {
                Customers.View.RequestRefresh();  // Rafraîchir la vue principale pour synchroniser avec le client sélectionné
            }
        }



        // Événement déclenché lorsque le champ TotalCleaned est mis à jour dans SanitizerBillingReport
        protected void _(Events.FieldUpdated<SanitizerBillingReport, SanitizerBillingReport.totalCleaned> e)
        {
            SanitizerBillingReport row = e.Row;
            if (row == null) return;

            // Récupérer le prix basé sur la quantité nettoyée
            PriceGridTable priceGrid = SelectFrom<PriceGridTable>
                .Where<PriceGridTable.breweryID.IsEqual<@P.AsInt>
                    .And<PriceGridTable.minQuantity.IsLessEqual<@P.AsInt>>
                    .And<PriceGridTable.maxQuantity.IsGreaterEqual<@P.AsInt>
                         .Or<PriceGridTable.maxQuantity.IsNull>>>
                .OrderBy<Asc<PriceGridTable.minQuantity>>
                .View.Select(this, row.BreweryID, row.TotalCleaned, row.TotalCleaned).TopFirst;

            if (priceGrid != null)
            {
                row.TotalPrice = priceGrid.PricePerUnit * row.TotalCleaned;
            }
            else
            {
                row.TotalPrice = 0;
            }
        }
        #endregion

        #region Actions
        public PXAction<SanitationCustomer> TraceBreweryID;
        [PXButton(CommitChanges = true)]
        [PXUIField(DisplayName = "Afficher les bières")]
        protected void traceBreweryID()
        {
            var currentBrewery = AssignedBreweries.Current;
            if (currentBrewery != null)
            {
                Customers.Current.BreweryID = currentBrewery.BreweryID;
                Customers.Cache.Update(Customers.Current);
                AssignedBeers.View.RequestRefresh();
            }
        }
        #endregion
    }
}


 

1 reply

MichaelShirk
Captain I
Forum|alt.badge.img+1
  • Captain I
  • 106 replies
  • October 25, 2024

Hi @kdesbiens !
Since you haven’t shared the code for you DAC, I’m assuming some things here, but I think this may be at least part of the problem.

In the code you shared, you’re using the Detail Line’s Row_Inserted event to set the ClientID on the new detail line. 
Acumatica has a simpler way of handling relationships with header-detail records. 
The ClientID field declaration in the Detail DAC (for ClientAvailability for example) should be something like below. 
The [PXDBDefault] attribute automatically sets the value of the field when the record is saved.
The [PXParent] attribute defines the header-detail relationship and also takes care of deleting detail lines when the header record is deleted.

#region ClientID
[PXDBInt(IsKey = true)]
[PXDBDefault(typeof(SanitationCustomer.clientID))]
[PXParent(typeof(SelectFrom<SanitationCustomer>.Where<SanitationCustomer.clientID.IsEqual<ClientAvailability.clientID.FromCurrent>>))]
public virtual int? ClientID { get; set; }
public abstract class clientID : PX.Data.BQL.BqlInt.Field<clientID> { }
#endregion

Depending on the other fields of the record, you may also need to implement a lineCounter field in the header record and the lineNumber key field for the detail record that serves as the second part of the composite key for the detail line. Similar to below.
Header field:

#region ClientAvailLineCntr //Field on header table to track line number
[PXDBInt()]
[PXDefault(0)]
public virtual int? ClientAvailLineCntr { get; set; }
public abstract class clientAvailLineCntr : BqlInt.Field<clientAvailLineCntr> { }
#endregion

Detail field:

#region LineNbr //Field on detail table to auto-number detail lines
[PXDBInt(IsKey = true)]
[PXLineNbr(typeof(SanitationCustomer.clientAvailLineCntr))]
public virtual int? LineNbr { get; set; }
public abstract class lineNbr : BqlInt.Field<lineNbr> { }
#endregion

 

Additionally, when the header-detail relationships are set up correctly, you won’t need to call the view.RequestRefresh() method when the header ID is changed as the detail view will automatically update to show the records related to the header record. 
You will want to make sure that “Commit Changes” is set to ‘true’ for the header ClientID field in the ASPX file so that the server knows to refresh the detail views.

 

Hope this helps!


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings