AX2012 XppCompiler create method动态创建方法并运行

时间:2023-03-09 06:22:22
AX2012 XppCompiler create method动态创建方法并运行

在用友系列的软件中经常可以看到可配置的计算公式,AX中其实也有可配置的公式,如call center呼叫中心的欺诈Fraud rule的配置,AX后台可以根据配置规则,变量,条件来动态产生方法并执行,如下:

public static boolean executeRule(MCRUpSellRule _rule, RecId _salesLineRecId)
{
  str condition;
  str andOr;
  MCRUpSellVarRule mcrUpSellVarRule;
  MCRUpSellVarRuleDetail mcrUpSellVarRuleDetail;
  //BP Deviation Documented
  XppCompiler xppCompiler;
  MCRFraudRule mcrFraudRule;
  MCRUpSellRule rule = _rule;

  new ExecutePermission().assert();
  // BP Deviation Documented
  xppCompiler = new xppCompiler();
  condition = "";
  andOr = "";
  while select Operand, LeftParen, RightParen, ConditionName from mcrUpSellVarRuleDetail where mcrUpSellVarRuleDetail.RuleID == rule
  {
    switch (mcrUpSellVarRuleDetail.Operand)
    {
      case MCRUpSellOperandType::None: andOr = ""; break;
      case MCRUpSellOperandType::AND: andOr = ' && '; break;
      case MCRUpSellOperandType::OR: andOr = ' || '; break;
    }
    condition = condition
    + enum2str(mcrUpSellVarRuleDetail.LeftParen)
    + 'MCRUpSellCrossSell::executeCondition('
    + strfmt('%1', _salesLineRecId) + ', \''
    + mcrUpSellVarRuleDetail.ConditionName + '\')'
    + enum2str(mcrUpSellVarRuleDetail.RightParen) + andOr;
  }
  condition = 'boolean retstuff(){ return ' + condition + '; }';
  xppCompiler.compile(condition);
  if (xppCompiler.errorText() != "")
  {
    select firstOnly RecId from mcrUpSellVarRule
    where mcrUpSellVarRule.RuleID == rule;
     
    select firstonly RecId from mcrFraudRule
      where mcrFraudRule.RuleId == rule;
    if (!mcrUpSellVarRule && !mcrFraudRule)
    {
      error(strfmt("@MCR11882", rule));
    }
    else
    {
    
      if (mcrFraudRule)
      {
        rule = MCRFraudRule::find(rule).RuleName;
        error(strfmt("@MCR24889", rule, xppCompiler.errorText()));
      }
      else //the problem is with an upsellCrossSell Rule
      {
        error(strfmt("@MCR11883", rule, xppCompiler.errorText()));
      }
   }
    return false;
    }
    return xppCompiler.execute();
  }

配置规则里的逻辑不复杂,下面例子说明,如果创建带参数的动态方法:

  new ExecutePermission().assert();

  xppCompiler = new XppCompiler();
  condition = '';

  condition = strFmt(this.Notes,
  enum2int(curSettlement.PurchCoalIncentiveClaims),
  num2str(curDetails.PurchQty,0,2,0,0),
  num2str(curDetails.PurchPrice,0,2,0,0),
  num2str(this.LoadPortValue,0,2,0,0),
  num2str(this.UnLoadPortValue,0,2,0,0),
  num2str(this.LowerLimit,0,2,0,0),
  num2str(this.UpperLimit,0,2,0,0));

  xppCompiler.compile(condition);
  if (xppCompiler.errorText() != '')
    error(strfmt("@HVL1634",xppCompiler.errorText()));
  return xppCompiler.execute();

this.Notes的方法体如下,其中%1表示接收第一个参数.

public LineAmount executeFormula( )
{
  LineAmount curLineAmount1,curLineAmount2;
  ;
  if(%4 ==0)
  {
    curLineAmount1 = 0;
    curLineAmount2 = 0;
  }
  else
  {
    curLineAmount1 = decRound((%4-%6)*decRound(%3/%6,3),2)*%2;
    curLineAmount2= (%4>=(%6-200) ? 0 : (%4-%6-200)*decRound(%3/%6,3))*%2;
  }
  return decRound(curLineAmount1+curLineAmount2,2) ;
}

以下例子也可以参考

http://www.van-veldhuizen.eu/blog/2012/04/19/run-custom-code-microsoft-dynamics-ax-2012/

n previous versions we used the RunBuff() method to run configured scripts. This is not allowed when you run in CIL.

There is a simple work around as there is new class: XppCompiler

http://msdn.microsoft.com/en-us/library/xppcompiler.executeex.aspx

A small sample is shown below:

static void Job12(Args _args)

{

  XppCompiler compiler = new XppCompiler();

  source source = strFmt("anyType runMethod()\n{\n  return %1\n}\n", 'today();');

  ;

  compiler.compile(source);

  test = compiler.execute();

}