如何在销售订单界面CustomerID选择器中显示客户代码-名称-类别
解决Acumatica销售订单CustomerID选择器显示「客户代码-客户名称-客户类别」无效果问题
问题背景
需求是在销售订单(Sales Order)界面的CustomerID选择器中,实现选择时显示「客户代码-客户名称-客户类别」,并将客户类别追加到选择器搜索描述末尾,使描述字段包含这三个元素。但自定义Field Selecting事件处理代码执行后界面无变化。
原始属性代码
[PXDefault] [Customer( typeof(Search<BAccountR.bAccountID, Where<True, Equal<True>>>), // TODO: remove fake Where after AC-101187 Visibility = PXUIVisibility.SelectorVisible, DescriptionField = typeof(Customer.acctName), Filterable = true)] [CustomerOrOrganizationInNoUpdateDocRestrictor] [PXRestrictor(typeof(Where<Optional<SOOrder.isTransferOrder>, Equal<True>, Or<Customer.status, IsNull, Or<Customer.status, Equal<CustomerStatus.active>, Or<Customer.status, Equal<CustomerStatus.oneTime>, Or<Customer.status, Equal<CustomerStatus.creditHold>>>>>>>>), AR.Messages.CustomerIsInStatus, typeof(Customer.status))] [PXForeignReference(typeof(Field<SOOrder.customerID>.IsRelatedTo<BAccount.bAccountID>))]
自定义事件代码
// Custom field selecting to show concatenated description protected virtual void _(Events.FieldSelecting<SOOrder, SOOrder.customerID> e) { if (e.Row?.CustomerID == null) return; Customer customer = PXSelect<Customer, Where<Customer.bAccountID, Equal<Required<Customer.bAccountID>>>> .Select(Base, e.Row.CustomerID); BAccount account = PXSelect<BAccount, Where<BAccount.bAccountID, Equal<Required<BAccount.bAccountID>>>> .Select(Base, e.Row.CustomerID); if (customer != null && account != null) { string fullDescription = $"{account.AcctCD} - {account.AcctName}"; if (!string.IsNullOrEmpty(customer.CustomerClassID)) fullDescription += $" - {customer.CustomerClassID}"; e.ReturnState = PXFieldState.CreateInstance(e.ReturnState, typeof(string), false, false, null, null, null, null, null, null, fullDescription, null, PXErrorLevel.Undefined, null, null, null, PXUIVisibility.Undefined, null, null, null); } }
问题原因分析
- 原事件仅处理已选择后字段的显示,未修改选择器下拉列表的显示逻辑,下拉列表仍沿用Customer属性默认的描述字段(AcctName)
- 单独查询Customer和BAccount会产生额外数据库请求,且未关联获取数据,存在性能损耗及数据不一致风险
- ReturnState参数设置不完整,未正确覆盖选择器的显示文本与描述规则
解决方案
方案一:修改Customer属性+优化FieldSelecting事件
修改Customer属性的查询逻辑,关联Customer表获取类别字段,同时指定选择器显示字段;再优化事件代码统一处理已选值和选择器描述:
修改后的属性代码
[PXDefault] [Customer( typeof(Search<BAccountR.bAccountID, LeftJoin<Customer, On<Customer.bAccountID, Equal<BAccountR.bAccountID>>>, Where<True, Equal<True>>>), // 保留原Where条件 Visibility = PXUIVisibility.SelectorVisible, // 指定选择器下拉显示的字段:客户代码、客户名称、客户类别 DisplayFields = new[] { typeof(BAccountR.acctCD), typeof(BAccountR.acctName), typeof(Customer.customerClassID) }, DescriptionField = typeof(BAccountR.acctCD), Filterable = true)] // 保留原有限制属性 [CustomerOrOrganizationInNoUpdateDocRestrictor] [PXRestrictor(typeof(Where<Optional<SOOrder.isTransferOrder>, Equal<True>, Or<Customer.status, IsNull, Or<Customer.status, Equal<CustomerStatus.active>, Or<Customer.status, Equal<CustomerStatus.oneTime>, Or<Customer.status, Equal<CustomerStatus.creditHold>>>>>>>>), AR.Messages.CustomerIsInStatus, typeof(Customer.status))] [PXForeignReference(typeof(Field<SOOrder.customerID>.IsRelatedTo<BAccount.bAccountID>))]
优化后的FieldSelecting事件
protected virtual void _(Events.FieldSelecting<SOOrder, SOOrder.customerID> e) { if (e.Row == null || e.Row.CustomerID == null) return; // 关联查询一次性获取所有需要的数据,避免多次数据库请求 var result = PXSelectJoin<BAccountR, LeftJoin<Customer, On<Customer.bAccountID, Equal<BAccountR.bAccountID>>>, Where<BAccountR.bAccountID, Equal<Required<BAccountR.bAccountID>>>> .Select(Base, e.Row.CustomerID); if (result == null) return; BAccountR account = result.GetItem<BAccountR>(); Customer customer = result.GetItem<Customer>(); string fullDescription = $"{account.AcctCD} - {account.AcctName}"; if (customer != null && !string.IsNullOrEmpty(customer.CustomerClassID)) { fullDescription += $" - {customer.CustomerClassID}"; } // 正确覆盖显示文本与描述 var state = (PXStringState)e.ReturnState; if (state != null) { state.DisplayText = fullDescription; e.ReturnState = state; } }
方案二:使用PXSelectorAttribute自定义选择器(更灵活)
如果Customer属性的默认限制较多,可直接用PXSelectorAttribute完全自定义选择器逻辑:
[PXDefault] [PXSelector( typeof(Search<BAccountR.bAccountID, LeftJoin<Customer, On<Customer.bAccountID, Equal<BAccountR.bAccountID>>>, Where<Optional<SOOrder.isTransferOrder>, Equal<True>, Or<Customer.status, IsNull, Or<Customer.status, Equal<CustomerStatus.active>, Or<Customer.status, Equal<CustomerStatus.oneTime>, Or<Customer.status, Equal<CustomerStatus.creditHold>>>>>>>>), // 下拉列表显示字段顺序 new[] { typeof(BAccountR.acctCD), typeof(BAccountR.acctName), typeof(Customer.customerClassID) }, // 拼接显示文本的字段 typeof(BAccountR.acctCD), typeof(BAccountR.acctName), typeof(Customer.customerClassID), DescriptionField = typeof(BAccountR.acctCD), Filterable = true, Visibility = PXUIVisibility.SelectorVisible)] [CustomerOrOrganizationInNoUpdateDocRestrictor] [PXForeignReference(typeof(Field<SOOrder.customerID>.IsRelatedTo<BAccount.bAccountID>))]
同时保留方案一中优化后的FieldSelecting事件,确保已选值显示正确。
关键说明
- 选择器下拉显示:必须通过
DisplayFields指定要显示的字段,或在PXSelector构造函数中传入多个字段实现自动拼接 - 已选值显示:通过FieldSelecting事件修改
ReturnState的DisplayText,确保字段显示自定义拼接文本 - 性能优化:使用关联查询(PXSelectJoin)一次性获取所有所需数据,避免多次数据库请求
内容的提问来源于stack exchange,提问作者Tharidhi P
相关产品推荐
相关产品推荐

