Award.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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. $marketConfig = Market::where(['id' => $type, 'status' => 1])->find();
  93. $marketType = isset($marketConfig['type']) ? $marketConfig['type'] : 2;
  94. $logData['config'] = $marketConfig;
  95. if (empty($marketConfig)) {
  96. PRedis::set("{$cacheKey}:error_config", $logData, 7200);
  97. return false;
  98. }
  99. // 验证上级用户是否符合奖励条件
  100. $where = ['id' => $userId, 'agent_type' => 1, 'agent_status' => 1];
  101. $field = 'id,openid,user_nickname,parent_id,user_login,balance,create_time';
  102. $userInfo = Member::getInfo($where, $field);
  103. $nickname = isset($userInfo['user_nickname']) ? trim($userInfo['user_nickname']) : '';
  104. $userLogin = isset($userInfo['user_login']) ? trim($userInfo['user_login']) : '';
  105. $balance = isset($userInfo['balance']) ? floatval($userInfo['balance']) : 0;
  106. $nickname = $nickname? $nickname : formatName($userLogin);
  107. $logData['userInfo'] = $userInfo;
  108. if (empty($userInfo)) {
  109. $logData['error'] = '审核用户信息不存在';
  110. PRedis::set("{$cacheKey}:error_user", $logData, 7200);
  111. return false;
  112. }
  113. // 收益原始来源用户
  114. $sWhere = ['id' => $sourceUid, 'user_type' => 2];
  115. $sourceInfo = Member::getInfo($sWhere, $field);
  116. $sourceNickname = isset($sourceInfo['user_nickname']) ? $sourceInfo['user_nickname'] : '';
  117. $userLogin = isset($sourceInfo['user_login']) ? trim($sourceInfo['user_login']) : '';
  118. $sourceNickname = $sourceNickname? $sourceNickname : formatName($userLogin);
  119. // 旧用户不结算
  120. $createTime = isset($sourceInfo['create_time'])? $sourceInfo['create_time'] : 0;
  121. if ($createTime && $createTime <= strtotime('2021-02-23')) {
  122. $logData['error'] = '注册时间不在结算范围内';
  123. PRedis::set("{$cacheKey}:error_user_reg_time", $logData, 7200);
  124. return false;
  125. }
  126. // 一级分销收益结算
  127. $logData['level'] = 1;
  128. $level1Award = isset($marketConfig['level_1']) ? floatval($marketConfig['level_1']) : 0;
  129. $awardMoney = $marketType==1? moneyFormat($level1Award) : moneyFormat($money * ($level1Award / 100),3);
  130. $logData['levelAward'] = $level1Award;
  131. $typeNames = [4=>'完善资料',5=>'完成身份认证',6=>'完成学历认证',7=>'完成工作认证',9=>'报名参加活动'];
  132. $typeName = isset($typeNames[$type])? $typeNames[$type] : ($money? "支付{$money}元,": '消费');
  133. if ($level1Award > 0 && $level1Award <= 100 && $awardMoney > 0) {
  134. // 账户变动
  135. Db::startTrans();
  136. if (Member::where($where)->setInc('balance', $awardMoney)) {
  137. // 写入奖励日志
  138. $levelName = "您邀请的[{$sourceNickname}]用户";
  139. $marketName = isset($marketConfig['name']) ? $marketConfig['name'] : '分销收益';
  140. $logTitle = "{$levelName}{$typeName},获得{$marketName}{$awardMoney}元";
  141. $log = [
  142. 'change' => $awardMoney,
  143. 'type' => $type,
  144. 'level' => 1,
  145. 'change_type' => 1,
  146. 'pay_money' => $awardMoney,
  147. 'user_id' => $userId,
  148. 'source_uid' => $sourceUid,
  149. 'balance' => moneyFormat($balance + $awardMoney),
  150. 'description' => $logTitle,
  151. 'create_time' => time(),
  152. 'status' => 1,
  153. ];
  154. $logData['log'] = $log;
  155. PRedis::set("{$cacheKey}:log", $logData, 7200);
  156. if(UserBalanceLog::insertGetId($log)){
  157. // 账户明细
  158. $accountData = [
  159. 'type' => 4,
  160. 'account_type' => 2,
  161. 'change_type' => 1,
  162. 'user_id' => $userId,
  163. 'money' => $awardMoney,
  164. 'balance' => $balance,
  165. 'created_at' => date('Y-m-d H:i:s'),
  166. 'remark' => $logTitle,
  167. ];
  168. if(AccountLog::insertGetId($accountData)){
  169. // 发送模板消息
  170. $openid = isset($userInfo['openid'])? $userInfo['openid'] : '';
  171. if($openid){
  172. $checkTime = date('Y.m.d H:i');
  173. $remark = "感谢您对拾光的信任,我们一起解救单身青年!点击查看收益明细";
  174. $msgParams = [
  175. 'title' => "您邀请的用户[$sourceNickname]{$typeName}所得的收益已到账!\n\n结算类型:\t{$marketName}",
  176. 'remark' => $remark,
  177. 'type' => 'income',
  178. 'keywords' => [
  179. 'keyword1' => [
  180. 'value' => "{$awardMoney}",
  181. 'color' => '#173177',
  182. ],
  183. 'keyword2' => [
  184. 'value' => $checkTime,
  185. 'color' => '#173177',
  186. ],
  187. ],
  188. 'url' => url('/weixin/market/income', '', '', true),
  189. ];
  190. PRedis::set("{$cacheKey}:message", ['result' => $userInfo, 'params' => $msgParams], 600);
  191. Wechat::sendTplMsg($openid, $msgParams);
  192. }
  193. Db::commit();;
  194. }else{
  195. PRedis::set("{$cacheKey}:account_log", $logData, 7200);
  196. Db::rollback();
  197. }
  198. }else{
  199. PRedis::set("{$cacheKey}:balance_log", $logData, 7200);
  200. Db::rollback();
  201. }
  202. } else {
  203. PRedis::set("{$cacheKey}:update_balance", $logData, 7200);
  204. Db::rollback();
  205. }
  206. } else {
  207. PRedis::set("{$cacheKey}:error_awardMoney", $logData, 7200);
  208. }
  209. // 二级分销收益结算
  210. $logData['level'] = 2;
  211. $userTwoId = isset($userInfo['parent_id'])? intval($userInfo['parent_id']) : 0;
  212. $cacheKey = "market:award:u_{$userTwoId}_{$sourceUid}_{$type}";
  213. if($userTwoId<=0 || $userTwoId == $userId || $userTwoId == $sourceUid){
  214. PRedis::set("{$cacheKey}:market2", $logData, 7200);
  215. return false;
  216. }
  217. $whereTwo = ['id' => $userTwoId, 'agent_type' => 1, 'agent_status' => 1];
  218. $userInfoTwo = Member::getInfo($whereTwo, $field);
  219. $balanceTwo = isset($userInfoTwo['balance']) ? floatval($userInfoTwo['balance']) : 0;
  220. $logData['userInfo'] = $userInfoTwo;
  221. if(empty($userInfoTwo)){
  222. PRedis::set("{$cacheKey}:error_userTwo", $logData, 7200);
  223. return false;
  224. }
  225. $level2Award = isset($marketConfig['level_2']) ? floatval($marketConfig['level_2']) : 0;
  226. $awardMoneyTwo = $marketType==1? moneyFormat($level2Award) : moneyFormat($money * ($level2Award / 100));
  227. $logData['levelAward'] = $level2Award;
  228. if ($level2Award > 0 && $level2Award <= 100 && $awardMoneyTwo > 0) {
  229. // 账户变动
  230. Db::startTrans();
  231. if (Member::where($whereTwo)->setInc('balance', $awardMoneyTwo)) {
  232. // 写入奖励日志
  233. $levelName = "您的下级[{$nickname}:]邀请的[{$sourceNickname}]用户";
  234. $marketName = isset($marketConfig['name']) ? $marketConfig['name'] : '分销收益';
  235. $logTitle = "{$levelName}{$typeName},获得{$marketName}{$awardMoneyTwo}元";
  236. $log = [
  237. 'change' => $awardMoneyTwo,
  238. 'type' => $type,
  239. 'level' => 2,
  240. 'change_type' => 1,
  241. 'pay_money' => $awardMoneyTwo,
  242. 'user_id' => $userTwoId,
  243. 'source_uid' => $userId,
  244. 'balance' => moneyFormat($balanceTwo + $awardMoneyTwo),
  245. 'description' => $logTitle,
  246. 'create_time' => time(),
  247. 'status' => 1,
  248. ];
  249. $logData['log'] = $log;
  250. PRedis::set("{$cacheKey}:log", $logData, 7200);
  251. if(UserBalanceLog::insertGetId($log)){
  252. // 账户明细
  253. $accountData = [
  254. 'type' => 4,
  255. 'account_type' => 2,
  256. 'change_type' => 1,
  257. 'user_id' => $userTwoId,
  258. 'money' => $awardMoneyTwo,
  259. 'balance' => $balanceTwo,
  260. 'created_at' => date('Y-m-d H:i:s'),
  261. 'remark' => $logTitle,
  262. ];
  263. if(AccountLog::insertGetId($accountData)){
  264. // 发送模板消息
  265. $openid = isset($userInfoTwo['openid'])? $userInfoTwo['openid'] : '';
  266. if($openid){
  267. $checkTime = date('Y.m.d H:i');
  268. $remark = "感谢您对拾光的信任,我们一起解救单身青年!点击查看收益明细";
  269. $msgParams = [
  270. 'title' => "您的下级[$nickname]邀请的用户[{$sourceNickname}]{$typeName}所得的收益已到账!\n\n结算类型:\t{$marketName}",
  271. 'remark' => $remark,
  272. 'type' => 'income',
  273. 'keywords' => [
  274. 'keyword1' => [
  275. 'value' => "{$awardMoneyTwo}",
  276. 'color' => '#173177',
  277. ],
  278. 'keyword2' => [
  279. 'value' => $checkTime,
  280. 'color' => '#173177',
  281. ],
  282. ],
  283. 'url' => url('/weixin/market/income', '', '', true),
  284. ];
  285. PRedis::set("{$cacheKey}:message", ['result' => $userInfoTwo, 'params' => $msgParams], 600);
  286. Wechat::sendTplMsg($openid, $msgParams);
  287. }
  288. Db::commit();
  289. }else{
  290. PRedis::set("{$cacheKey}:account_log", $logData, 7200);
  291. Db::rollback();
  292. return false;
  293. }
  294. }else{
  295. PRedis::set("{$cacheKey}:balance_log", $logData, 7200);
  296. Db::rollback();
  297. return false;
  298. }
  299. } else {
  300. PRedis::set("{$cacheKey}:update_balance", $logData, 7200);
  301. Db::rollback();
  302. return false;
  303. }
  304. } else {
  305. PRedis::set("{$cacheKey}:error_awardMoney", $logData, 7200);
  306. return false;
  307. }
  308. return true;
  309. }
  310. }