小程序后端开发之《PHP级差分佣系统功能》

小程序后端开发之《PHP级差分佣系统功能》


目录

一.需求来源 

二.需求分析 

三.级差收益模式 

四.级差配置项 

1)店长,店主邀请人数门槛 

2)日订单数量阶梯 

3)单笔佣金阶梯金额 

4)单笔订单佣金总限额 

5)级差佣金自动结算周期 

6)级差佣金开关 

五.代码开发 

1)自动升级身份 

2)自动计算当日的订单数、单笔订单金额、下级总人数、下级所有订单、下级已经完成交易订单 

3)佣金计算及分配 

六.功能测试 

七.总结 


一.需求来源

        最近正在开发一款S2BC的直播电商小程序,因为业务升级,需要在原来的直推佣金分销模式之上再添加级差分佣,系统是二级分佣模式,推广人数和推广订单都只统计到二级。

图一:直推收益模式图

图二:整个系统的收益模式图

二.需求分析

        开发前先来具体分析下整个系统大概情况;

        首页,用户进入小程序后自动免费注册用户帐号,用户通过购买会员商品或会员卡成为分销会员,分销会员可享受消费订单的直推收益,也就是说:所有会员自己购物或邀请的人购物均可获得消费奖励,其中包括一级10%或二级3%奖励,非会员用户自购或推广他人购物都无分佣。

        分销会员可通过邀请升级为店长和店主。当邀请的下级人数为12人时自动升级为店长,邀请的下级人数达到156人时自动升级为店主。

        其中:如果非会员用户邀请人数达到12人,自动成为会员,并升级为店长,同理,如果非会员用户邀请人数达到156人,自动成为会员,并升级为店主。

        整个系统店长和店主有级差团队佣金,根据每日下级订单数来分级别获得单笔佣金金额。

比方:

        当店长或店主当日订单达到1-100单时,每笔订单可得0.5元;

        当日订单达到101-300,单笔订单佣金为0.8元;

        当日订单达到301-600,单笔订单佣金为1.1元;

        当日订单达到601-1000,单笔订单佣金为1.3元;

        当日订单达到1001-2000,单笔订单佣金为1.5元;

        当日订单达到2001-5000,单笔订单佣金为1.7元;

        当日订单达到5001-10000,单笔订单佣金为1.8元;

        当日订单达到10001-20000,单笔订单佣金为1.9元;

        当日订单达到20000或以上,单笔订单佣金为2元;

        同时单个订单总佣金上限是2元;

        也就是说,如果有如下上下级关系:

        A店主->B店长->C店长->D店长->E->F,如果F购买商品产生一个订单,同时A当日订单数50,B当日订单数40,C当日订单数25,D当日订单数10,那边A、B、C、D可以同时通过该订单获得0.5元收益。

三.级差收益模式

图三:级差收益模式图

图四:直推和店主店长团队收益计算图

图五:累计团队收益

图六:团队总分润演示

四.级差配置项

        开发前先配置一些参数:

1)店长,店主邀请人数门槛

        参数及参数值设置:

图七:参数设置

图八:参数值设置

2)日订单数量阶梯

        参数及参数值设置:

图九:参数设置

图十:参数值设置

3)单笔佣金阶梯金额

        参数及参数值设置:

图十一:参数设置

图十二:参数值设置

4)单笔订单佣金总限额

        参数及参数值设置:

图十三:参数设置

图十四:参数值设置

5)级差佣金自动结算周期

        参数及参数值设置:

图十五:参数设置

图十六:参数值设置

6)级差佣金开关

        参数及参数值设置:

图十七:参数设置

图十八:参数值设置

五.代码开发

1)自动升级身份(部分代码)

a.下级人数

    //获取一级推广用户的人数public function getOneLevelCount($uid){return User::getDB()->where('spread_uid', $uid)->count();}
    //获取二级用户人数public function getSubIds($uid){return User::getDB()->where('spread_uid', $uid)->column('uid');}public function getTwoLevelCount($uid){$ids = $this->getSubIds($uid);return count($ids) ? User::getDB()->whereIn('spread_uid', $ids)->count() : 0;}
    //获取下级所有人数public function getSubTwoIds(array $ids,$sum,$uid){$sum = $sum;$count = count($ids) ? User::getDB()->whereIn('spread_uid', $ids)->count() : 0;if ($count == 0) {return $sum;} else {$sum += $count;$ids = User::getDB()->whereIn('spread_uid', $ids)->column('uid');if(in_array($uid,$ids)){$key = array_search($uid, $ids);if ($key !== false){array_splice($ids, $key, 1);}return $sum-1;} else {return $this->getSubTwoIds($ids,$sum,$uid);}}}public function getSubIds($uid){return User::getDB()->where('spread_uid', $uid)->column('uid');}public function getLevelCount($uid){$ids = $this->getSubIds($uid);//一级用户的ids$sum = User::getDB()->where('spread_uid', $uid)->count();//一级用户数量return $this->getSubTwoIds($ids,$sum,$uid);//二及以下级数用户数量和}

b.下级人员列表

    //获取下级用户public function spread_list(){[$level, $sort, $nickname] = $this->request->params(['level', 'sort', 'keyword'], true);$uid = $this->request->uid();[$page, $limit] = $this->getPage();return app('json')->success($level == 2? $this->repository->getTwoLevelList($uid, $nickname, $sort, $page, $limit): ($level == 1 ? $this->repository->getOneLevelList($uid, $nickname, $sort, $page, $limit) : $this->repository->getAllLevelList($uid, $nickname, $sort, $page, $limit)));}public function getOneLevelList($uid, $nickname, $sort, $page, $limit){$query = $this->search(['spread_uid' => $uid, 'nickname' => $nickname, 'sort' => $sort]);$count = $query->count();$list = $query->setOption('field', [])->field('uid,avatar,nickname,pay_count,pay_price,spread_count,spread_time')->page($page, $limit)->select();return compact('list', 'count');}public function getTwoLevelList($uid, $nickname, $sort, $page, $limit){$ids = $this->dao->getSubIds($uid);if (count($ids)) {$query = $this->search(['spread_uids' => $ids, 'nickname' => $nickname, 'sort' => $sort]);$count = $query->count();$list = $query->setOption('field', [])->field('uid,avatar,nickname,pay_count,pay_price,spread_count,spread_time')->page($page, $limit)->select();} else {$list = [];$count = 0;}return compact('list', 'count');}public function getAllLevelList($uid, $nickname, $sort, $page, $limit){$ids = $this->dao->getLevelCount($uid);if (count($ids)) {$query = $this->search(['uids' => $ids, 'nickname' => $nickname, 'sort' => $sort]);$count = $query->count();$list = $query->setOption('field', [])->field('uid,avatar,nickname,pay_count,pay_price,spread_count,spread_time')->page($page, $limit)->select();} else {$list = [];$count = 0;}return compact('list', 'count');}public function getLevelCount($uid){$ids = $this->getSubIds($uid);//一级用户的ids$sum = User::getDB()->where('spread_uid', $uid)->count();//一级用户数量return $this->getSubTwoIds($ids,$sum,$uid,$ids);//二及以下级数用户数量和}public function getSubTwoIds(array $ids,$sum,$uid,array $idss){$sum = $sum;$count = count($ids) ? User::getDB()->whereIn('spread_uid', $ids)->count() : 0;if ($count == 0) {return $idss;} else {$sum += $count;$ids = User::getDB()->whereIn('spread_uid', $ids)->column('uid');if(in_array($uid,$ids)){$key = array_search($uid, $ids);if ($key !== false){array_splice($ids, $key, 1);}$allIds = array_merge($idss, $ids);return $allIds;} else {$allIds = array_merge($idss, $ids);return $this->getSubTwoIds1($ids,$sum,$uid,$allIds);}}}

c.定时升级用户

    $this->tick(10000, function () {$userRepository = app()->make(UserRepository::class);request()->clearCache();$userIds = $userRepository->getSpreadUserIds(0);foreach ($userIds as $id) {try {$userRepository->updateSpread($id);Log::info('已自动升级用户' . var_export($id, 1));} catch (\Exception $e) {Log::info('自动升级身份失败' . var_export($id, 1));}}});public function getSpreadUserIds($is_promoter){return $this->dao->getUserIds($is_promoter);}public function getUserIds($is_promoter){return User::getDB()->where('is_promoter', $is_promoter)->column('uid');}public function updateSpread($uid){//自动升级为会员(店长/店主自动开能会员)$user = $this->dao->get($uid);$user->append(['level_count']);$config = systemConfig(['manager_level']);if($user->level_count >= $config['manager_level'] && $user['is_promoter'] == 0){$times = time();$user->is_promoter = 1;$user->gift_due_time = date('Y-m-d H:i:s',$times+365*24*60*60);$user->promoter_time = date('Y-m-d H:i:s');$user->spread_count = $user->level_count;$user->save();}}

2)自动计算当日的订单数、单笔订单金额、下级总人数、下级所有订单、下级已经完成交易订单(部分代码)

        //自动计算前一天的收入$this->tick(30000, function () {$userRepository = app()->make(UserRepository::class);request()->clearCache();$timer = ((int)systemConfig('order_commission_day')) ?: 1;$timers = $timer - 1;$time = date('Y-m-d 00:00:00', strtotime("- $timer day"));$times = date('Y-m-d 00:00:00', strtotime("- $timers day"));$userIds = $userRepository->getSpreadUserIds(1);//所有的分销会员if (count($userIds)) {//Log::info('打印所有的分销会员' . var_export($userIds, 1));foreach ($userIds as $userId) {try {//获取下面的人列表$uids = $userRepository->getLevelCount($userId);//单个分销员所有的下级if (count($uids)) {//Log::info('打印单个分销员所有的下级' . var_export($userId, 1) . var_export($uids, 1));$storeOrderRepository = app()->make(StoreOrderRepository::class);$orderIds = $storeOrderRepository->getFinishOrdersIds($time,$times,$uids);//所有下级人员所有已完成交易的订单,$time根据收货时间判断if (count($orderIds)) {//Log::info('打印单个分销员下所有下级人员所有的订单' . var_export($userId, 1).'---'.var_export($orderIds, 1));$spreadId = $userId;//分销员ID$spreadUserNum = count($uids);//下线总人数$spreadOrderOverNmu = count($orderIds);//当日下级完成交易的订单总数//邀请人所有订单$where = [];$query = $storeOrderRepository->usersOrderQuery($where, $uids);$spreadOrderAllNmu = $query->count();//邀请人所有订单//Log::info('分销员ID:' . var_export($spreadId, 1) . ';邀请数量:' . var_export($spreadUserNum, 1) . ';当日交易完成的订单总数:' . var_export($spreadOrderOverNmu, 1). ';下级订单总数:' . var_export($spreadOrderAllNmu, 1));//收入记录入库$config = systemConfig(['day_order_level_1','day_order_level_2','day_order_level_3','day_order_level_4','day_order_level_5','day_order_level_6','day_order_level_7','day_order_level_8','one_order_commission_1','one_order_commission_2','one_order_commission_3','one_order_commission_4','one_order_commission_5','one_order_commission_6','one_order_commission_7','one_order_commission_8','one_order_commission_max']);$commission = 0;if($spreadOrderOverNmu <= $config['day_order_level_1']){$commission = $config['one_order_commission_1'];} elseif($spreadOrderOverNmu > $config['day_order_level_1'] && $spreadOrderOverNmu <= $config['day_order_level_2']) {$commission = $config['one_order_commission_2'];} elseif($spreadOrderOverNmu > $config['day_order_level_2'] && $spreadOrderOverNmu <= $config['day_order_level_3']) {$commission = $config['one_order_commission_3'];} elseif($spreadOrderOverNmu > $config['day_order_level_3'] && $spreadOrderOverNmu <= $config['day_order_level_4']) {$commission = $config['one_order_commission_4'];} elseif($spreadOrderOverNmu > $config['day_order_level_4'] && $spreadOrderOverNmu <= $config['day_order_level_5']) {$commission = $config['one_order_commission_5'];} elseif($spreadOrderOverNmu > $config['day_order_level_5'] && $spreadOrderOverNmu <= $config['day_order_level_6']) {$commission = $config['one_order_commission_6'];} elseif($spreadOrderOverNmu > $config['day_order_level_6'] && $spreadOrderOverNmu <= $config['day_order_level_7']) {$commission = $config['one_order_commission_7'];} elseif($spreadOrderOverNmu > $config['day_order_level_7'] && $spreadOrderOverNmu <= $config['day_order_level_8']) {$commission = $config['one_order_commission_8'];} elseif($spreadOrderOverNmu > $config['day_order_level_8']) {$commission = $config['one_order_commission_max'];}//更新用户数据$userRepository->update($spreadId, ['spread_count' => $spreadUserNum,//下线总人数'spread_order_all' => $spreadOrderAllNmu,//邀请人所有订单'spread_order_over' => $spreadOrderOverNmu,//当日下级完成交易的订单总数'one_order_commission' => $commission,//每单的佣金]);foreach ($orderIds as $id) {try {Log::info('打印订单ID' . var_export($id, 1));} catch (\Exception $e) {Log::info('自动计算单笔级差佣金失败' . var_export($id, 1));}}}}} catch (\Exception $e) {Log::info('自动计算单笔级差佣金失败' . var_export($userId, 1));}}}});

3)佣金计算及分配(部分代码)

        $this->tick(60000, function () {$userRepository = app()->make(UserRepository::class);request()->clearCache();$timer = ((int)systemConfig('order_commission_day')) ?: 1;$timers = $timer - 1;$time = date('Y-m-d 00:00:00', strtotime("- $timer day"));$times = date('Y-m-d 00:00:00', strtotime("- $timers day"));$userIds = $userRepository->getSpreadUserIds(1);//所有的分销会员if (count($userIds)) {//Log::info('打印所有的分销会员' . var_export($userIds, 1));foreach ($userIds as $userId) {try {//获取下面的人列表$uids = $userRepository->getLevelCount($userId);//单个分销员所有的下级if (count($uids)) {//Log::info('打印单个分销员所有的下级' . var_export($userId, 1) . var_export($uids, 1));$storeOrderRepository = app()->make(StoreOrderRepository::class);$orderIds = $storeOrderRepository->getFinishOrdersIds($time,$times,$uids);//所有下级人员所有已完成交易的订单,$time根据收货时间判断if (count($orderIds)) {foreach ($orderIds as $id) {try {$storeOrderRepository->orderSpreadComputed($id);Log::info('自动计算级差佣金的订单ID' . var_export($id, 1));} catch (\Exception $e) {Log::info('自动计算级差佣金失败' . var_export($id, 1));}}}}} catch (\Exception $e) {Log::info('自动计算级差佣金失败' . var_export($userId, 1));}}}});
    public function getFinishOrdersIds($big,$end,array $uid){return StoreOrderStatus::getDB()->alias('A')->leftJoin('StoreOrder B', 'A.order_id = B.order_id')->where('A.change_type','in',['over','auto_over'] )->where('B.is_computed',0)->where('A.change_time', '>=', $big)->where('A.change_time', '<', $end)->where('B.paid', 1)->where('B.status', 3)->where('B.uid','in',$uid)->column('A.order_id');}
    public function orderSpreadComputed($id, ?User $user = null){if (systemConfig('differential_commission')) {$order = $this->dao->search(!$user ? [] : ['uid' => $user->uid], null)->where('order_id', $id)->where('is_del', 0)->where('is_computed', 0)->find();if (!$order)throw new ValidateException('订单不存在');if ($order['status'] != 3 || $order['order_type'])throw new ValidateException('订单状态有误');$order->is_computed = 1;Db::transaction(function () use ($order) {$this->orderSpread($order);$order->save();});}}
    public function orderSpread(StoreOrder $order){Db::transaction(function () use ($order) {$spreadId = $this->getTopUid($order['uid'],$order['uid'],[],[]);foreach ($spreadId['a'] as $id){$userRepository = app()->make(UserRepository::class);$users = $userRepository->getWhere(['uid' => $id, 'status' => 1]);$this->spreadComputed($order,$id,$users->one_order_commission);}$order->save();});}
    //根据用户id 获取头部推广人idpublic function getTopUid($id, $uid, array $a, array $b){$c = [];$num = 0;$userRepository = app()->make(UserRepository::class);$puser = $userRepository->getWhere(['uid' => $uid, 'status' => 1]);if ($puser->spread_uid > 0 && $puser->spread_uid <> $id) //有上级,上级不是消费者{$pusers = $userRepository->getWhere(['uid' => $puser->spread_uid, 'status' => 1]);if($pusers->one_order_commission > 0){$a1= $a;$b1= $b;array_push($a1, $puser->spread_uid);array_push($b1, $pusers->one_order_commission);}//计算佣金是否超过最大上限foreach ($b1 as $ids) {$num += $ids;}$max = systemConfig('one_order_commission_max') ?: 2;if($num <= $max){//佣金总和未超过上限return $this->getTopUid($id,$puser->spread_uid,$a1,$b1);} else {//佣金总和超过上限$c['uid'] = $id;$c['a'] = $a;$c['b'] = $b;return $c;}} else {//有上级,上级是消费者,或没有上级$c['uid'] = $id;$c['a'] = $a;$c['b'] = $b;return $c;}}
    public function spreadComputed(StoreOrder $order, $spreadId, $commission){$userBillRepository = app()->make(UserBillRepository::class);//TODO 添加冻结佣金if ($commission > 0) {$userRepository = app()->make(UserRepository::class);$users = $userRepository->getWhere(['uid' => $order['uid'], 'status' => 1]);$userBillRepository->incBill($spreadId, 'brokerage', 'order_one', ['link_id' => $order['order_id'],'status' => 0,'title' => '获得推广级差佣金','number' => $commission,'mark' =>  $users->nickname . '有用户成功消费' . floatval($order['pay_price']) . '元,奖励推广级差佣金' . floatval($commission),'balance' => 0]);$userRepository->incBrokerage($spreadId, $commission);}}
    public function incBill(int $uid, string $category, string $type, array $data){return $this->bill($uid, $category, $type, 1, $data);}
    public function incBrokerage($uid, $inc, $type = '+'){$weekKey = 'b_top_' . date('Y-m');$moneyKey = 'b_top_' . monday();//TODO 佣金周榜$brokerage = Cache::zscore($weekKey, $uid);$brokerage = $type == '+' ? bcadd($brokerage, $inc, 2) : bcsub($brokerage, $inc, 2);Cache::zadd($weekKey, $brokerage, $uid);//TODO 佣金月榜$brokerage = Cache::zscore($moneyKey, $uid);$brokerage = $type == '+' ? bcadd($brokerage, $inc, 2) : bcsub($brokerage, $inc, 2);Cache::zadd($moneyKey, $brokerage, $uid);}

六.功能测试

先测试下下级人数:

用户信息返回下级人数信息

按级数返回下级人员列表

全部下级人员列表

推广人下级全部订单

推广人完成交易的下级订单

 

 

 

七.总结

        因为时间问题,本文只简单的介绍了本次开发过程,具体过程及工作比较多,技术也涉及的比较多,无法在此尽数介绍。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部