项目背景

订单完成后,会由交易系统推送实时MQ消息给订单清算系统,告诉清算系统此订单交易完成,可以进行给商家结算等后续操作。

财务要求在交易推送订单到清算系统时和订单清算系统接收到订单消息后,需要按照财务给定的校验公式,验证交易推送的数据是否正确。比如下面的财务公式:

  • 商品原价 = 商品活动价 + 活动价补贴
  • 在线支付=微信+支付宝+QQ钱包+会员卡支付+翼支付
  • 用户实付=在线支付+现金
  • 订单总额=在线支付金额+会员卡优惠+代金券优惠+公司活动补贴+商家活动价补贴+现金支付

财务同学明确告知,随着支付网关后续接入更多支付渠道整体公式都要随着变化。另外营销手段的丰富化(拼团返现等),相应结算相关的金额都要纳入财务公式计算和校验中。故公式整体是不断变化的。

方案

金额单元参数化

为了应对后续财务相关字段的随时扩充,项目组组长确定使用大Json,单元参数形式表示非订单基础信息。形如:

[{"K":10112,"V":"2100"},{"K":10113,"V":"10"},{"K":10115,"V":"2300"},{"K":10117,"V":"0"}]

具体Key字段(比如:10112、10113、10115)含义由枚举形式维护。并人为规定10000~20000段为金额相关字段。

字典表或配置中心存储校验公式

校验公式前期是存储在MySQL的一张字典表里。后期有计划迁移到架构部维护的统一配置中心里。部分校验公式形如下:

1. p10125-(p10101+p10106+p10108+p10131+p10113)
2. p10101-(p10102+p10103+p10104+p10105+p10130)
3. p10108-(p10109+p10110+p10111+p10133)
4. p10125-(p10131+p10124)
5. p10131-(p10112+p10132)
6. p10107-(p10132+p10133)
7. p10117-(p10134+p10135+p10136+p10140+p10137+p10138+p10139)

其实,通过看上面一大堆公式,也可以看出 使用这种编码化的单元参数,可读性太差了!!

公式校验

在订单清算系统接收到到订单MQ消息时,会遍历消息体内全部金额相关字段写入到FelContext内,为后面计算做准备。

校验前准备:

private FelContext getFelContext(OrderSalary orderSalary, FelEngine fel) {
FelContext ctx = fel.getContext();
ParamEnum[] enums = ParamEnum.values();
for (ParamEnum paramEnum : enums) {
if (paramEnum.getCode() < 20000) {
// 获取对应的Value值
String value = ParamapUtil.getSingleton().getEntityParamValueByParamID(orderSalary, paramEnum.getCode()) == null ? "0" : ParamapUtil.getSingleton().getEntityParamValueByParamID(orderSalary, paramEnum.getCode());
// 以 p11002 , 2000 的形式写入FelContext
ctx.set("p" + paramEnum.getCode(), Long.parseLong(value));
}
}
return ctx;
}

公式校验: 比如 ( 用户实付 - (在线支付+现金) = 0 )

// checkValue为全部检验公式,是从字典表或者配置中心获取的
for (String check : checkValue) {
Expression exp = fel.compile(check, ctx);
Object result = exp.eval(ctx);
Long checkNumber = NumberUtil.toLong(result);
if (checkNumber != 0) {
logger.error("orderId={} 规则校验错误:{}", new Object[]{orderSalary.getOrderId(), check});
return Boolean.FALSE;
}
}

其他场景

比如计算本单实发,也就是本单实际给商家结算金额,就可以表达式引擎。我们公司旧的计算规则:

本单实发=结算金额-退款金额+商家补贴撤回+现金退款-现金支付-商家信息服务费-商家承税;

最后

还是想吐槽这种编码形式的单元参数设计,可读性太差了。人为去维护code和具体含义的枚举,一旦维护乱了,后面的人就再也不知道这个编码的含义了。

Fel表达式实践的更多相关文章

  1. Fel表达式使用过程中需要注意的问题

    精度问题: 我们知道java中直接使用float和double参与的计算都可能会产生精度问题,比如0.1+0.3.1.0-0.9 等.所以一般财务系统,都会使用BigDecimal进行加减乘除. 在调 ...

  2. Fel表达式计算引擎学习

    转载原文地址:Fel是轻量级的高效的表达式计算引擎 Fel的问题 Fel的问题 Fel是轻量级的高效的表达式计算引擎 Fel在源自于企业项目,设计目标是为了满足不断变化的功能需求和性能需求. Fel是 ...

  3. FEL表达式的用法

    Fel是开放的,引擎执行中的多个模块都可以扩展或替换.Fel的执行主要是通过函数实现,运算符(+.-等都是Fel函数),所有这些函数都是可以替换的,扩展函数也非常简单. Fel有双引擎,同时支持解释执 ...

  4. Java8函数式接口以及lambda表达式实践

    罗列一下遇到可以转换成lamada表达式的场景,仅供参考,如有更好的方式,欢迎在评论区留言. 1.计算订单总金额 订单总金额一般是在后台循环叠加每个购买商品的金额已获取到,通常的方式如下 BigDec ...

  5. Shell编程学习(六)

    Shell 脚本条件测试与比较 条件测试方法综述 在Bash的各种条件结构和控制结构中都要进行各种测试,然后根据测试结果执行不同的操作,有时也会与if等条件语句相结合,来完成测试判断,以减少程序运行的 ...

  6. javascript之小积累-匿名函数表达式的最佳实践

    在写js的时候,还是经常会用的匿名函数表达式,比如 setTimeout(function() { console.log(110); }, 1000); 上面那个function()就是匿名函数表达 ...

  7. Atitit 表达式原理 语法分析 原理与实践 解析java的dsl  递归下降是现阶段主流的语法分析方法

    Atitit 表达式原理 语法分析 原理与实践 解析java的dsl  递归下降是现阶段主流的语法分析方法 于是我们可以把上面的语法改写成如下形式:1 合并前缀1 语法分析有自上而下和自下而上两种分析 ...

  8. 表达式树练习实践:C# 五类运算符的表达式树表达

    目录 表达式树练习实践:C# 运算符 一,算术运算符 + 与 Add() - 与 Subtract() 乘除.取模 自增自减 二,关系运算符 ==.!=.>.<.>=.<= 三 ...

  9. 表达式树练习实践:C# 循环与循环控制

    目录 表达式树练习实践:C# 循环 LabelTarget for / while 循环 无限循环 最简单的循环 多次循环 break 和 continue 一起 表达式树练习实践:C# 循环 C# ...

随机推荐

  1. POJ. 2253 Frogger (Dijkstra )

    POJ. 2253 Frogger (Dijkstra ) 题意分析 首先给出n个点的坐标,其中第一个点的坐标为青蛙1的坐标,第二个点的坐标为青蛙2的坐标.给出的n个点,两两双向互通,求出由1到2可行 ...

  2. JavaScript去除空格trim()的原生实现

    W3C那帮人的脑袋被驴踢了,直到javascript1.8.1才支持trim函数(与trimLeft,trimRight),可惜现在只有firefox3.5支持.由于去除字符串两边的空白实在太常用,各 ...

  3. MySQL、Oracle、DB2等数据库常规排序、自定义排序和按中文拼音字母排序

    MySQL常规排序.自定义排序和按中文拼音字母排序,在实际的SQL编写时,我们有时候需要对条件集合进行排序. 下面给出3中比较常用的排序方式,mark一下 1.常规排序ASC DESC ASC 正序 ...

  4. django-jet 中文文档

    关于 JET是新式的Django管理界面并且增强了功能.     内容 文档 开始 安装django-jet 安装仪表盘 配置 配置文件 自动补全 紧凑内联 过滤器 仪表盘 自定义仪表盘 仪表盘模块 ...

  5. A great tutorial with Jupyter notebook for ML beginners

    An end to end implementation of a Machine Learning pipeline SPANDAN MADAN Visual Computing Group, Ha ...

  6. Intervals ZOJ - 3953 (区间贪心)

    Chiaki has n intervals and the i-th of them is [li, ri]. She wants to delete some intervals so that ...

  7. Human life FZU - 2295 最大权闭合子图(第一次遇到被教育了)

    Xzz is playing a MMORPG "human life". In this game, there are N different skills. Some ski ...

  8. Naming Company CodeForces - 794C

    Oleg the client and Igor the analyst are good friends. However, sometimes they argue over little thi ...

  9. Django请求原理(二)

    1,Web服务器(中间件)收到一个http请求 2,Django在URLconf里查找对应的视图(View)函数来处理http请求 3,视图函数调用相应的数据模型来存取数据.调用相应的模板向用户展示页 ...

  10. j2ee 项目部署指引

    j2ee相关的项目一般是web工程或java application,部署到linux服务器上,本文结合自己的经验.教训,总结下部署的过程. 一.准备阶段 部署前要做的事情: 1.明确自己的产品都包含 ...