IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Ecstore订单促销策略错误读取其他商品促销的BUG

    tiandi发表于 2016-05-20 03:49:50
    love 0

    最近发现一个Ecstore大bug关于订单促销这一块的,能直接影响到最后的结算金额,使结算价格远远低于应付金额。在和官方技术人员沟通中,发现最新版的ecstore仍然没有修复此bug,因此有必要将此bug公布一下。

    活动名称:第2件商品半价,多款商品可同时享受。
    场景重现:
    1. 建立1条订单策略,优先权50,不排他。指定包含购买商品A数量x2的时候,订单-100元。
    2. 建立另1条订单策略,优先权50,不排他。指定包含购买商品B数量x2的时候,订单-60元。
    3. 建立商品A,单价为200元,商品B单价为120,确保商品单价要大于减免价格。

    结果发现买商品A两件时,结算价格变成了200×2-100-60了,执行了商品A的100元的优惠基础上同时又执行了商品B的的促销优惠。同一时间上,生效的第2件半价的订单促销策略不止这两条,查看其他产品结算价格都正常。起初怀疑是后台设置问题,但是在仔细比对其他产品的第2件商品半价促销设置后,并没有发现有什么设置上的问题,于是开始怀疑本身的代码有bug。

    订单促销走的是/b2c/lib/cart/postfilter/promotion.php到/b2c/lib/sales/,代码封装得很深,最后定位到产生的问题的文件/b2c/lib/sales/basic/operator/contain.php这个文件的validate函数。

    原代码为:

    public function validate($operator,$value,$validate) {
            if( !$value  || !$validate ) return false;
            //商品包含某个字
            switch($operator) {
                case '()':
                    if(is_array($value)) return in_array($validate,$value);
                    $flag = strpos($validate,$value);
                    if( $flag===false ) 
    			return false;
                    else 
    			return true;
                    break;
                case '!()':
                    if(is_array($value)) return !in_array($validate,$value);
                    $flag = strpos($validate,$value);
                    if( $flag===false ) return false;
                    else return true;
                    break;
            }
            return false;
        }
    

    这里函数参数operator是包含的符号’()’,value是策略里的goods_id(多个的情况下是数组),validate是购物车里的goods_id(只可能是单个)。可以看到如果策略里包含多个商品,则会用in_array判断购物车商品是否在策略生效的商品清单中,这个没问题。问题点在于下面这条strpos,如果购物车内的goods_id是123,策略里生效的goods_id是1234的话,那么strpos(’123′,’1234′)是成立的。另外查了一下后台所有策略的可选项,发现在设置商品名称匹配的时候也用到了包含,所以,这里针对性的略做修改,如下:

     case '()':
        if(is_array($value)) return in_array($validate,$value);
    				
    	//by tiandi 2016.5.9 尝试修复goods_id=123的商品会载入goods_id=1234订单促销的错误,不清楚这里原先为什么要用strpos,可能并不局限用于促销策略模块,
    	//所以可能会造成其他问题。如果value字符串里都是数字(goods_id),则不使用strpos,而直接判断是否和validate相同
    	//start 
    	if(is_numeric($value)&&($validate != $value)) 
    		return false;
    	//end
    				
            $flag = strpos($validate,$value);
            if( $flag===false ) 
    		return false;
            else 
    		return true;
            break;
    

    这样在比对goods_id的时候就不会再出现读取错误的情况了。Ecstore的框架写得还真是有够复杂,查明上述问题,几乎涉及到10个左右的文件。

    PS:已经将该问题提交给官方技术了。

    文章评分2次,平均分5.0:★★★★★


沪ICP备19023445号-2号
友情链接