Question

Customer Groups Beyond Customization - Can't get UI to Update Accordingly

  • 20 June 2023
  • 1 reply
  • 45 views

I’m working on a customization to add customer groups for discounts. The goal is that multiple customers and multiple items (with adjusted pricing) can be added to a “Customer Group” that can be maintained and edited as needed. Currently I have 3 DACs for my master (JptCustomerGroup) and detail (JptItem & JptCustomer) relationship. Once the user adds items / customers to a group, they get saved to a new table, JptCustomerGroupCustomer that stores relevant customer ID’s / items and their adjusted prices.

So far, I’m able to create new groups with my “Add to Group” action. the relevant data is than stored to the database (in JptCustomerGroupCustomer):
 

However, no matter what I seem to do, I can’t get the detail grids to refresh when I choose a new Group with the “GroupID” selector in the master part of the form. I messed around with callback commands a bit and was able to get the items to update, but then the customers wouldn’t properly refresh, or the items would get messed up when adding new customers. What I’d like is that the grids for Customers/Items in the group selected at the top refresh to display items / customers in that specific group.

Another strange detail is that the groups DO refresh if I use the arrows at the top of the form (go to next record, pictured below) to cycle between groupID’s. However, the changes are not reflected upon using the selector, even when “Commit Changes” is set to true.

Below, I’ve included relevant fields from my DAC’s as well as the graph for my form. Any help would be greatly appreciated, thanks.

graph:

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

namespace FLCustomerAgreement
{
public class FLCustomerAgreementMaint : PXGraph<FLCustomerAgreementMaint, JptCustomerGroup>
{
public SelectFrom<JptCustomerGroup>.View CustomerGroups;

public SelectFrom<JptCustomer>.
Where<JptCustomer.customerGroupID.
IsEqual<JptCustomerGroup.customerGroupID.FromCurrent>>.View CustomersInGroup;

public SelectFrom<JptItem>.
Where<JptItem.customerGroupID.
IsEqual<JptCustomerGroup.customerGroupID.FromCurrent>>.View ItemsInGroup;

public SelectFrom<JptCustomerGroupCustomer>.View CustomerGroupCustomersView;

public PXAction<JptCustomerGroup> AddToGroup;
[PXButton]
[PXUIField(DisplayName = "Add to Group", Enabled = true)]
protected virtual void addToGroup()
{
// Get the current group from the cache.
JptCustomerGroup group = CustomerGroups.Current;

// If the group's ID doesn't exist, update the group and save the changes
if (!group.CustomerGroupID.HasValue)
{
group = CustomerGroups.Update(group);
this.Save.Press();
PXTrace.WriteInformation("Group saved with ID: " + group.CustomerGroupID);
}
// Refresh the caches before retrieving the data
CustomersInGroup.View.RequestRefresh();
ItemsInGroup.View.RequestRefresh();

foreach (JptCustomer customer in CustomersInGroup.Select())
{
if (customer.Active == true)
{
foreach (JptItem item in ItemsInGroup.Select())
{
if (item.Active == true)
{
// Create a new JptCustomerGroupCustomer entry and set its properties
JptCustomerGroupCustomer groupCustomer = new JptCustomerGroupCustomer
{
CustomerGroupID = group.GroupCD, //string
CustomerID = customer.CustomerCD, //string
InventoryID = item.InventoryID, //int
AdjustedPrice = item.AdjustedPrice //decimal
};
// Insert the new JptCustomerGroupCustomer row into the database
try
{
groupCustomer = CustomerGroupCustomersView.Insert(groupCustomer);
PXTrace.WriteInformation("Customer inserted into group.");
}
catch (Exception ex)
{
PXTrace.WriteError(ex.Message);
}
}
}
}
}
// Save the changes
this.Actions.PressSave();
}
}
}

JptCustomerGroup DAC (Master form):

using System;
using PX.Data;
using PX.Objects.AR;

namespace FLCustomerAgreement
{
[Serializable]
[PXCacheName(Messages.JptCustomerGroup)]
public class JptCustomerGroup : IBqlTable
{

#region CustomerGroupID
[PXDBIdentity()]
public virtual int? CustomerGroupID { get; set; }
public abstract class customerGroupID : PX.Data.BQL.BqlInt.Field<customerGroupID> { }
#endregion


#region GroupCD
[PXDBString(25, IsUnicode = true, InputMask = "", IsKey =true)]
[PXDefault]
[PXUIField(DisplayName = "Group ID")]
[PXSelector(typeof(Search<JptCustomerGroup.groupCD>),
typeof(JptCustomerGroup.groupCD),
typeof(JptCustomerGroup.description))
]
[PX.Data.EP.PXFieldDescription]
[PX.Objects.CS.AutoNumber(typeof(Search<ARSetup.invoiceNumberingID>), typeof(AccessInfo.businessDate))]
public virtual string GroupCD { get; set; }
public abstract class groupCD : PX.Data.BQL.BqlString.Field<groupCD> { }
#endregion


#region LineNbr
[PXDBInt()]
[PXLineNbr(typeof(JptCustomerGroup.groupLineCounter))]
public virtual int? LineNbr { get; set; }
public abstract class lineNbr : PX.Data.BQL.BqlInt.Field<lineNbr> { }
#endregion


#region GroupLineCounter
[PXDBInt()]
[PXDefault(0)]
public virtual int? GroupLineCounter { get; set; }
public abstract class groupLineCounter : PX.Data.BQL.BqlInt.Field<groupLineCounter> { }
#endregion

#region Description
[PXDBString(50, IsUnicode = true, InputMask = "")]
[PXDefault("Enter a description")]
[PXUIField(DisplayName = "Description")]
public virtual string Description { get; set; }
public abstract class description : PX.Data.BQL.BqlString.Field<description> { }
#endregion

#region Active
[PXDBBool()]
[PXDefault(true)]
[PXUIField(DisplayName = "Active")]
public virtual bool? Active { get; set; }
public abstract class active : PX.Data.BQL.BqlBool.Field<active> { }
#endregion

//audit fields
[...]

 


1 reply

 

JptItem DAC (detail grid):

using System;
using PX.Data;
using PX.Data.BQL;
using PX.Data.BQL.Fluent;
using PX.Data.ReferentialIntegrity.Attributes;
using PX.Objects.IN;

namespace FLCustomerAgreement
{
[Serializable]
[PXCacheName(Messages.JptItem)]
public class JptItem : IBqlTable
{

#region ItemID
[PXDBIdentity(IsKey = true)]
public virtual int? ItemID { get; set; }
public abstract class itemID : PX.Data.BQL.BqlInt.Field<itemID> { }
#endregion

#region InventoryID
[Inventory]
public virtual int? InventoryID { get; set; }
public abstract class inventoryID : PX.Data.BQL.BqlInt.Field<inventoryID> { }
#endregion

#region Description
[PXDBString(50, IsUnicode = true, InputMask = "")]
public virtual string Description { get; set; }
public abstract class description : PX.Data.BQL.BqlString.Field<description> { }
#endregion

#region Active
[PXDBBool()]
[PXDefault(true)]
[PXUIField(DisplayName = "Active")]
public virtual bool? Active { get; set; }
public abstract class active : PX.Data.BQL.BqlBool.Field<active> { }
#endregion

#region AdjustedPrice
[PXDBDecimal()]
[PXUIField(DisplayName = "Adj Cost", Required = true)]
public virtual Decimal? AdjustedPrice { get; set; }
public abstract class adjustedPrice : PX.Data.BQL.BqlDecimal.Field<adjustedPrice> { }
#endregion

#region CustomerGroupID
[PXDBInt()]
[PXDBDefault(typeof(JptCustomerGroup.customerGroupID))]
[PXParent(typeof(SelectFrom<JptCustomerGroup>.
Where<JptCustomerGroup.customerGroupID.
IsEqual<JptItem.customerGroupID.FromCurrent>>))]
public virtual int? CustomerGroupID { get; set; }
public abstract class customerGroupID : PX.Data.BQL.BqlInt.Field<customerGroupID> { }
#endregion


#region CustomerGroupCD
[PXDBString(25, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Customer Group ID")]
[PXDBDefault(typeof(JptCustomerGroup.groupCD))]
public virtual string CustomerGroupCD { get; set; }
public abstract class customerGroupCD : PX.Data.BQL.BqlString.Field<customerGroupCD> { }
#endregion

#region StdCost
[PXDBDecimal()]
[PXDefault(typeof(Search<InventoryItemCurySettings.basePrice, Where<InventoryItemCurySettings.inventoryID, Equal<Current<JptItem.inventoryID>>>>), PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIField(DisplayName = "Std Cost")]
public virtual Decimal? StdCost { get; set; }
public abstract class stdCost : PX.Data.BQL.BqlDecimal.Field<stdCost> { }
#endregion

//audit fields
[...]


JptCustomer DAC (detail grid 2):
 

using System;
using PX.Data;
using PX.Data.BQL.Fluent;
using PX.Data.ReferentialIntegrity.Attributes;
using PX.Objects.AR;

namespace FLCustomerAgreement
{
[Serializable]
[PXCacheName(Messages.JptCustomer)]
public class JptCustomer : IBqlTable
{
#region CustomerCD
[PXDBString(25, IsUnicode = true, InputMask = ">aaaaaaaaaaaaaaa")]
[PXUIField(DisplayName = "Customer", Required = true)]
[PXSelector(typeof(Search<Customer.acctCD>),
typeof(Customer.acctCD),
typeof(Customer.acctName),
typeof(Customer.customerClassID))
]
public virtual string CustomerCD { get; set; }
public abstract class customerCD : PX.Data.BQL.BqlString.Field<customerCD> { }
#endregion

#region CustomerGroupID
[PXDBInt()]
[PXDBDefault(typeof(JptCustomerGroup.customerGroupID))]
[PXParent(typeof(SelectFrom<JptCustomerGroup>.
Where<JptCustomerGroup.customerGroupID.
IsEqual<JptCustomer.customerGroupID.FromCurrent>>))]
public virtual int? CustomerGroupID { get; set; }
public abstract class customerGroupID : PX.Data.BQL.BqlInt.Field<customerGroupID> { }
#endregion

#region GroupCD
[PXDBString(25, IsUnicode = true, InputMask = "")]
[PXDBDefault(typeof(JptCustomerGroup.groupCD))]
public virtual string GroupCD { get; set; }
public abstract class groupCD : PX.Data.BQL.BqlString.Field<groupCD> { }
#endregion



#region CustomerID
[PXDBIdentity]
[PXDefault(typeof(Search<Customer.bAccountID, Where<Customer.acctCD, Equal<Current<JptCustomer.customerCD>>>>), PersistingCheck = PXPersistingCheck.Nothing)]
public virtual int? CustomerID { get; set; }
public abstract class customerID : PX.Data.BQL.BqlInt.Field<customerID> { }
#endregion

#region Description
[PXDBString(50, IsUnicode = true, InputMask = "")]
[PXDefault("Enter a description")]
public virtual string Description { get; set; }
public abstract class description : PX.Data.BQL.BqlString.Field<description> { }
#endregion


#region Active
[PXDBBool()]
[PXDefault(true)]
[PXUIField(DisplayName = "Active")]
public virtual bool? Active { get; set; }
public abstract class active : PX.Data.BQL.BqlBool.Field<active> { }
#endregion

// audit fields
[...]
}
}

JptCustomerGroupCustomer DAC (junction for ea Customer / Item in group):
 

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

namespace FLCustomerAgreement
{
[Serializable]
[PXCacheName("JptCustomerGroupCustomer")]
public class JptCustomerGroupCustomer : IBqlTable
{
#region CustomerGroupCustomerID
[PXDBIdentity(IsKey = true)]
public virtual int? CustomerGroupCustomerID { get; set; }
public abstract class customerGroupCustomerID : PX.Data.BQL.BqlInt.Field<customerGroupCustomerID> { }
#endregion

#region CustomerGroupID
[PXDBString(25, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Customer Group ID")]
[PXDBDefault(typeof(JptCustomerGroup.groupCD))]
[PXParent(typeof(SelectFrom<JptCustomerGroup>.
Where<JptCustomerGroup.groupCD.
IsEqual<JptCustomerGroupCustomer.customerGroupID.FromCurrent>>))]
public virtual string CustomerGroupID { get; set; }
public abstract class customerGroupID : PX.Data.BQL.BqlString.Field<customerGroupID> { }
#endregion

#region CustomerID
[PXDBString(25, IsUnicode = true, InputMask = "")]
[PXDefault(typeof(JptCustomer.customerCD))]
[PXParent(typeof(SelectFrom<JptCustomer>.
Where<JptCustomer.customerCD.
IsEqual<JptCustomerGroupCustomer.customerID.FromCurrent>>))]
public virtual string CustomerID { get; set; }
public abstract class customerID : PX.Data.BQL.BqlString.Field<customerID> { }
#endregion


#region AdjustedPrice
[PXDBDecimal()]
[PXUIField(DisplayName = "Adjusted Price")]
public virtual decimal? AdjustedPrice { get; set; }
public abstract class adjustedPrice : PX.Data.BQL.BqlDecimal.Field<adjustedPrice> { }
#endregion

#region InventoryID
[PXDBInt()]
[PXUIField(DisplayName = "Inventory ID")]
public virtual int? InventoryID { get; set; }
public abstract class inventoryID : PX.Data.BQL.BqlInt.Field<inventoryID> { }
#endregion



}
}

other notes:

  • I’m using autonumber to create new ID’s for adding a new group to the table. I’m unsure if this contributing to the issues.
  • It’s quite common for my troubleshooting to lead to new errors when inserting customers/items. ie, often my changes will make it so that adding a new item  deletes all but one existing customer. Another common error to occur is the CustomersInGroup view will display the correct number of customers in that group, but they will all show the same customer rather than the unique customers within that group.

 

.aspx file:

<%@ Page Language="C#" MasterPageFile="~/MasterPages/FormDetail.master" AutoEventWireup="true" ValidateRequest="false" CodeFile="FL201000.aspx.cs" Inherits="Page_FL201000" Title="Customer Agreement" %>
<%@ MasterType VirtualPath="~/MasterPages/FormDetail.master" %>

<asp:Content ID="cont1" ContentPlaceHolderID="phDS" Runat="Server">
<px:PXDataSource PageLoadBehavior="PopulateSavedValues" ID="ds" runat="server" Visible="True" Width="100%"
TypeName="FLCustomerAgreement.FLCustomerAgreementMaint"
PrimaryView="CustomerGroups">
<CallbackCommands>
<px:PXDSCallbackCommand Name="Action" CommitChanges="True" />
<px:PXDSCallbackCommand Name="Save" CommitChanges="True" ></px:PXDSCallbackCommand></CallbackCommands>
</px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phF" Runat="Server">
<px:PXFormView SyncPosition="True" ID="form" runat="server" DataSourceID="ds" DataMember="CustomerGroups" Width="100%" Height="150px" AllowAutoHide="false">
<Template>
<px:PXLayoutRule ID="PXLayoutRule1" runat="server" StartRow="True"></px:PXLayoutRule>
<px:PXCheckBox runat="server" ID="CstPXCheckBox1" DataField="Active" Type="CheckBox"></px:PXCheckBox>
<px:PXSelector runat="server" DataField="GroupCD" CommitChanges="True" ID="CstPXTextEdit3" >
<AutoCallBack Target="gridGroupView,gridItemView" Command="Refresh" ActiveBehavior="True" >
<Behavior RepaintControlsIDs="gridGroupView,gridItemView" ></Behavior>
<Behavior BlockPage="True" ></Behavior></AutoCallBack></px:PXSelector>
<px:PXTextEdit runat="server" ID="CstPXTextEdit6" DataField="Description" ></px:PXTextEdit>
<px:PXButton Text="Create Group" runat="server" ID="CstButton5" >
<AutoCallBack Command="Ok" /></px:PXButton>
</Template>

<CallbackCommands>
<ActivityCheck CommitChanges="True" ></ActivityCheck></CallbackCommands></px:PXFormView>
</asp:Content>
<asp:Content ID="cont3" ContentPlaceHolderID="phG" Runat="Server">
<px:PXSplitContainer PositionInPercent="True" runat="server" Orientation="Vertical" SplitterPosition="30" ID="splitConditions">
<AutoSize Enabled="true" Container="Window" ></AutoSize>
<Template1>
<px:PXGrid runat="server" SyncPosition="True" Height="150px" SkinID="DetailsInTab" Width="100%" ID="gridGroupView" AutoAdjustColumns="True">
<AutoSize Enabled="True" MinHeight="150" />
<Levels>
<px:PXGridLevel DataMember="CustomersInGroup">
<Columns>
<px:PXGridColumn Type="CheckBox" DataField="Active" Width="60" CommitChanges="False" />
<px:PXGridColumn DataField="CustomerCD" Width="140" CommitChanges="True" /></Columns></px:PXGridLevel></Levels></px:PXGrid></Template1>
<Template2>
<px:PXGrid runat="server" Height="150px" SkinID="DetailsInTab" Width="100%" ID="gridItemView" AutoAdjustColumns="True">
<AutoSize Enabled="True" MinHeight="150" />
<Levels>
<px:PXGridLevel DataMember="ItemsInGroup">
<Columns>
<px:PXGridColumn Type="CheckBox" DataField="Active" Width="60" CommitChanges="False" />
<px:PXGridColumn DataField="InventoryID" Width="140" CommitChanges="True" />
<px:PXGridColumn DataField="AdjustedPrice" Width="100" />
<px:PXGridColumn DataField="InventoryID_description" Width="280" />
<px:PXGridColumn DataField="StdCost" Width="100" /></Columns></px:PXGridLevel></Levels></px:PXGrid></Template2>
</px:PXSplitContainer>
</asp:Content>

 

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