RecordWaitCommission.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2017~2021 https://www.yiovo.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
  8. // +----------------------------------------------------------------------
  9. // | Author: 萤火科技 <admin@yiovo.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\common\service\commission;
  13. use app\api\model\ConfigPercent;
  14. use app\api\model\Order;
  15. use app\api\model\User;
  16. use app\api\model\user\CommissionsDetail;
  17. use app\common\library\helper;
  18. use app\common\model\GoodsSku;
  19. use app\common\model\ShopIdentity;
  20. use app\common\model\Shops;
  21. use app\common\model\store\Setting;
  22. use app\common\service\BaseService;
  23. use app\common\service\Message;
  24. use think\db\exception\DataNotFoundException;
  25. use think\db\exception\DbException;
  26. use think\db\exception\ModelNotFoundException;
  27. use think\facade\Db;
  28. use think\facade\Log;
  29. use think\facade\Queue;
  30. /**
  31. * 待结算佣金服务类
  32. * 1.待分佣记录是用队列写入,2.分佣结算是定时任务,30秒清算一次,3.每日奖励金是执行计划crontab,每天凌晨一次,4.每月奖励金结算是执行计划crontab在次月的20日凌晨结算
  33. * Class Complete
  34. * @package app\common\service\order
  35. */
  36. class RecordWaitCommission extends BaseService
  37. {
  38. /**
  39. * 获取门店参与分佣的人与角色
  40. * @param $shopId
  41. * @param $staffId
  42. * @return array
  43. * @throws DataNotFoundException
  44. * @throws DbException
  45. * @throws ModelNotFoundException
  46. */
  47. private function getShopUser($shopId,$staffId): ?array
  48. {
  49. $md = new ShopIdentity();
  50. $pers = $md->field('shop_id,role_id as role,fc_percent as percent')->where('shop_id',$shopId)->select();
  51. $pers = $pers?$pers->toArray():[];
  52. $shop = Shops::find($shopId);
  53. if(!$shop)return null;
  54. $roles = array_column($pers,'role');
  55. //获取新增身份的用户
  56. $cUsers = \app\common\model\User::getCommissionUsers($shopId,$roles);
  57. //加入店老板分佣比例
  58. $pers[] = ['shop_id'=>$shopId,'role'=>User::SHOP_BOSS,'percent'=>$shop->boss_percent];
  59. $pers[] = ['shop_id'=>$shopId,'role'=>User::SHOP_MG,'percent'=>$shop->manager_percent];
  60. //加入店员分佣比例
  61. $pers[] = ['shop_id'=>$shopId,'role'=>User::SHOP_SELLER,'percent'=>$shop->staff_percent];
  62. $pers = array_column($pers,null,'role');
  63. //加入店员
  64. $cUsers[] = ['user_id'=>$shop->boss_user_id,'role'=>User::SHOP_BOSS];
  65. if ($shop->manager_user_id){
  66. $cUsers[] = ['user_id'=>$shop->manager_user_id,'role'=>User::SHOP_MG];
  67. }
  68. $cUsers[] = ['user_id'=>$staffId,'role'=>User::SHOP_SELLER];
  69. return ['pers'=>$pers,'cUsers'=>$cUsers];
  70. }
  71. /**
  72. * Notes:计算商品预计分佣
  73. * Author: zhangs
  74. * DateTime: 2021/10/9 11:09
  75. * @param $goodsInfo
  76. * @param $userInfo
  77. * @return string
  78. */
  79. public function calcFcYjAmount($goodsInfo, $userInfo) {
  80. if (!$userInfo) {
  81. return '0.00';
  82. }
  83. $goodsSku = GoodsSku::where('goods_id', $goodsInfo['goods_id'])->order('goods_price', 'asc')->find();
  84. $percents = ConfigPercent::find(1);
  85. $ticketRate = $percents->ticket_rate;
  86. $platformRate = $goodsSku['platform_rate'] > 0 ? $goodsSku['platform_rate'] : $percents->platform_rate;
  87. $staff_percent = $percents->getAttr('staff_percent'); // 店员
  88. $manager_percent = $percents->getAttr('manager_percent'); // 店长
  89. $boss_percent = $percents->getAttr('boss_percent'); // 店老板
  90. $pool = ($goodsInfo['goods_price_min'] - $goodsSku['clearing_price'] - $goodsInfo['goods_price_min']*$ticketRate/100)*$platformRate/100;
  91. $money = '0.00';
  92. if ($userInfo->role == User::SHOP_SELLER) {
  93. // 推荐人是店员
  94. $money = helper::bcadd($pool * $staff_percent/100,0,2);
  95. } elseif ($userInfo->role == User::SHOP_MG) {
  96. // 推荐人是店长
  97. // $money = helper::bcadd($pool * $manager_percent/100,0,2);
  98. } elseif ($userInfo->role == User::SHOP_BOSS) {
  99. // 推荐人是店老板
  100. // $money = helper::bcadd($pool * $boss_percent/100,0,2);
  101. }
  102. return $money;
  103. }
  104. /**
  105. * 待结算店员分销佣金
  106. * @param $pool
  107. * @param $cUsers
  108. * @param $percents
  109. * @param $orderId
  110. * @param $shopId
  111. * @param $buyerId
  112. * @param $orderCreateTime
  113. * @return bool
  114. * @throws \Exception
  115. */
  116. private function handleWaitShopSellerCommission($pool,$cUsers,$percents,$orderId,$shopId,$buyerId,$orderCreateTime): bool
  117. {
  118. $data = [];
  119. foreach ($cUsers as $cUser){
  120. $percent = $percents[$cUser['role']]['percent'];
  121. $money = helper::bcadd($pool * $percent/100,0,4);
  122. $data[] = ['user_id'=>$cUser['user_id'],
  123. 'clearing_money'=>$money,
  124. 'order_id'=>$orderId,
  125. 'shop_id'=>$shopId,
  126. 'role'=>$cUser['role'],
  127. 'buyer_user_id'=>$buyerId,
  128. 'commission_percent'=>$percent,
  129. 'order_create_time'=>$orderCreateTime,
  130. 'order_sale_volume'=>$pool
  131. ];
  132. }
  133. if (count($data)){
  134. $model = new \app\common\model\user\CommissionsDetail();
  135. $model->saveAll($data);
  136. }
  137. return true;
  138. }
  139. /**
  140. * 订单支付回调成功时,将待分佣明细job加入队列执行
  141. * @param $orderId
  142. * @return bool
  143. */
  144. public function recordWaitCommission($orderId){
  145. $jobHandlerClassName = 'app\job\recordWaitCommissionsDetail';
  146. $jobQueueName = "orderWaitCommissionsQueue";
  147. //数组数据
  148. $orderData = [
  149. 'orderId' => $orderId,
  150. ];
  151. $isPushed = Queue::push($jobHandlerClassName, $orderData ,$jobQueueName);
  152. //$isPushed = Queue::later(5, $jobHandlerClassName, $orderData, $jobQueueName);
  153. if( $isPushed !== false ){
  154. return true;
  155. }else{
  156. log_record('加队列失败,orderId:'.$orderId);
  157. return false;
  158. }
  159. }
  160. //todo 1.下单时订单商品快照表需要记录分享者的id,
  161. //todo 2.需要在下单成功后变更用户的推荐人信息和门店信息
  162. /**
  163. * 待结算佣金计算,需要在支付回调完成时调用这个方法去记录待结算的佣金详情,在售后期结束后调用结算
  164. * @param $orderId
  165. * @return bool
  166. * @throws DataNotFoundException
  167. * @throws DbException
  168. * @throws ModelNotFoundException
  169. */
  170. public function waitGiveOutCommission(int $orderId){
  171. Log::error('Job wait orderId:'.$orderId);
  172. $order = Order::where(['order_id'=>$orderId,'commission_settlement_status'=>10])->find();
  173. if (empty($order)){
  174. return true;
  175. }
  176. $orderCreateTime = strtotime($order['create_time']);
  177. //如果订单退单退货,不执行分佣
  178. $buyerId = $order->user_id;
  179. $ratios = Setting::getItem('distributor_grade', 10001)['distributor'];
  180. $buyerUser = User::where('is_delete',0)->find($buyerId);
  181. Db::startTrans();
  182. try{
  183. //商品加入购物车时需要记录分享者id,商品推荐人
  184. $staffUserId = (int)$order['staff_user_id'];
  185. if ($staffUserId == $buyerId){
  186. throwError('自分享无分佣');
  187. }
  188. //pool = 实付金额 + 现金米卡抵扣金额 - 运费
  189. $poolTemp = helper::bcadd($order['pay_price'] , $order['rice_card_money'],4);
  190. $pool = helper::bcsub($poolTemp , $order['express_price'],4);
  191. if ($pool <= 0){
  192. throwError('金额有误');
  193. }
  194. Log::info('Job orderId:'.$orderId.',pool:'.$pool.',staffUserId:'.$staffUserId);
  195. //如果商品有推荐人
  196. $staffUser = null;
  197. $shopId = 0;
  198. if ($staffUserId > 0){
  199. $shopId = $order['staff_shop_id'];
  200. $staffUser = User::where('is_delete',0)
  201. ->field('user_id,role,shop_id,upper_user_id,seller_grade')
  202. ->find($staffUserId);
  203. if (!$staffUser){
  204. throwError('推广人用户不存在A');
  205. }
  206. }else{
  207. //店长、店老板、店内新增身份,店员自己购买都不分佣
  208. if (in_array($buyerUser->role,[2,3,4,5])){
  209. throwError('买家角色不支持分佣');
  210. }
  211. if (in_array($buyerUser->role,[1,99]) && isset($buyerUser->upper_user_id) && $buyerUser->upper_user_id > 0 ){
  212. $staffUser = User::where('is_delete',0)
  213. ->field('user_id,role,shop_id,upper_user_id,seller_grade')
  214. ->find($buyerUser->upper_user_id);
  215. if (!$staffUser){
  216. throwError('推广人用户不存在B');
  217. }
  218. if (!in_array($staffUser->role,[User::COMMISSION_USER,User::SHOP_SELLER])){
  219. throwError('推广人不支持分佣');
  220. }
  221. $shopId = $staffUser['shop_id'];
  222. }else{
  223. throwError('买家无上级A');
  224. }
  225. }
  226. if (empty($staffUser)){
  227. throwError('买家无上级B');
  228. }
  229. if ($staffUser->role == User::SHOP_SELLER){
  230. $flag = $this->getShopUser($shopId,$staffUser->user_id);
  231. if (!$flag){
  232. throwError('门店员工获取异常,shopId:'.$shopId);
  233. }
  234. $cUsers = $flag['cUsers'];
  235. $percents = $flag['pers'];
  236. $flag1 = $this->handleWaitShopSellerCommission($pool,$cUsers,$percents,$orderId,$shopId,$buyerId,$orderCreateTime);
  237. if (!$flag1){
  238. throwError('写门店分佣失败');
  239. }
  240. }
  241. if ($staffUser->role == User::COMMISSION_USER){
  242. $levelOneRate = $ratios[$staffUser->seller_grade-1]['first_commission']??0;
  243. $money = helper::bcadd($pool * $levelOneRate/100,0,4);
  244. //dd($order);
  245. if (CommissionsDetail::addNewCommission($staffUser->user_id,$orderId,$orderCreateTime,$money,0,$buyerId,User::COMMISSION_USER,1,$staffUser->seller_grade,$levelOneRate,$pool) === false){
  246. throwError('写分销员一级分佣失败');
  247. }
  248. //二级佣金
  249. if ($staffUser->upper_user_id >0){
  250. $secondUser = \app\common\model\User::where('is_delete',0)->find($staffUser->upper_user_id);
  251. if ($secondUser && $secondUser->role == User::COMMISSION_USER){
  252. $levelTwoRate = $ratios[$secondUser->seller_grade-1]['second_commission']??0;
  253. $money1 = helper::bcadd($pool * $levelTwoRate/100,0,4);
  254. if ( CommissionsDetail::addNewCommission($staffUser->upper_user_id,$orderId,$orderCreateTime,$money1,0,$buyerId,User::COMMISSION_USER,2,$secondUser->seller_grade,$levelTwoRate,$pool) === false){
  255. throwError('写分销员二级分佣失败');
  256. }
  257. }
  258. }
  259. }
  260. //订单佣金结算状态改为待结算
  261. $order->commission_settlement_status = 0;
  262. $order->save();
  263. Db::commit();
  264. }catch(\Exception $e){
  265. Db::rollback();
  266. $msg = 'Job orderId:'.$orderId.':'.$e->getMessage();
  267. Log::error($msg);
  268. Message::wxRobot($msg);
  269. return false;
  270. }
  271. return true;
  272. }
  273. }