ProfitsRepository.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. <?php
  2. namespace app\common\repositories\profits;
  3. use app\common\dao\profit\ZeroUserProfitDao;
  4. use app\common\dao\user\UserDao;
  5. use app\common\dao\user\ZeroUserLineDao;
  6. use app\common\enum\user\ZeroUserEnum;
  7. use app\common\model\log\OldUserLog;
  8. use app\common\model\profit\ZeroUserProfitsDetail;
  9. use app\common\model\user\User;
  10. use app\common\utils\QueueLogger;
  11. use app\jobs\ZeroUserProfits;
  12. use think\db\exception\DataNotFoundException;
  13. use think\db\exception\DbException;
  14. use think\db\exception\ModelNotFoundException;
  15. use think\facade\Db;
  16. class ProfitsRepository
  17. {
  18. // 初级合伙人id
  19. const BASIC = 4;
  20. // 初级合伙人佣金比例
  21. const BASIC_PERCENT = 0.15;
  22. // 中级合伙人id
  23. const MIDDLE = 5;
  24. // 中级合伙人佣金比例
  25. const MIDDLE_PERCENT = 0.15;
  26. // 高级合伙人id
  27. const HIGH = 6;
  28. // 高级合伙人佣金比例
  29. const HIGH_PERCENT = 0.15;
  30. // 合伙人数据映射
  31. private $parents = [
  32. self::BASIC => self::BASIC_PERCENT,
  33. self::MIDDLE => self::MIDDLE_PERCENT,
  34. self::HIGH => self::HIGH_PERCENT,
  35. ];
  36. // 业绩数据映射(pv)
  37. private $pv = [
  38. 1180 => 700,
  39. 11800 => 7000,
  40. 10620 => 6300,
  41. 9440 => 5600,
  42. 2360 => 1400
  43. ];
  44. // 用户
  45. private $userDao;
  46. // 订单(老)
  47. // private $oldUserOfGoodsDao;
  48. // 订单(新)
  49. // private $storeOrder;
  50. public function __construct()
  51. {
  52. $this->userDao = new UserDao();
  53. // $this->oldUserOfGoodsDao = new OldUserOfGoodsDao();
  54. // $this->storeOrder = new StoreOrderDao();
  55. }
  56. /**
  57. * @param $param
  58. * @return string|true
  59. * @throws DataNotFoundException
  60. * @throws DbException
  61. * @throws ModelNotFoundException
  62. * 获取需要分红的0号线用户并加入队列
  63. */
  64. public function getZeroUser($param)
  65. {
  66. $zeroUserId = $param['zeroUserId'];
  67. // 0号线用户id是0的时候,获取全部0号线用户
  68. if ($zeroUserId == 0) {
  69. $zeroUserId = $this->getAllZeroUserIds();
  70. }
  71. if (is_string($zeroUserId)) {
  72. $zeroUserId = explode(',', $zeroUserId);
  73. }
  74. // 拼接队列需要的数据
  75. $queueData = [
  76. 'startTime' => $param['startTime'],
  77. 'endTime' => $param['endTime'],
  78. 'is_test' => $param['isTest'],
  79. 'amount' => $param['amount']
  80. ];
  81. // 记录日志
  82. $insertData = [
  83. 'start_time' => $param['startTime'],
  84. 'end_time' => $param['endTime'],
  85. 'is_test' => $param['isTest'],
  86. 'amount' => $param['amount']
  87. ];
  88. $dao = new ZeroUserProfitDao();
  89. // 加入队列
  90. try {
  91. foreach ($zeroUserId as $value) {
  92. $insertData['user_id'] = $value;
  93. $logId = $dao->insertGetId($insertData);
  94. $queueData['zeroUserId'] = $value;
  95. $queueData['logId'] = $logId;
  96. queue(ZeroUserProfits::class, $queueData, 0, 'zeroProfit');
  97. }
  98. return true;
  99. } catch (\Exception $e) {
  100. return $e->getMessage();
  101. }
  102. }
  103. /**
  104. * @throws DataNotFoundException
  105. * @throws ModelNotFoundException
  106. * @throws DbException
  107. * 执行分红
  108. */
  109. public function profits($param)
  110. {
  111. try {
  112. // 获取0号线用户的所有下级用户
  113. $userIds = $this->getAllUser($param['zeroUserId']);
  114. // 获取分红总额(业绩)
  115. $amount = $param['amount'];
  116. if ($param['amount'] == 0) {
  117. $amount = $this->getAmount($userIds);
  118. }
  119. // 计算分红
  120. $directUids = [];
  121. foreach ($this->parents as $key => $value) {
  122. // 获取初,中,高用户
  123. unset($groupData);
  124. $groupData = $this->getUserByGroup($userIds, $key);
  125. if (empty($groupData)) {
  126. QueueLogger::info('0号线合伙人分红:0号线用户:' . $param['zeroUserId'] . ',暂无' . $key . '级别用户');
  127. continue;
  128. }
  129. // 获取初中高用户直推和团队业绩
  130. $profitDetail = $this->getDirect($groupData, $amount * $value);
  131. $directUids[$key] = $profitDetail;
  132. $this->recordLog($param, $amount, $profitDetail);
  133. }
  134. return true;
  135. } catch (\Exception $e) {
  136. return $e->getMessage();
  137. }
  138. }
  139. /**
  140. * @param $param
  141. * @return array
  142. * 获取要分红的用户ids
  143. */
  144. private function getUserIds($param): array
  145. {
  146. $res = $this->getAllZeroUser($param['zeroUserId']);
  147. return $res;
  148. }
  149. /**
  150. * @return array
  151. * @throws \think\db\exception\DataNotFoundException
  152. * @throws \think\db\exception\DbException
  153. * @throws \think\db\exception\ModelNotFoundException
  154. * 获取所有下级用户
  155. */
  156. private function getAllUser($zeroUid)
  157. {
  158. $sql = "select getUserLevelId($zeroUid) as teamUids";
  159. $teamUids = Db::query($sql)[0]['teamUids'];
  160. // $resArr[$zeroUid] = $teamUids;
  161. return $teamUids;
  162. }
  163. /**
  164. * @return array
  165. * @throws DataNotFoundException
  166. * @throws DbException
  167. * @throws ModelNotFoundException
  168. * 获取全部0号线用户
  169. */
  170. private function getAllZeroUserIds()
  171. {
  172. $zeroUserDao = new ZeroUserLineDao();
  173. $zeroUserIds = $zeroUserDao->selectWhere([
  174. 'is_remove' => ZeroUserEnum::IS_REMOVE_MAP['YES']['code'],
  175. 'status' => ZeroUserEnum::STATUS_MAP['NORMAL']['code']
  176. ])->column('team_uid');
  177. if (empty($zeroUserIds)) {
  178. return [];
  179. }
  180. return $zeroUserIds;
  181. }
  182. /**
  183. * @param $userIds
  184. * @return int
  185. * 获取分红总额
  186. */
  187. private function getAmount($userIds): int
  188. {
  189. return 10000;
  190. }
  191. /**
  192. * @param $uids
  193. * @param $userGroup
  194. * @return array
  195. * @throws \think\db\exception\DataNotFoundException
  196. * @throws \think\db\exception\DbException
  197. * @throws \think\db\exception\ModelNotFoundException
  198. * 获取符合合伙人等级的用户
  199. */
  200. private function getUserByGroup($uid, $userGroup): array
  201. {
  202. $userDao = new UserDao();
  203. return $userDao->getUsersByGroup($uid, $userGroup);
  204. }
  205. /**
  206. * @param $data
  207. * @return array
  208. * @throws DataNotFoundException
  209. * @throws DbException
  210. * @throws ModelNotFoundException
  211. * 获取直推用户业绩
  212. */
  213. private function getDirect($data, $amount): array
  214. {
  215. $money = $amount / 2;
  216. $res = [];
  217. foreach ($data as $key => $value) {
  218. if (empty($value)) {
  219. unset($data[$key]);
  220. continue;
  221. }
  222. // 获取直推
  223. $directUids = $this->userDao->selectWhere(['level_id' => $value])->column('uid');
  224. // 获取直推用户pv
  225. $pvArr = $this->getPv($directUids);
  226. $all = 0;
  227. $all += array_sum($pvArr);
  228. $max = max($pvArr);
  229. $min = $all - $max;
  230. $res[$value]['all'] = $all;
  231. $res[$value]['min'] = $min;
  232. $res[$value]['max'] = $max;
  233. }
  234. $res = $this->countPrice($res, $money);
  235. return $res;
  236. }
  237. /**
  238. * @param $directUids
  239. * @param $pvConfig
  240. * @return array
  241. * 计算pv
  242. */
  243. private function getPv($directUids)
  244. {
  245. $res = [];
  246. foreach ($directUids as $uid) {
  247. // 获取直推用户的团队uid
  248. $teamUids = $this->getTeamUids($uid);
  249. // 去除自己
  250. $teamUids = array_slice($teamUids, 1);
  251. // 获取团队的pv
  252. $pvArr = $this->userDao->selectWhereIn('uid', $teamUids)->column('pv', 'uid');
  253. if (($pvArr)) {
  254. $all = array_sum($pvArr);
  255. $res[$uid] = $all;
  256. }
  257. }
  258. return $res;
  259. }
  260. /**
  261. * @param $uid
  262. * @return mixed
  263. * 获取团队所有人uids [1,2,3]
  264. */
  265. private function getTeamUids($uid): array
  266. {
  267. $sql = "select getUserLevelId($uid) as uids";
  268. return explode(',', Db::query($sql)[0]['uids']);
  269. }
  270. /**
  271. * @param $pvArr
  272. * @param $money
  273. * @return mixed
  274. * 计算分佣
  275. */
  276. private function countPrice($pvArr, $money)
  277. {
  278. $minAll = array_sum(array_column($pvArr, 'min'));
  279. $maxAll = array_sum(array_column($pvArr, 'all'));
  280. foreach ($pvArr as $k => $v) {
  281. $pvArr[$k]['minCount'] = floor($money * ($v['min'] / $minAll) * 100) / 100;
  282. $pvArr[$k]['maxCount'] = floor($money * ($v['all'] / $maxAll) * 100) / 100;
  283. }
  284. return $pvArr;
  285. }
  286. /**
  287. * @param $param
  288. * @param $amount
  289. * @param $detail
  290. * @return string|true
  291. * 记录日志
  292. */
  293. private function recordLog($param, $amount, $detail)
  294. {
  295. $logDao = new ZeroUserProfitDao();
  296. $detailDao = new ZeroUserProfitsDetail();
  297. // 记录分红明细日志,修改主表数据
  298. $updateData = [
  299. 'amount' => $amount,
  300. 'status' => 1
  301. ];
  302. foreach ($detail as $key => $value) {
  303. $insertData = [
  304. 'zero_user_profit_id' => $param['logId'],
  305. 'zero_user_id' => $param['zeroUserId'],
  306. 'user_id' => $key,
  307. 'amount' => $amount,
  308. 'all' => $value['all'],
  309. 'min' => $value['min'],
  310. 'max' => $value['max'],
  311. 'min_count' => $value['minCount'],
  312. 'max_count' => $value['maxCount'],
  313. ];
  314. try {
  315. Db::startTrans();
  316. $logDao->update($param['logId'], $updateData);
  317. $detailDao->create($insertData);
  318. Db::commit();
  319. } catch (\Exception $e) {
  320. Db::rollback();
  321. return $e->getMessage();
  322. }
  323. }
  324. return true;
  325. }
  326. // 执行分红
  327. public function executeProfit($param)
  328. {
  329. $detailDao = new ZeroUserProfitsDetail();
  330. // 获取分红信息
  331. $list = $detailDao->where('zero_user_profit_id', $param['zeroUserProfitId'])->select()->toArray();
  332. if (empty($list)) {
  333. return [];
  334. }
  335. // $userIds = array_column($list, 'user_id');
  336. //
  337. // $userList = User::select($userIds);
  338. // dd($list);
  339. foreach ($list as $key => $value) {
  340. $allAward = bcadd($value['min_count'], $value['max_count']);
  341. //90%给佣金,10给复购金
  342. $yj_90 = floor($allAward * 0.9 * 100) / 100;
  343. $fg_10 = floor($allAward * 0.1 * 100) / 100;
  344. $userModel = $this->userDao->get($value['user_id']);
  345. $userModel->total_amount_old = $userModel->total_amount_old + $yj_90;
  346. $userModel->amount_old = $userModel->amount_old + $yj_90;
  347. $userModel->brokerage_price = $userModel->brokerage_price + $yj_90;
  348. $userModel->fugou = $userModel->fugou + $fg_10;
  349. $userModel->save();
  350. }
  351. die;
  352. // 插入执行分红队列
  353. // foreach ($userList as $value) {
  354. // $value->amount_old = Db::raw('amount_old + 1');
  355. // $value->save();
  356. // }
  357. $update = [];
  358. foreach ($userList as $value) {
  359. $amountOld = $value->amount_old + 1;
  360. $update[] = [
  361. 'uid' => $value->uid,
  362. 'amount_old' => $amountOld
  363. ];
  364. }
  365. $this->userDao->saveAll($update);
  366. die;
  367. }
  368. /**
  369. * @param $userId
  370. * @param $type
  371. * @param $changeStatus
  372. * @param $money
  373. * @param $routineLogOfKeyId
  374. * @param $remark
  375. * @param $isAdmin
  376. * @param $createTime
  377. * @param $alterMoney
  378. * @return int|string
  379. * @author 史晨
  380. * @date 2025/9/18 14:16
  381. * 记录用户余额日志
  382. */
  383. private function recordOldUserLog($userId, $type, $changeStatus, $money, $routineLogOfKeyId, $remark = "", $isAdmin = 1, $alterMoney = 0)
  384. {
  385. $insertData = [
  386. 'user_id' => $userId,
  387. 'type' => $type,
  388. 'change_status' => $changeStatus,
  389. 'money' => $money,
  390. 'routine_log_of_key_id' => $routineLogOfKeyId,
  391. 'remark' => $remark,
  392. 'is_admin' => $isAdmin,
  393. 'create_time' => time(),
  394. 'alter_money' => $alterMoney
  395. ];
  396. $dao = new OldUserLog();
  397. return $dao->insert($insertData);
  398. }
  399. private function recordUserBillLog()
  400. {
  401. $bill = [
  402. 'uid' => $uid,
  403. 'link_id' => 0,//关联订单id
  404. 'pm' => 1,//0:支出,1:获得
  405. 'title' => $name,//账单标题
  406. 'category' => 'now_money',//明细种类
  407. 'type' => 'commission',//明细类型
  408. 'number' => $num,//明细数字
  409. 'balance' => 0,//剩余
  410. 'mark' => $mark,//备注
  411. 'create_time' => date('Y-m-d H:i:s'),//添加时间
  412. 'status' => 1,//0待确定,1有效,-1无效
  413. 'commission_type' => $comm,//佣金类型 1代理费 2 消费佣金 3直推奖√ 4辖区佣金\r\n5 养老金√ 6 广告费
  414. //7 跨店奖励√ 8平台奖励 9渠道商\r\n10 推荐创客收益√ 11分红奖金√ 12代理区域收益√ 13消费循环佣金
  415. //14-推荐代理收益√ 15邀请小区团长升级√ 16大v分享奖√ 17创客合伙人√ 18积分奖励√ 19创客补贴√’
  416. 'order_sn' => 0,//订单号
  417. 'tripartite' => 0,//
  418. 'type_shop' => 0,//0平台1多多进宝2唯品会3苏宁易购4网易考拉5淘宝客6京东联盟7饿了么8线上
  419. 'mer_id' => 0,//商户id
  420. 'source' => 0,//1线下 0线上
  421. 'order_type' => 1,//1自营 2 第三方 订单类型
  422. 'is_red_brokerage' => 0,//1红积分对冲佣金 0正常佣金
  423. 'gzc' => 3,//养老金是否已进入公证处log表0:未进入。1:已进入
  424. 'take_time' => time(),//结算时间
  425. 'district_id' => '',//
  426. 'street_id' => '',//
  427. 'month' => '',//月份
  428. ];
  429. }
  430. private function fugouUserLog()
  431. {
  432. $bill = [
  433. 'uid' => $uid,
  434. 'number' => $num,//数量
  435. 'status' => $status,//复购金状态1-有效 0-失效 -1待确认
  436. 'mark' => "复购金",//备注
  437. 'desc' => "10%复购金",//描述
  438. 'order_id' => $order_id,//订单id
  439. 'surplus' => 0,//剩余
  440. 'order_type' => 11,//关联订单ID
  441. 'type' => $type_inc_des,//复购金类型 :1赠送,2消耗
  442. 'settlement_time' => date('Y-m-d H:i:s'),//添加时间,
  443. 'addtime' => time(),
  444. ];
  445. }
  446. }