Award.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. <?php
  2. /**
  3. * 奖励服务模块
  4. * @author wesmiler
  5. */
  6. namespace app\weixin\service;
  7. use app\weixin\model\AccountLog;
  8. use app\weixin\model\Market;
  9. use app\weixin\model\Member;
  10. use app\weixin\model\UserBalanceLog;
  11. use app\weixin\model\Wechat;
  12. use think\Db;
  13. class Award
  14. {
  15. /**
  16. * 分享邀请用户奖励结算
  17. * @param $userId
  18. * @param array $regUserInfo
  19. * @return array|false
  20. * @throws \think\Exception
  21. * @throws \think\db\exception\DataNotFoundException
  22. * @throws \think\db\exception\ModelNotFoundException
  23. * @throws \think\exception\DbException
  24. * @throws \think\exception\PDOException
  25. */
  26. public static function inviteUser($userId, $regUserInfo = [])
  27. {
  28. $userInfo = Member::where(['id' => $userId, 'user_status' => 1])
  29. ->field('id,user_login,user_nickname,openid,redheart')
  30. ->find();
  31. $inviteOpenid = isset($userInfo['openid']) ? $userInfo['openid'] : '';
  32. $inviteNickname = isset($userInfo['user_nickname']) ? $userInfo['user_nickname'] : '';
  33. $redheart = isset($userInfo['redheart']) ? floatval($userInfo['redheart']) : 0;
  34. if (empty($userInfo)) {
  35. return false;
  36. }
  37. $siteInfo = cmf_get_site_info();
  38. $awardNum = isset($siteInfo['invite_award_redheart']) ? intval($siteInfo['invite_award_redheart']) : 0;
  39. if ($awardNum > 0) {
  40. // 奖励入账
  41. Member::where(['id' => $userId])->update(['redheart' => moneyFormat($redheart + $awardNum), 'updated_at' => date('Y-m-d H:i:s')]);
  42. // 账户明细
  43. $dateTime = date('Y-m-d H:i:s');
  44. $regNickname = isset($regUserInfo['user_nickname']) ? $regUserInfo['user_nickname'] : '';
  45. $regUserId = isset($regUserInfo['id']) ? $regUserInfo['id'] : '';
  46. $logData = [
  47. 'user_id' => $userId,
  48. 'type' => 4,
  49. 'account_type' => 1,
  50. 'change_type' => 1,
  51. 'money' => $awardNum,
  52. 'balance' => $redheart,
  53. 'remark' => "邀请用户[$regUserId],昵称[{$regNickname}]完成注册奖励",
  54. 'created_at' => $dateTime,
  55. ];
  56. db('account_log')->insertGetId($logData);
  57. // 推送消息
  58. $message = [];
  59. $pushInvite = isset($siteInfo['push_invite']) ? $siteInfo['push_invite'] : true;
  60. if ($inviteOpenid && $pushInvite) {
  61. $siteName = isset($siteInfo['site_name']) ? $siteInfo['site_name'] : '本公众号';
  62. $inviteMsg = isset($siteInfo['invite_msg']) ? $siteInfo['invite_msg'] : '';
  63. $match = ['{nickname}', '{inviteNickname}', '{awardNum}', '{datetime}', '{date}'];
  64. $data = [$regNickname, $inviteNickname, $awardNum, $dateTime, date('Y.m.d')];
  65. $inviteMsg = $inviteMsg ? str_replace($match, $data, $inviteMsg) : "尊敬的【{$inviteNickname}】,您在{$dateTime}成功邀请了用户{$regNickname}关注{$siteName},获得奖励{$awardNum}颗爱心!!!";
  66. $message = ['content' => $inviteMsg];
  67. }
  68. return ['openid' => $inviteOpenid, 'message' => $message];
  69. }
  70. return false;
  71. }
  72. /**
  73. * 分销收益奖励结算
  74. * @param $userId 当前奖励用户ID
  75. * @param $sourceUid 当前收益直接来源用户ID
  76. * @param $type 收益类型:对应market表ID
  77. * @param int $money 结算金额:比例分成必传金额
  78. * @return bool
  79. * @throws \think\Exception
  80. * @throws \think\db\exception\DataNotFoundException
  81. * @throws \think\db\exception\ModelNotFoundException
  82. * @throws \think\exception\DbException
  83. */
  84. public static function marketAward($userId, $sourceUid, $type, $money=0)
  85. {
  86. if (empty($type) || $userId <= 0 || ($userId == $sourceUid)) {
  87. return false;
  88. }
  89. // 分销参数配置
  90. $cacheKey = "market:award:u_{$userId}_{$sourceUid}_{$type}";
  91. $logData = ['money' => $money, 'sourceUid' => $sourceUid, 'userId'=> $userId];
  92. // 验证上级用户是否符合奖励条件
  93. $where = ['id' => $userId, 'agent_type' => 1, 'agent_status' => 1];
  94. $field = 'id,openid,user_nickname,parent_id,user_login,shop_type,balance,create_time';
  95. $userInfo = Member::getInfo($where, $field);
  96. $nickname = isset($userInfo['user_nickname']) ? trim($userInfo['user_nickname']) : '';
  97. $userLogin = isset($userInfo['user_login']) ? trim($userInfo['user_login']) : '';
  98. $balance = isset($userInfo['balance']) ? floatval($userInfo['balance']) : 0;
  99. $nickname = $nickname? $nickname : formatName($userLogin);
  100. $logData['userInfo'] = $userInfo;
  101. if (empty($userInfo)) {
  102. $logData['error'] = '审核用户信息不存在';
  103. PRedis::set("{$cacheKey}:error_user", $logData, 7200);
  104. return false;
  105. }
  106. // 按类型获取分销配置
  107. $shopType = isset($userInfo['shop_type'])? $userInfo['shop_type'] : 0;
  108. $marketConfig = Market::where(['id' => $type, 'status' => 1,'shop_type'=> $shopType])->find();
  109. $marketType = isset($marketConfig['type']) ? $marketConfig['type'] : 2;
  110. $logData['config'] = $marketConfig;
  111. if (empty($marketConfig)) {
  112. PRedis::set("{$cacheKey}:error_config", $logData, 7200);
  113. return false;
  114. }
  115. // 收益原始来源用户
  116. $sWhere = ['id' => $sourceUid, 'user_type' => 2];
  117. $sourceInfo = Member::getInfo($sWhere, $field);
  118. $sourceNickname = isset($sourceInfo['user_nickname']) ? $sourceInfo['user_nickname'] : '';
  119. $userLogin = isset($sourceInfo['user_login']) ? trim($sourceInfo['user_login']) : '';
  120. $sourceNickname = $sourceNickname? $sourceNickname : formatName($userLogin);
  121. // 旧用户不结算
  122. $createTime = isset($sourceInfo['create_time'])? $sourceInfo['create_time'] : 0;
  123. if ($createTime && $createTime <= strtotime('2021-02-20')) {
  124. $logData['error'] = '审核用户注册时间不在结算范围内';
  125. PRedis::set("{$cacheKey}:error_user_reg_time", $logData, 7200);
  126. return false;
  127. }
  128. // 一级分销收益结算
  129. $logData['level'] = 1;
  130. $level1Award = isset($marketConfig['level_1']) ? floatval($marketConfig['level_1']) : 0;
  131. $awardMoney = $marketType==1? moneyFormat($level1Award) : moneyFormat($money * ($level1Award / 100),3);
  132. $logData['levelAward'] = $level1Award;
  133. $typeNames = [4=>'完善资料',5=>'完成身份认证',6=>'完成学历认证',7=>'完成工作认证',9=>'报名参加活动'];
  134. $typeName = isset($typeNames[$type])? $typeNames[$type] : ($money? "支付{$money}元,": '消费');
  135. if ($level1Award > 0 && $level1Award <= 100 && $awardMoney > 0) {
  136. // 账户变动
  137. Db::startTrans();
  138. if (Member::where($where)->setInc('balance', $awardMoney)) {
  139. // 写入奖励日志
  140. $levelName = "您邀请的[{$sourceNickname}]用户";
  141. $marketName = isset($marketConfig['name']) ? $marketConfig['name'] : '分销收益';
  142. $logTitle = "{$levelName}{$typeName},获得{$marketName}{$awardMoney}元";
  143. $log = [
  144. 'change' => $awardMoney,
  145. 'type' => $type,
  146. 'level' => 1,
  147. 'change_type' => 1,
  148. 'pay_money' => $awardMoney,
  149. 'user_id' => $userId,
  150. 'source_uid' => $sourceUid,
  151. 'balance' => moneyFormat($balance + $awardMoney),
  152. 'description' => $logTitle,
  153. 'create_time' => time(),
  154. 'status' => 2,
  155. ];
  156. $logData['log'] = $log;
  157. PRedis::set("{$cacheKey}:log", $logData, 7200);
  158. if(UserBalanceLog::insertGetId($log)){
  159. // 账户明细
  160. $accountData = [
  161. 'type' => 4,
  162. 'account_type' => 2,
  163. 'change_type' => 1,
  164. 'user_id' => $userId,
  165. 'money' => $awardMoney,
  166. 'balance' => $balance,
  167. 'created_at' => date('Y-m-d H:i:s'),
  168. 'remark' => $logTitle,
  169. ];
  170. if(AccountLog::insertGetId($accountData)){
  171. // 发送模板消息
  172. $openid = isset($userInfo['openid'])? $userInfo['openid'] : '';
  173. if($openid){
  174. $checkTime = date('Y.m.d H:i');
  175. $remark = "感谢您对拾光的信任,我们一起解救单身青年!点击查看收益明细";
  176. $msgParams = [
  177. 'title' => "您邀请的用户[$sourceNickname]{$typeName}所得的收益已到账!\n\n结算类型:\t{$marketName}",
  178. 'remark' => $remark,
  179. 'type' => 'income',
  180. 'keywords' => [
  181. 'keyword1' => [
  182. 'value' => "{$awardMoney}",
  183. 'color' => '#173177',
  184. ],
  185. 'keyword2' => [
  186. 'value' => $checkTime,
  187. 'color' => '#173177',
  188. ],
  189. ],
  190. 'url' => url('/weixin/market/income', '', '', true),
  191. ];
  192. PRedis::set("{$cacheKey}:message", ['result' => $userInfo, 'params' => $msgParams], 600);
  193. Wechat::sendTplMsg($openid, $msgParams);
  194. }
  195. Db::commit();;
  196. }else{
  197. PRedis::set("{$cacheKey}:account_log", $logData, 7200);
  198. Db::rollback();
  199. }
  200. }else{
  201. PRedis::set("{$cacheKey}:balance_log", $logData, 7200);
  202. Db::rollback();
  203. }
  204. } else {
  205. PRedis::set("{$cacheKey}:update_balance", $logData, 7200);
  206. Db::rollback();
  207. }
  208. } else {
  209. PRedis::set("{$cacheKey}:error_awardMoney", $logData, 7200);
  210. }
  211. // 二级分销收益结算
  212. $logData['level'] = 2;
  213. $logData['userInfo'] = [];
  214. $logData['log'] = [];
  215. $userTwoId = isset($userInfo['parent_id'])? intval($userInfo['parent_id']) : 0;
  216. $cacheKey = "market:award:u_{$userTwoId}_{$sourceUid}_{$type}";
  217. $logData['userTwoId'] = $userTwoId;
  218. if($userTwoId<=0 || $userTwoId == $userId || $userTwoId == $sourceUid){
  219. PRedis::set("{$cacheKey}:market2", $logData, 7200);
  220. return false;
  221. }
  222. $whereTwo = ['id' => $userTwoId, 'agent_type' => 1, 'agent_status' => 1];
  223. $userInfoTwo = Member::getInfo($whereTwo, $field);
  224. $balanceTwo = isset($userInfoTwo['balance']) ? floatval($userInfoTwo['balance']) : 0;
  225. $logData['userInfo'] = $userInfoTwo;
  226. if(empty($userInfoTwo)){
  227. PRedis::set("{$cacheKey}:error_userTwo", $logData, 7200);
  228. return false;
  229. }
  230. $level2Award = isset($marketConfig['level_2']) ? floatval($marketConfig['level_2']) : 0;
  231. $awardMoneyTwo = $marketType==1? moneyFormat($level2Award) : moneyFormat($money * ($level2Award / 100));
  232. $logData['levelAward'] = $level2Award;
  233. if ($level2Award > 0 && $level2Award <= 100 && $awardMoneyTwo > 0) {
  234. // 账户变动
  235. Db::startTrans();
  236. if (Member::where($whereTwo)->setInc('balance', $awardMoneyTwo)) {
  237. // 写入奖励日志
  238. $levelName = "您的下级[{$nickname}:]邀请的[{$sourceNickname}]用户";
  239. $marketName = isset($marketConfig['name']) ? $marketConfig['name'] : '分销收益';
  240. $logTitle = "{$levelName}{$typeName},获得{$marketName}{$awardMoneyTwo}元";
  241. $log = [
  242. 'change' => $awardMoneyTwo,
  243. 'type' => $type,
  244. 'level' => 2,
  245. 'change_type' => 1,
  246. 'pay_money' => $awardMoneyTwo,
  247. 'user_id' => $userTwoId,
  248. 'source_uid' => $userId,
  249. 'balance' => moneyFormat($balanceTwo + $awardMoneyTwo),
  250. 'description' => $logTitle,
  251. 'create_time' => time(),
  252. 'status' => 2,
  253. ];
  254. $logData['log'] = $log;
  255. PRedis::set("{$cacheKey}:log", $logData, 7200);
  256. if(UserBalanceLog::insertGetId($log)){
  257. // 账户明细
  258. $accountData = [
  259. 'type' => 4,
  260. 'account_type' => 2,
  261. 'change_type' => 1,
  262. 'user_id' => $userTwoId,
  263. 'money' => $awardMoneyTwo,
  264. 'balance' => $balanceTwo,
  265. 'created_at' => date('Y-m-d H:i:s'),
  266. 'remark' => $logTitle,
  267. ];
  268. if(AccountLog::insertGetId($accountData)){
  269. // 发送模板消息
  270. $openid = isset($userInfoTwo['openid'])? $userInfoTwo['openid'] : '';
  271. if($openid){
  272. $checkTime = date('Y.m.d H:i');
  273. $remark = "感谢您对拾光的信任,我们一起解救单身青年!点击查看收益明细";
  274. $msgParams = [
  275. 'title' => "您的下级[$nickname]邀请的用户[{$sourceNickname}]{$typeName}所得的收益已到账!\n\n结算类型:\t{$marketName}",
  276. 'remark' => $remark,
  277. 'type' => 'income',
  278. 'keywords' => [
  279. 'keyword1' => [
  280. 'value' => "{$awardMoneyTwo}",
  281. 'color' => '#173177',
  282. ],
  283. 'keyword2' => [
  284. 'value' => $checkTime,
  285. 'color' => '#173177',
  286. ],
  287. ],
  288. 'url' => url('/weixin/market/income', '', '', true),
  289. ];
  290. PRedis::set("{$cacheKey}:message", ['result' => $userInfoTwo, 'params' => $msgParams], 600);
  291. Wechat::sendTplMsg($openid, $msgParams);
  292. }
  293. Db::commit();
  294. }else{
  295. PRedis::set("{$cacheKey}:account_log", $logData, 7200);
  296. Db::rollback();
  297. return false;
  298. }
  299. }else{
  300. PRedis::set("{$cacheKey}:balance_log", $logData, 7200);
  301. Db::rollback();
  302. return false;
  303. }
  304. } else {
  305. PRedis::set("{$cacheKey}:update_balance", $logData, 7200);
  306. Db::rollback();
  307. return false;
  308. }
  309. } else {
  310. PRedis::set("{$cacheKey}:error_awardMoney", $logData, 7200);
  311. return false;
  312. }
  313. return true;
  314. }
  315. }