1
votes

I need to build a processing screen for customer locations that determines and then updates the residential flag on locations.

This code correctly processes each selected record and appears to update the appropriate fields. But the problem I am encountering is that my changes to Location are not being saved back to the database.

The Customer Locations graph requires the business account to be specified before you can enter a Location ID, and I suspect that because of that I cannot simply update the Locations view on the graph. But I cannot find any documentation or code examples indicating what approach I should use here.

Here is the code on my processing screen graph:

public class ProcessCustomerLocations : PXGraph<ProcessCustomerLocations>
{
    public PXCancel<Location> Cancel;
    public PXProcessing<Location, Where<Location.isActive, Equal<True>>> Locations;

    public static void Process(List<Location> locations)
    {
        var graph = PXGraph.CreateInstance<CustomerLocationMaint>();
        CustomerLocationMaint_Extension graphExt = graph.GetExtension<CustomerLocationMaint_Extension>();

        foreach (var location in locations)
        {
            graphExt.UpdateLocation(location, true);
        }
    }

    public ProcessCustomerLocations()
    {
        Locations.SetProcessDelegate(Process);
    }

}

And here is my code on the CustomerLocationMaint_Extension graph:

public class CustomerLocationMaint_Extension : PXGraphExtension<CustomerLocationMaint>
{
  public void UpdateLocation(Location location, bool isMassProcess = false)
    {
        bool isRes = false;

        Base.Location.Current = Base.Location.Search<Location.locationID>(location.LocationID, location.BAccountID);
        LocationExt locationExt = location.GetExtension<LocationExt>();

        // INSERT CODE TO DETERMINE VALUE OF isRes
        locationExt.UsrResidentialValidated = true;
        location.CResedential = isRes;

        Base.Location.Update(location);
        Base.Actions.PressSave();
    }
}

One of the fields I am updating on Location is a custom field called UsrResidentialValidated. Here is the code for that field.

namespace PX.Objects.CR
{
  public class LocationExt : PXCacheExtension<PX.Objects.CR.Location>
  {          
    #region UsrResidentialValidated
    [PXDBBool]
    [PXUIField(DisplayName="Residential Validated")]

    public virtual bool? UsrResidentialValidated { get; set; }
    public abstract class usrResidentialValidated : IBqlField { }
    #endregion
  }
}

Update

Thanks to some help from @Samvel I've modified the UpdateLocation code as follows. The following code does save the changes to the database (both on the custom field and the non-custom field), which is great. However, in order to do that, I had to create a new Location object "myLocation" and am no longer using the "location" object that the PXProcessing graph passed to UpdateLocation. This means that after processing, when the processing screen displays the processed records with the modified data (after processing finishes and before you refresh the screen), it does not show the updated values. Is there any way to both have the processing screen show the updated values and save the changes to the database?

    public void UpdateLocation(PX.Objects.CR.Location location, bool isMassProcess = false)
    {
        bool isRes = true;

        Location myLocation = PXSelect<Location,
              Where<Location.bAccountID, Equal<Required<Location.bAccountID>>, And<Location.locationID, Equal<Required<Location.locationID>>>>>
              .Select(this.Base, location.BAccountID, location.LocationID);

        this.Base.Location.Current = myLocation;

        LocationExt locationExt = myLocation.GetExtension<LocationExt>();
        locationExt.UsrResidentialValidated = true;

        myLocation.CResedential = isRes;
        Base.Location.Current = Base.Location.Update(myLocation);

        this.Base.Save.Press();
    }
1

1 Answers

1
votes

UPDATED

I have updated the code to correspond to your case. After processing all the records the records in the grid are being updated and showing modified records. You can download the customization package for this code by this link

To create a processing page for updating Location you should do the following steps:

  1. Add "Selected" field to the Location DAC

    public sealed class LocationExt: PXCacheExtension<Location>
    {
        #region Selected
        public abstract class selected : IBqlField
        { }
        [PXBool()]
        [PXDefault(true,PersistingCheck = PXPersistingCheck.Nothing)]
        [PXUIField(DisplayName = "Selected")]
        public bool? Selected { get; set; }
        #endregion
        #region UsrResidentialValidated
        [PXDBBool]
        [PXUIField(DisplayName = "Residential Validated")]
        public bool? UsrResidentialValidated { get; set; }
        public abstract class usrResidentialValidated : IBqlField { }
        #endregion
    }
    

    This step is required because otherwise your delegate for SetProcessDelegate will never be called. Acumatica is checking if there is at least one selected record before calling Process Delegate.

  2. Create the Processing Graph like below:

    using PX.Data;
    using PX.Objects.CR;
    using System.Collections.Generic;
    
    namespace CustomerLocationUpdate
    {
        public class ProcessCustomerLocations : PXGraph<ProcessCustomerLocations>
        {
            public PXCancel<Location> Cancel;
            public PXProcessingJoin<Location,InnerJoin<BAccountR,On<Location.bAccountID,Equal<BAccountR.bAccountID>>>, 
        Where<Location.isActive, Equal<True>,And<Location.locType, Equal<PX.Objects.CR.LocTypeList.customerLoc>>>> Locations;
    
            public static void Process(List<Location> locations)
            {
                var graph = PXGraph.CreateInstance<PX.Objects.AR.CustomerLocationMaint>();
                CustomerLocationMaint_Extension graphExt = graph.GetExtension<CustomerLocationMaint_Extension>();
    
                foreach (var location in locations)
                {
                    graphExt.UpdateLocation(location, true);
                    graph.Clear();
                }
            }
    
            public ProcessCustomerLocations()
            {
                Locations.SetProcessDelegate(Process);
            }
        }
    }   
    

    As you can see I have implicitly specified PX.Objects.AR and PX.Objects.CR for some reason the program has worked only this way on my instance.

  3. Create the UpdateLocation method in the GraphExtension:

    using PX.Data;
    
    namespace CustomerLocationUpdate
    {
        public class CustomerLocationMaint_Extension : PXGraphExtension<PX.Objects.AR.CustomerLocationMaint>
        {
            public void UpdateLocation(PX.Objects.CR.Location location, bool isMassProcess = false)
            {
                bool isRes = false;
                this.Base.Location.Current = PXSelect<PX.Objects.CR.Location,Where<PX.Objects.CR.Location.bAccountID,Equal<Required<PX.Objects.CR.Location.bAccountID>>,And<PX.Objects.CR.Location.locationID,Equal<Required<PX.Objects.CR.Location.locationID>>>>>.Select(this.Base,location.BAccountID,location.LocationID);
                this.Base.Location.Current.CResedential = isRes;
                LocationExt locationExt = PXCache<PX.Objects.CR.Location>.GetExtension<LocationExt>(this.Base.Location.Current);
                locationExt.UsrResidentialValidated = false;
                this.Base.Location.Current = this.Base.Location.Update(this.Base.Location.Current);
                this.Base.Save.Press();
            }
        }
    }
    

    As you can see I am setting the Location.Current using PXSelect and not Location.Current.Search. For some reason Location.Current.Search is always returning null. May be it is caused by the PXProjectionAttribute applied to it, I am not sure what is the exact reason.