【原创】关于订单折扣分拆到商品明细的算法分亨

33 篇文章 0 订阅
这篇博客分享了一个PHP实现的订单折扣分摊算法,遵循了特定的分摊原则:单品折扣、满减活动、按商品小计占比分摊以及处理尾数。算法详细描述了如何将折扣平摊到每个商品,特别处理了除不尽的情况,以避免价格异常。代码中还包含了未参加活动商品的折扣分摊和剩余尾数的处理策略。
摘要由CSDN通过智能技术生成

根据业务需要,订单折扣需要分拆到订单的每个商品上去,熬夜到零晨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;
	}

如有问题,欢迎大家留言沟通,点赞支持!!!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

phpgolife

您的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值