首页 > 解决方案 > Acumatica - 两种方式将单价更新为毛利润百分比并返回

问题描述

无法设置单价更新毛利百分比并返回。

我已经成功地为销售订单行创建了一个新字段来显示毛利润百分比,但现在用户想要一种方法来调整百分比并更新单价。到目前为止,我所有的尝试显然都导致了无限循环。

添加到DAC 中的[UnitPrice]字段的属性:

[PXFormula(typeof(Switch<Case<Where<SOLineExt.usrGPPercent, Equal<decimal0>>, decimal0>, Mult<SOLineExt.usrGPPercent, SOLine.curyUnitCost>>))]

[UsrGPPercent]字段属性:

[PXDBDecimal]
[PXUIField(DisplayName="GPPercent", Visible = false)]
[PXFormula(typeof(Switch<Case<Where<SOLine.curyLineAmt, Equal<decimal0>>, decimal0>, Div<SOLineExt.usrTotalProfit, SOLine.curyLineAmt>>))]
[PXDefault(TypeCode.Decimal, "0.0")]

[UsrGPPct]字段属性:

[PXUIField(DisplayName = "GP %", Enabled = true)] 
[PXFormula(typeof(Mult<SOLineExt.usrGPPercent, decimal100>))]
[PXDefault(TypeCode.Decimal, "0.0")]

以上所有内容都可以正常工作并按预期更新 GP%。

尝试 #1,将以下属性添加到 [UsrGCP] (我意识到数学是不完整的,此时只是尝试进行概念验证)。

[PXFormula(typeof(Switch<Case<Where<SOLine.curyLineAmt, Equal<decimal0>>, decimal0>, Div<SOLineExt.usrTotalProfit, SOLine.curyLineAmt>>))]

尝试#2:FieldUpdated 处理程序:

protected void SOLine_UsrGPPct_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e, PXFieldUpdated InvokeBaseHandler)
{
  if(InvokeBaseHandler != null)
    InvokeBaseHandler(cache, e);
  var row = (SOLine)e.Row;

  PX.Objects.SO.SOLineExt soLineExt = PXCache<SOLine>.GetExtension<PX.Objects.SO.SOLineExt>(row);

  if (row.OrderType == "SO")
  {
      if (soLineExt.UsrGPPct > 0)
      {
        row.CuryUnitPrice = row.CuryUnitCost + (soLineExt.UsrGPPct * row.CuryUnitCost);
      }
  }

}

这两种方法显然都会导致无限循环(猜测是因为触发了调试器并且必须重置 IIS)。目标是仅在用户更新任一字段时更新一次,并忽略系统所做的更新。有任何想法吗?

根据 HB_Acumatica 的回复,我将上面的代码更新为:

protected void SOLine_UsrGPPct_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e, PXFieldUpdated InvokeBaseHandler)
{
  if(InvokeBaseHandler != null)
    InvokeBaseHandler(cache, e);
  var row = (SOLine)e.Row;

  PX.Objects.SO.SOLineExt soLineExt = PXCache<SOLine>.GetExtension<PX.Objects.SO.SOLineExt>(row);

  if (e.ExternalCall)
  {
      if (soLineExt.UsrGPPct > 0)
      {
        if (row.OrderType == "SO")
        {
          decimal NewUnitPrice;
          decimal GPPercent = soLineExt.UsrGPPct ?? 0;
          decimal UnitCost = row.CuryUnitCost ?? 0;
          NewUnitPrice = UnitCost + ((GPPercent  / (decimal)100) * UnitCost);
          row.CuryUnitPrice = NewUnitPrice;
          row.UnitPrice = NewUnitPrice;
        }
      }
  }
}

几乎可以工作。屏幕上没有任何反应,但保存时单价确实会更新并正确保存。快到了,我是否缺少某种更新步骤?

标签: acumatica

解决方案


这通常e.ExternalCall在字段更新事件处理程序中修复以防止递归:

protected void SOLine_UsrGPPct_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e, PXFieldUpdated InvokeBaseHandler)
{
   if (e.ExternalCall)
   {
        // Make sure it gets in here only once when value change in UI
   }
}

ExternalCall 属性 (PXRowUpdatingEventArgs)

如果等于 true,则获取指示 DAC 对象的更新已从 UI 或通过 Web 服务 API 启动的值


除此之外,另一种情况是两个字段属性相互依赖并且需要彼此计算它们的值。您不能让字段 1 的公式依赖于字段 2,以及字段 1 也具有引用字段 2 的公式。

使用这种设置,当请求字段 1 时,它将首先尝试评估字段 1 公式中的依赖字段 2,并且由于字段 2 也依赖于字段 1,因此它将启动无限递归循环。

据我所知,这是没有办法的,您必须重新设计 DAC 字段,因此没有一个是相互依赖的。或者只是省略 DAC 属性并在 RowSelected 事件中执行计算(这有一些缺点,因为它需要图形才能工作)。


编辑:

关于 UI 中未更改的字段值。当某些字段的值更改时需要触发某些事件(通常是 FieldUpdated 事件)时,可能会发生这种情况。

而不是像这样分配不会引发任何事件的值:

row.Field = value;

您可以改用 SetValueExt 来引发 FieldUpdated 等事件:

sender.SetValueExt<DAC.field>(row, value);

发件人需要是 DAC 类型的缓存,在您的情况下应该是,否则它是:

Base.Caches[typeof(DAC)].SetValueExt<DAC.field>(row, value);

请注意,具有 PXFormula 属性的字段将在某些时候重新计算其值,因此您不应手动设置此类字段的值。

如果您在 UnitPrice 字段上仍有这样的属性,则不应手动更新字段值:

[PXFormula(typeof(Switch<Case<Where<SOLineExt.usrGPPercent, Equal<decimal0>>, decimal0>, Mult<SOLineExt.usrGPPercent, SOLine.curyUnitCost>>))]

也许您需要做的就是在 UsrGPPercent 更改时强制刷新公式。如果是这种情况,请尝试使用RaiseFieldDefaulting方法重新计算公式,而不是设置 UnitPrice 值:object dummy;

sender.RaiseFieldDefaulting<SOLine.unitPrice>(e.Row, out dummy);

推荐阅读