根据业务需要,订单折扣需要分拆到订单的每个商品上去,熬夜到零晨2点多钟实现了此算法,此算法实现了以下几个分拆的原则规则:
一、有单品折扣活动,直接把对应的单品折扣的金额直接分拆到对应的参与活动的单品上去
二、有满减活动,对应的折扣只会分摊到参与活动的商品上去
三、分摊时尽量安商品的小计的占比进行分摊,小计越大分摊的金额越多,小计金额越小分摊的金额越小
四、最后由于整除余数的部分会分摊到价格最高的符合条件的商品上,而不是直接把余数直接分摊到最后一个商品上,导致最后一个商品的价格低出现异常情况
这个逻辑用php语言实现如下,分亨出来供大家参考:
function split_order_goods_discount($order_goods,$order){
$discount = $order['discount'];
//获取订单的折扣对应的活动明细
$left_activity_discount = $discount;
$order_activity = $GLOBALS['db']->getAll("select a.act_id, a.act_name, a.act_type, a.price, f.act_goods_list from self_order_activity as a left join self_favourable_activity as f on f.act_id=a.act_id where a.order_id='$order[order_id]'");
foreach($order_activity as &$activity){
$activity['total_price'] =0;
$activity['act_goods_list_arr'] = $activity['act_goods_list']?explode(',',$activity['act_goods_list']):[];
foreach($order_goods as &$goods){
if(in_array($goods['goods_sn'],$activity['act_goods_list_arr'])){
$activity['total_price'] +=$goods['goods_price'] * $goods['goods_number'];
$goods['split_act_id'] = $activity['act_id'];
}
}
if($activity['act_goods_list_arr'] && $activity['total_price']){
$activity['split_price'] = $discount>=$activity['price']? $activity['price']:$discount;
}
}
foreach($order_activity as $cur_activity){
foreach($order_goods as &$goods){
if(!isset($goods['split_discount'])) $goods['split_discount']=0;
if(!isset($goods['split_discount_price'])) $goods['split_discount_price']=0;
if(in_array($goods['goods_sn'],$cur_activity['act_goods_list_arr'])){
$cur_split_discount= $this->priceformat(($cur_activity['split_price']*($this->priceformat($goods['goods_price'] * $goods['goods_number']/$cur_activity['total_price'],1))/$goods['goods_number']),1)*$goods['goods_number'];
$cur_split_discount_price = $goods['goods_number']? $cur_split_discount/$goods['goods_number']:0;
$goods['split_discount']+=$cur_split_discount;
$goods['split_discount_price']+=$cur_split_discount_price;
$left_activity_discount -=$cur_split_discount;
}
}
}
//如果没参加任务活动分摊,重新分摊一下折扣
if( $left_activity_discount == $discount ){
$left_total_price = 0;
foreach($order_goods as &$goods){
$left_total_price += intval($goods['goods_price']) * $goods['goods_number'];
}
foreach($order_goods as &$goods){
if(!isset($goods['split_discount'])) $goods['split_discount']=0;
if(!isset($goods['split_discount_price'])) $goods['split_discount_price']=0;
$cur_split_discount = $this->priceformat(($left_activity_discount*($this->priceformat($goods['goods_price'] * $goods['goods_number']/$left_total_price,1))/$goods['goods_number']),1)*$goods['goods_number'];
$cur_split_discount_price = $goods['goods_number']? $cur_split_discount/$goods['goods_number']:0;
$goods['split_discount']+=$cur_split_discount;
$goods['split_discount_price']+=$cur_split_discount_price;
$left_activity_discount -=$cur_split_discount;
}
}
//处理剩余的尾数,从最后一个商品遍历,把尾数的折扣到加一个符合条件的商品上:这个商品需要可以被这个商品的数量整除,并且整除后的值要小于商品价格,否则会出现价格倒挂情况
if($left_activity_discount >0){
//把数组排一下序,最后要扣的从最大合乎条件的商品上去折
$left_price =[];
$left_i =[];
foreach($order_goods as $k=>$v){
$left_price[] = ($v['goods_price'] - ($v['split_discount_price'] ?? 0) )*$v['goods_number'];
$left_i[] =$k;
}
array_multisort($left_price,SORT_DESC,SORT_NUMERIC,$left_i,SORT_DESC,SORT_NUMERIC);
foreach($left_i as $i){
if($order_goods[$i]['goods_price']>$left_activity_discount && $order_goods[$i]['goods_number']>0){
$need_split_discount_price = number_format($left_activity_discount/$order_goods[$i]['goods_number'],2,'.','');
//这晨
if(abs($need_split_discount_price-($left_activity_discount/$order_goods[$i]['goods_number']))<0.001){
$order_goods[$i]['split_discount'] += $left_activity_discount;
$order_goods[$i]['split_discount_price'] += $need_split_discount_price;
$left_activity_discount =0;
break;
}
}
}
}
if($left_activity_discount >0){
//已超出我的能力处理范围啦 ,不过这种情况一般永远不会发生,哈哈!
}
//处理尾数
return $order_goods;
}
//不四舍五入保留一位
function priceformat($price,$weishu=1){
return substr(number_format($price, $weishu+1, '.', ''), 0, -1);
}
以上算法是把折扣分摊到每个商品的单价里,实际情况会出现除不尽的情况,有些时间,可能只用分摊下商品级,不用分摊到商品的单价里,这种情况是不存在除不尽的情况,相应的算法稍有区别,相应的代码如下:
function split_order_goods_discount($order_goods,$order){
$discount = $order['discount']*100;
foreach($order_goods as &$goods){
$goods['goods_price'] = $goods['goods_price']*100;
$goods['split_discount']=0;
}
//获取订单的折扣对应的活动明细
$order_activity = $GLOBALS['db']->getAll("select a.act_id, a.act_name, a.act_type, a.price, f.act_goods_list from self_order_activity as a left join self_favourable_activity as f on f.act_id=a.act_id where a.order_id='$order[order_id]'");
$total_act_discount = 0;
foreach($order_activity as &$activity){
$activity['total_price'] =0;
$activity['price'] = $activity['price']*100;
$activity['act_goods_list_arr'] = $activity['act_goods_list']?explode(',',$activity['act_goods_list']):[];
foreach($order_goods as &$goods){
if(in_array($goods['goods_sn'],$activity['act_goods_list_arr'])){
$activity['total_price'] +=$goods['goods_price'] * $goods['goods_number'];
$goods['split_act_id'] = $activity['act_id'];
}
}
if($activity['act_goods_list_arr'] && $activity['total_price']){
$activity['split_price'] = $discount>=$activity['price']? $activity['price']:$discount;
}
$total_act_discount +=$activity['price'];
}
//if($discount != $total_act_discount ) $discount = $total_act_discount;
$left_activity_discount = intval($discount);
foreach($order_activity as $cur_activity){
$prva = [];
$cur_left_activity_discount =(int)$cur_activity['split_price'];
foreach($order_goods as $prvi=>&$goods){
if(in_array($goods['goods_sn'],$cur_activity['act_goods_list_arr'])){
$cur_split_discount= intval($cur_activity['split_price']*($goods['goods_price'] * $goods['goods_number']/$cur_activity['total_price']));
$goods['split_discount']+=(int)$cur_split_discount;
$left_activity_discount -=(int)$cur_split_discount;
$cur_left_activity_discount -=(int)$cur_split_discount;
$prva[] = $prvi;
}
}
if($cur_left_activity_discount>0){
$prva = array_reverse($prva);
foreach($prva as $prv){
if(($cur_left_activity_discount+$order_goods[$prv]['split_discount'])<=$order_goods[$prv]['goods_price']*$order_goods[$prv]['goods_number']){
$order_goods[$prv]['split_discount']+=$cur_left_activity_discount;
$left_activity_discount -= $cur_left_activity_discount;
$cur_left_activity_discount =0;
break;
}
}
}
}
//如果没参加任务活动分摊,重新分摊一下折扣
if($left_activity_discount == $discount ){
$left_total_price = 0;
foreach($order_goods as &$goods){
$left_total_price += $goods['goods_price'] * $goods['goods_number']-$goods['split_discount'];
}
foreach($order_goods as &$goods){
$cur_split_discount = intval($left_activity_discount*($goods['goods_price'] * $goods['goods_number']-$goods['split_discount'])/$left_total_price);
$goods['split_discount']+=$cur_split_discount;
$left_activity_discount -=$cur_split_discount;
}
}
//处理剩余的尾数,从最后一个商品遍历,把尾数的折扣到加一个符合条件的商品上:这个商品需要可以被这个商品的数量整除,并且整除后的值要小于商品价格,否则会出现价格倒挂情况
if($left_activity_discount >0){
//把数组排一下序,最后要扣的从最大合乎条件的商品上去折
$left_price =[];
$left_i =[];
foreach($order_goods as $k=>$v){
$left_price[] = $v['goods_price']*$v['goods_number']-$goods['split_discount'];
$left_i[] =$k;
}
array_multisort($left_price,SORT_DESC,SORT_NUMERIC,$left_i,SORT_DESC,SORT_NUMERIC);
foreach($left_i as $i){
if($order_goods[$i]['goods_price']*$order_goods[$i]['goods_number'] - $order_goods[$i]['split_discount']>=$left_activity_discount){
$order_goods[$i]['split_discount'] += $left_activity_discount;
$left_activity_discount =0;
break;
}
}
}
foreach($order_goods as &$goods){
$goods['goods_price'] = $goods['goods_price']/100;
$goods['split_discount'] /= 100;
$goods['split_discount_price'] /= 100;
}
return $order_goods;
}
如有问题,欢迎大家留言沟通,点赞支持!!!