Payment.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. <?php
  2. namespace app\weixin\model;
  3. use app\weixin\model\Member as MemberModel;
  4. use app\weixin\service\Award;
  5. use app\weixin\service\PRedis;
  6. use think\Db;
  7. class Payment
  8. {
  9. /**
  10. * 返回给微信
  11. */
  12. public static function rebackOk(){
  13. echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
  14. exit;
  15. }
  16. /**
  17. * 处理订单
  18. * @param $outTradeNo 订单号
  19. * @param array $notifyData 回调数据
  20. * @return bool
  21. */
  22. public static function catchOrder($outTradeNo, $notifyData=[]){
  23. Db::startTrans();
  24. // 更新订单支付状态信息
  25. $payMoney = isset($notifyData['total_fee'])? moneyFormat($notifyData['total_fee']): 0;
  26. $orderPayMoney = moneyFormat($payMoney/100);
  27. $orderInfo = Books::getInfo(['order_sn'=> $outTradeNo]);
  28. PRedis::set('orders:books:info_'.$outTradeNo, ['order'=> $orderInfo,'notify'=> $notifyData], 600);
  29. $userId = isset($orderInfo['uid'])? intval($orderInfo['uid']) : 0;
  30. if(empty($userId)){
  31. return false;
  32. }
  33. $bookAt = time();
  34. $updateData = [
  35. 'pay_type'=> isset($notifyData['pay_type'])? intval($notifyData['pay_type']) : 1,
  36. 'transaction_id'=> isset($notifyData['transaction_id'])? $notifyData['transaction_id'] : '',
  37. 'status'=> 2,
  38. 'book_at'=> date('Y-m-d H:i:s', $bookAt),
  39. ];
  40. PRedis::set('orders:books:update_'.$outTradeNo, ['order'=> $updateData,'notify'=> $notifyData], 600);
  41. $res = Books::saveData(['order_sn'=> $outTradeNo], $updateData);
  42. if(!$res){
  43. PRedis::set('orders:books:error_'.$outTradeNo, ['order'=> $updateData,'notify'=> $notifyData,'error'=> '更新订单支付数据失败'], 600);
  44. Db::rollback();
  45. return false;
  46. }
  47. // 账户明细
  48. $memberInfo = Member::getInfo(['id'=> $userId],'id,openid,redheart,user_nickname,real_name');
  49. $redheart = isset($memberInfo['redheart'])? intval($memberInfo['redheart']) : 0;
  50. $accountData = [
  51. 'type' => 2,
  52. 'account_type' => 4,
  53. 'change_type' => 2,
  54. 'user_id' => $userId,
  55. 'money' => moneyFormat($orderPayMoney, 2),
  56. 'balance' => $redheart,
  57. 'created_at' => date('Y-m-d H:i:s'),
  58. 'remark' => "微信支付活动报名:单号[{$outTradeNo}],活动:{$orderInfo['aid']},金额" . $orderPayMoney,
  59. ];
  60. PRedis::set('payments:books:account_' . $outTradeNo, ['notify' => $notifyData, 'log' => $accountData,'user'=> $memberInfo], 600);
  61. AccountLog::insertGetId($accountData);
  62. Db::commit();
  63. // 发送报名提交成功消息
  64. $openid = isset($memberInfo['openid']) ? $memberInfo['openid'] : '';
  65. $nickname = isset($memberInfo['user_nickname']) ? $memberInfo['user_nickname'] : '';
  66. $bookNo = isset($orderInfo['book_num'])? trim($orderInfo['book_num']) : '无';
  67. $money = isset($orderInfo['money'])? floatval($orderInfo['money']) : 0;
  68. $credit = isset($orderInfo['credit'])? floatval($orderInfo['credit']) : 0;
  69. $bookStatus = Books::where(['order_sn'=> $outTradeNo])->value('status');
  70. if($bookStatus != 2){
  71. return false;
  72. }
  73. if($openid) {
  74. $aid = isset($orderInfo['aid'])? intval($orderInfo['aid']) : 0;
  75. $activityInfo = Activity::where(['id'=> $aid])
  76. ->field('id,starttime,title,address')
  77. ->find();
  78. $title = isset($activityInfo['title'])? trim($activityInfo['title']) : '无';
  79. $address = isset($activityInfo['address'])? trim($activityInfo['address']) : '无';
  80. $bookAt = $bookAt? date('Y.m.d H:i', $bookAt) : date('Y.m.d H:i');
  81. $params = [
  82. 'title' => "我们已经收到您的报名,稍后会进行审核,请留意后续的通知哦!\n\n姓名:\t{$nickname}(昵称)\n\n支付单号:\t{$outTradeNo}\n\n支付金额:\t{$orderPayMoney}",
  83. 'remark' => "转发积姻缘,把活动分享给身边的朋友,一起来脱单哦!",
  84. 'type' => 'book',
  85. 'keywords' => [
  86. 'keyword1' => [
  87. 'value' => $title,
  88. 'color' => '#173177',
  89. ],
  90. 'keyword2' => [
  91. 'value' => $bookAt,
  92. 'color' => '#173177',
  93. ],
  94. 'keyword3' => [
  95. 'value' => '待审核',
  96. 'color' => '#173177',
  97. ],
  98. 'keyword4' => [
  99. 'value' => "活动费用{$money}元,活动守时金{$credit}元。",
  100. 'color' => '#173177',
  101. ],
  102. ],
  103. 'url' => url('/weixin/activity/bookdetail?id='.$aid, '', '', true),
  104. ];
  105. PRedis::set('payments:books:message_' . $outTradeNo, ['notify' => $notifyData, 'params' => $params], 600);
  106. Wechat::sendTplMsg($openid, $params);
  107. }
  108. return true;
  109. }
  110. /**
  111. * 充值结果处理
  112. * @param $outTradeNo
  113. * @param array $notifyData
  114. * @return bool
  115. * @throws \think\Exception
  116. * @throws \think\db\exception\DataNotFoundException
  117. * @throws \think\db\exception\ModelNotFoundException
  118. * @throws \think\exception\DbException
  119. * @throws \think\exception\PDOException
  120. */
  121. public static function catchRechargeOrder($outTradeNo, $notifyData=[]){
  122. try {
  123. db()->startTrans();
  124. // 更新订单支付状态信息
  125. $payMoney = isset($notifyData['total_fee']) ? moneyFormat($notifyData['total_fee']) : 0;
  126. $orderPayMoney = moneyFormat($payMoney / 100);
  127. $orderInfo = db('user_recharge_log')
  128. ->where(['order_sn' => $outTradeNo])
  129. ->field('money,pay_money,give_num,user_id,source_id,order_sn')
  130. ->find();
  131. $orderSn = isset($orderInfo['order_sn']) ? $orderInfo['order_sn'] : '';
  132. $userId = isset($orderInfo['user_id']) ? $orderInfo['user_id'] : 0;
  133. $num = isset($orderInfo['money']) ? $orderInfo['money'] : 0;
  134. $giveNum = isset($orderInfo['give_num']) ? $orderInfo['give_num'] : 0;
  135. $updateData = [
  136. 'pay_money' => $orderPayMoney,
  137. 'transaction_id' => isset($notifyData['transaction_id']) ? $notifyData['transaction_id'] : '',
  138. 'status' => 2,
  139. 'pay_at' => date('Y-m-d H:i:s'),
  140. ];
  141. PRedis::set('payments:redheart:catchOrder_' . $outTradeNo, ['notify' => $notifyData, 'update' => $updateData], 600);
  142. $res = db('user_recharge_log')->where(['order_sn' => $outTradeNo])->update($updateData);
  143. if (!$res) {
  144. PRedis::set('payments:redheart:updateError_' . $outTradeNo, ['notify' => $notifyData, 'update' => $updateData], 600);
  145. db()->rollback();
  146. return false;
  147. }
  148. // 更新账户
  149. if ($userId && $num > 0) {
  150. $memberInfo = Member::where(['id' => $userId])->field('openid,redheart')->find();
  151. $redheart = isset($memberInfo['redheart']) ? intval($memberInfo['redheart']) : 0;
  152. $data = ['updated_at' => date('Y-m-d H:i:s'), 'redheart' => intval($redheart + intval($num+$giveNum))];
  153. PRedis::set('payments:redheart:update_account' . $outTradeNo, ['notify' => $notifyData, 'update' => $data], 600);
  154. if (!Member::where(['id' => $userId])->update($data)) {
  155. db()->rollback();
  156. return false;
  157. }
  158. $accountData = [
  159. 'type' => 1,
  160. 'account_type' => 1,
  161. 'change_type' => 1,
  162. 'user_id' => $userId,
  163. 'money' => intval($num+$giveNum),
  164. 'balance' => $redheart,
  165. 'created_at' => date('Y-m-d H:i:s'),
  166. 'remark' => "微信支付爱心充值:单号[{$outTradeNo}],数量{$num}".($giveNum? ",赠送{$giveNum}":'').",金额" . $orderPayMoney,
  167. ];
  168. PRedis::set('payments:redheart:account_' . $outTradeNo, ['notify' => $notifyData, 'log' => $accountData,'user'=> $memberInfo], 600);
  169. db('account_log')->insertGetId($accountData);
  170. // 发送充值成功消息
  171. $openid = isset($memberInfo['openid']) ? $memberInfo['openid'] : '';
  172. if($openid) {
  173. $params = [
  174. 'title' => "恭喜您充值成功",
  175. 'remark' => "感谢您的使用,点击详情查看充值明细",
  176. 'type' => 'redheart',
  177. 'keywords' => [
  178. 'keyword1' => [
  179. 'value' => moneyFormat($orderPayMoney, 2),
  180. 'color' => '#173177',
  181. ],
  182. 'keyword2' => [
  183. 'value' => date('Y.m.d H:i'),
  184. 'color' => '#173177',
  185. ],
  186. 'keyword3' => [
  187. 'value' => '微信支付',
  188. 'color' => '#173177',
  189. ],
  190. ],
  191. 'url' => url('/weixin/account/index', '', '', true),
  192. ];
  193. PRedis::set('payments:redheart:message_' . $outTradeNo, ['notify' => $notifyData, 'params' => $params], 600);
  194. Wechat::sendTplMsg($openid, $params);
  195. }
  196. }
  197. // 操作日志
  198. UserLog::saveLog(['user_id' => $userId, 'type' => 2, 'content' => "充值爱心:{$num}个"]);
  199. db()->commit();
  200. // 分销收益结算
  201. $inviteInfo = MemberModel::getInviteInfo($userId);
  202. $inviteId = isset($inviteInfo['invite_id'])? $inviteInfo['invite_id'] : 0;
  203. if($inviteInfo && $inviteId>0){
  204. PRedis::set('markets:recharge:entry' . $outTradeNo, ['notify' => $notifyData, 'inviteInfo'=> $inviteInfo, 'params' => $params], 7200);
  205. Award::marketAward($inviteId, $userId, 8, $orderPayMoney);
  206. }
  207. return true;
  208. } catch (\Exception $exception){
  209. PRedis::set('payments:redheart:error:'.$outTradeNo, $exception, 600);
  210. db()->rollback();
  211. return false;
  212. }
  213. }
  214. /**
  215. * 微信支付
  216. * @param $orderId 订单ID
  217. * @param $orderInfo 订单信息
  218. * @param array $userInfo 用户信息
  219. * @return array
  220. */
  221. public static function wechatPay($orderId, $orderInfo, $userInfo=[]){
  222. $prepayId = isset($orderInfo['prepay_id']) ? trim($orderInfo['prepay_id']) : '';
  223. $orderStatus = isset($orderInfo['status']) ? trim($orderInfo['status']) : 0;
  224. $userId = isset($userInfo['id']) ? intval($userInfo['id']) : 0;
  225. if($orderStatus != 1){
  226. return 5007;
  227. }
  228. $orderSn = isset($orderInfo['order_sn'])? $orderInfo['order_sn'] : '';
  229. if(empty($orderSn)){
  230. return 1012;
  231. }
  232. $orderSn = isset($orderInfo['order_sn'])? $orderInfo['order_sn'] : '';
  233. if(empty($orderSn)){
  234. showJson(1004, 1012);
  235. }
  236. // 支付金额
  237. $orderMoney = isset($orderInfo['money']) ? moneyFormat($orderInfo['money']) : 0.00;
  238. $credit = isset($orderInfo['credit']) ? moneyFormat($orderInfo['credit']) : 0.00;
  239. $orderAmount = moneyFormat($orderMoney + $credit);
  240. if ($orderMoney <= 0) {
  241. return 5008;
  242. }
  243. if ($prepayId && $orderStatus == 1) {
  244. // 查询订单状态
  245. $queryResult = Wechat::queryOrder($orderSn);
  246. PRedis::set('payments:books:queryOrder_'.$orderSn, $queryResult, 600);
  247. if ($queryResult && Payment::catchOrder($orderInfo['order_sn'], $queryResult)) {
  248. return 5009;
  249. } else {
  250. $orderSn = makeTradeNo('BK', $userId);
  251. $saveData = ['order_sn' => $orderSn, 'remark' => '订单重新发起支付,原单号:' . $orderInfo['order_sn']];
  252. PRedis::set('payments:books:makeSn_'.$orderInfo['order_sn'], $saveData);
  253. Books::saveData(['id' => $orderId], $saveData);
  254. }
  255. }
  256. // 获取OPENID
  257. $openid = session('openid');
  258. if (empty($openid)) {
  259. $openid = Member::where(['id' => $userId])->value('openid');
  260. }
  261. $order = [
  262. 'orderNo' => $orderSn,
  263. 'amount' => $orderAmount,
  264. 'openid' => $openid,
  265. 'body' => '报名订单支付',
  266. ];
  267. $params = Wechat::jsapiUnifiedorder($order);
  268. PRedis::set('payments:books:payParams_'.$orderSn,['order'=> $order, 'params'=> $params,'date'=> date('Y-m-d H:i:s')], 600);
  269. $code = isset($params['code']) ? $params['code'] : '';
  270. if ($code == 'error') {
  271. return $params['message'];
  272. }
  273. // 更新订单参数
  274. $prepayId = isset($params['prepay_id'])? $params['prepay_id'] : '';
  275. Books::saveData(['id' => $orderId], ['prepay_id' => $prepayId]);
  276. unset($params['prepay_id']);
  277. return $params;
  278. }
  279. /**
  280. * VIP套餐支付处理
  281. * @param $outTradeNo
  282. * @param $notifyData
  283. * @param $taskNo
  284. * @return bool|string
  285. * @throws \think\Exception
  286. * @throws \think\db\exception\DataNotFoundException
  287. * @throws \think\db\exception\ModelNotFoundException
  288. * @throws \think\exception\DbException
  289. * @throws \think\exception\PDOException
  290. */
  291. public static function catchVip($outTradeNo, $notifyData, $taskNo){
  292. // 验证订单是否存在
  293. $where = ['order_sn' => $outTradeNo, 'type'=> 4];
  294. $orderInfo = db('user_recharge_log')
  295. ->field('money,pay_money,user_id,order_sn,status')
  296. ->where($where)
  297. ->find();
  298. if(empty($orderInfo)){
  299. PRedis::set('payments:vip:errorMoney_'.$taskNo, ['result'=> $notifyData, 'error'=> $outTradeNo.'订单不存在'], 600);
  300. return false;
  301. }
  302. // 订单已处理
  303. PRedis::set('payments:vip:order_'.$taskNo, ['result'=> $notifyData, 'order'=> $orderInfo], 3600);
  304. $orderStatus = isset($orderInfo['status']) ? intval($orderInfo['status']) : 0;
  305. // 验证订单状态是否可处理
  306. if ($orderStatus != 1) {
  307. db('user_recharge_log')->where($where)->update(['remark'=> '订单已处理']);
  308. Payment::rebackOk();
  309. return true;
  310. }
  311. // 验证订单金额是否正确
  312. $payDebug = config('weixin.payDebug');
  313. $payMoney = isset($notifyData['total_fee']) ? moneyFormat($notifyData['total_fee']) : 0;
  314. $orderMoney = isset($orderInfo['pay_money']) ? moneyFormat($orderInfo['pay_money']) : 0.00;
  315. if (!$payDebug && $orderMoney * 100 != $payMoney) {
  316. $error = ['remark'=> "订单金额错误:\n支付金额:" . $payMoney . "\n订单金额:" . $orderMoney];
  317. PRedis::set('payments:vip:errorMoney_'.$taskNo, ['result'=> $notifyData, 'order'=> $orderInfo,'error'=> $error], 600);
  318. db('user_recharge_log')->where($where)->update($error);
  319. return '支付金额错误';
  320. }
  321. try {
  322. db()->startTrans();
  323. // 更新订单支付状态信息
  324. $payMoney = isset($notifyData['total_fee']) ? moneyFormat($notifyData['total_fee']) : 0;
  325. $orderPayMoney = moneyFormat($payMoney / 100);
  326. $userId = isset($orderInfo['user_id']) ? $orderInfo['user_id'] : 0;
  327. $num = isset($orderInfo['money']) ? $orderInfo['money'] : 0;
  328. $updateData = [
  329. 'pay_money' => $orderPayMoney,
  330. 'transaction_id' => isset($notifyData['transaction_id']) ? $notifyData['transaction_id'] : '',
  331. 'status' => 2,
  332. 'pay_at' => date('Y-m-d H:i:s'),
  333. ];
  334. PRedis::set('payments:vip:catchOrder_' . $outTradeNo, ['notify' => $notifyData, 'update' => $updateData], 3600);
  335. $res = db('user_recharge_log')->where($where)->update($updateData);
  336. if (!$res) {
  337. PRedis::set('payments:vip:updateError_' . $outTradeNo, ['notify' => $notifyData, 'update' => $updateData], 3600);
  338. db()->rollback();
  339. return false;
  340. }
  341. // 更新账户
  342. if ($userId && $num > 0) {
  343. $dateTime = strtotime(date('Y-m-d 00:00:00'));
  344. $memberInfo = Member::where(['id' => $userId])->field('openid,vip_auth,user_nickname,vip_expire')->find();
  345. $vipAuth = isset($memberInfo['vip_auth']) ? intval($memberInfo['vip_auth']) : 0;
  346. $vipExpire = isset($memberInfo['vip_expire']) && !empty($memberInfo['vip_expire'])? intval($memberInfo['vip_expire']) : 0;
  347. $newVipExpire = $vipExpire>$dateTime && $vipAuth? $vipExpire + $num*30*24*3600+86400 : $dateTime+$num*30*24*3600+86400;
  348. if($newVipExpire - time() > 200*24*3600){
  349. $siteInfo = cmf_get_site_info();
  350. $customOpenid = isset($siteInfo['custom_openid'])? trim($siteInfo['custom_openid']) : '';
  351. if($customOpenid){
  352. $params = [
  353. 'title' => '用户'.$memberInfo['user_nickname']."购买VIP成功,由于到期时间超过6个月,请留意\n\n购买时长:\t{$num}个月\n续费前时间:\t".date('Y.m.d',$vipExpire)."\n"."到期时间:\t".date('Y.m.d',$newVipExpire)."\n",
  354. 'remark' => "请到后台留意查看该用户购买或续费是否正常",
  355. 'type' => 'pay',
  356. 'keywords' => [
  357. 'keyword1' => [
  358. 'value' => moneyFormat($orderPayMoney, 2),
  359. 'color' => '#173177',
  360. ],
  361. 'keyword2' => [
  362. 'value' => date('Y.m.d H:i'),
  363. 'color' => '#173177',
  364. ],
  365. ],
  366. 'url' => '',
  367. ];
  368. PRedis::set('payments:custom:message_' . $outTradeNo, ['notify' => $notifyData, 'params' => $params], 3600);
  369. Wechat::sendTplMsg($customOpenid, $params);
  370. }
  371. }
  372. $data = ['vip_time'=> date('Y-m-d H:i:s'), 'vip_auth'=> 1, 'vip_expire' => $newVipExpire];
  373. PRedis::set("accounts:vipUpdate:{$userId}_".$outTradeNo, ['data'=> $data,'info'=> $memberInfo,'new'=> $newVipExpire], 20 * 24 * 3600);
  374. if (!Member::where(['id' => $userId])->update($data)) {
  375. db()->rollback();
  376. return false;
  377. }
  378. $num = intval($num);
  379. $accountData = [
  380. 'type' => 6,
  381. 'account_type' => 4,
  382. 'change_type' => 1,
  383. 'user_id' => $userId,
  384. 'money' => $orderPayMoney,
  385. 'balance' => 0,
  386. 'created_at' => date('Y-m-d H:i:s'),
  387. 'remark' => "购买VIP:单号[{$outTradeNo}],时长{$num}个月,支付金额" . $orderPayMoney,
  388. ];
  389. PRedis::set('payments:vip:account_' . $outTradeNo, ['notify' => $notifyData, 'log' => $accountData,'user'=> $memberInfo], 600);
  390. db('account_log')->insertGetId($accountData);
  391. // 发送充值成功消息
  392. $openid = isset($memberInfo['openid']) ? $memberInfo['openid'] : '';
  393. if($openid) {
  394. $monthTxt = $num ==6? '半年' : ($num == 12? '一年' : $num.'个月');
  395. $params = [
  396. 'title' => "恭喜您购买{$monthTxt}VIP成功\n\n到期时间:\t".date('Y.m.d',$newVipExpire).'到期',
  397. 'remark' => "感谢您的使用,点击详情查看购买明细",
  398. 'type' => 'pay',
  399. 'keywords' => [
  400. 'keyword1' => [
  401. 'value' => moneyFormat($orderPayMoney, 2),
  402. 'color' => '#173177',
  403. ],
  404. 'keyword2' => [
  405. 'value' => date('Y.m.d H:i'),
  406. 'color' => '#173177',
  407. ],
  408. ],
  409. 'url' => url('/weixin/account/index', '', '', true),
  410. ];
  411. PRedis::set('payments:vip:message_' . $outTradeNo, ['notify' => $notifyData, 'params' => $params], 3600);
  412. Wechat::sendTplMsg($openid, $params);
  413. }
  414. }
  415. // 提交
  416. db()->commit();
  417. // 操作日志
  418. UserLog::saveLog(['user_id' => $userId, 'type' => 3, 'content' => "购买VIP:{$num}个月,支付金额:{$orderPayMoney},原到期时间:{$vipExpire}"]);
  419. // 分销收益结算
  420. $inviteInfo = MemberModel::getInviteInfo($userId);
  421. $inviteId = isset($inviteInfo['invite_id'])? $inviteInfo['invite_id'] : 0;
  422. if($inviteInfo && $inviteId>0){
  423. PRedis::set('markets:vip:entry' . $outTradeNo, ['notify' => $notifyData, 'inviteInfo'=> $inviteInfo, 'params' => $params], 7200);
  424. Award::marketAward($inviteId, $userId, 2, $orderPayMoney);
  425. }
  426. Payment::rebackOk();
  427. return true;
  428. } catch (\Exception $exception){
  429. PRedis::set('payments:vip:error:'.$outTradeNo, $exception, 3600);
  430. db()->rollback();
  431. return $exception->getMessage();
  432. }
  433. }
  434. /**
  435. * 人工牵线支付处理
  436. * @param $outTradeNo
  437. * @param $notifyData
  438. * @param $taskNo
  439. * @return bool|string
  440. * @throws \think\Exception
  441. * @throws \think\db\exception\DataNotFoundException
  442. * @throws \think\db\exception\ModelNotFoundException
  443. * @throws \think\exception\DbException
  444. * @throws \think\exception\PDOException
  445. */
  446. public static function catchHand($outTradeNo, $notifyData, $taskNo){
  447. // 验证订单是否存在
  448. $where = ['order_sn' => $outTradeNo, 'type'=> 5];
  449. $orderInfo = db('user_recharge_log')
  450. ->field('money,pay_money,user_id,order_sn,status')
  451. ->where($where)
  452. ->find();
  453. if(empty($orderInfo)){
  454. PRedis::set('payments:hand:errorMoney_'.$taskNo, ['result'=> $notifyData, 'error'=> $outTradeNo.'订单不存在'], 600);
  455. return false;
  456. }
  457. // 订单已处理
  458. PRedis::set('payments:hand:order_'.$taskNo, ['result'=> $notifyData, 'order'=> $orderInfo], 600);
  459. $orderStatus = isset($orderInfo['status']) ? intval($orderInfo['status']) : 0;
  460. // 验证订单状态是否可处理
  461. if ($orderStatus != 1) {
  462. db('user_recharge_log')->where($where)->update(['remark'=> '订单已处理']);
  463. Payment::rebackOk();
  464. return true;
  465. }
  466. // 验证订单金额是否正确
  467. $payDebug = config('weixin.payDebug');
  468. $payMoney = isset($notifyData['total_fee']) ? moneyFormat($notifyData['total_fee']) : 0;
  469. $orderMoney = isset($orderInfo['pay_money']) ? moneyFormat($orderInfo['pay_money']) : 0.00;
  470. if (!$payDebug && $orderMoney * 100 != $payMoney) {
  471. $error = ['remark'=> "订单金额错误:\n支付金额:" . $payMoney . "\n订单金额:" . $orderMoney];
  472. PRedis::set('payments:hand:errorMoney_'.$taskNo, ['result'=> $notifyData, 'order'=> $orderInfo,'error'=> $error], 600);
  473. db('user_recharge_log')->where($where)->update($error);
  474. return '支付金额错误';
  475. }
  476. try {
  477. db()->startTrans();
  478. // 更新订单支付状态信息
  479. $payMoney = isset($notifyData['total_fee']) ? moneyFormat($notifyData['total_fee']) : 0;
  480. $orderPayMoney = moneyFormat($payMoney / 100);
  481. $userId = isset($orderInfo['user_id']) ? $orderInfo['user_id'] : 0;
  482. $num = isset($orderInfo['money']) ? $orderInfo['money'] : 0;
  483. $updateData = [
  484. 'pay_money' => $orderPayMoney,
  485. 'transaction_id' => isset($notifyData['transaction_id']) ? $notifyData['transaction_id'] : '',
  486. 'status' => 2,
  487. 'pay_at' => date('Y-m-d H:i:s'),
  488. ];
  489. PRedis::set('payments:hand:catchOrder_' . $outTradeNo, ['notify' => $notifyData, 'update' => $updateData], 600);
  490. $res = db('user_recharge_log')->where($where)->update($updateData);
  491. if (!$res) {
  492. PRedis::set('payments:hand:updateError_' . $outTradeNo, ['notify' => $notifyData, 'update' => $updateData], 600);
  493. db()->rollback();
  494. return false;
  495. }
  496. // 更新账户
  497. if ($userId && $num > 0) {
  498. $dateTime = date('Y-m-d');
  499. $memberInfo = Member::where(['id' => $userId])->field('openid,vip_auth,vip_expire')->find();
  500. $vipAuth = isset($memberInfo['vip_auth']) ? intval($memberInfo['vip_auth']) : 0;
  501. $vipExpire = isset($memberInfo['vip_expire']) ? intval($memberInfo['vip_expire']) : 0;
  502. $newVipExpire = $vipExpire>$dateTime && $vipAuth? ($vipExpire-$dateTime) + $num*30*24*3600+86400 : $dateTime+$num*30*24*3600+86400;
  503. $data = ['updated_at' => date('Y-m-d H:i:s'), 'vip_auth'=> 1, 'vip_expire' => $newVipExpire];
  504. if (!Member::where(['id' => $userId])->update($data)) {
  505. db()->rollback();
  506. return false;
  507. }
  508. $accountData = [
  509. 'type' => 7,
  510. 'account_type' => 4,
  511. 'change_type' => 1,
  512. 'user_id' => $userId,
  513. 'money' => $num,
  514. 'balance' => 0,
  515. 'created_at' => date('Y-m-d H:i:s'),
  516. 'remark' => "购买人工牵线服务:单号[{$outTradeNo}],支付金额" . $orderPayMoney,
  517. ];
  518. PRedis::set('payments:hand:account_' . $outTradeNo, ['notify' => $notifyData, 'log' => $accountData,'user'=> $memberInfo], 600);
  519. db('account_log')->insertGetId($accountData);
  520. // 发送充值成功消息
  521. $openid = isset($memberInfo['openid']) ? $memberInfo['openid'] : '';
  522. if($openid) {
  523. $params = [
  524. 'title' => "恭喜您购买人工牵线服务成功",
  525. 'remark' => "感谢您的使用,点击详情查看购买明细",
  526. 'type' => 'pay',
  527. 'keywords' => [
  528. 'keyword1' => [
  529. 'value' => moneyFormat($orderPayMoney, 2),
  530. 'color' => '#173177',
  531. ],
  532. 'keyword2' => [
  533. 'value' => date('Y.m.d H:i'),
  534. 'color' => '#173177',
  535. ],
  536. ],
  537. 'url' => url('/weixin/account/index', '', '', true),
  538. ];
  539. PRedis::set('payments:hand:message_' . $outTradeNo, ['notify' => $notifyData, 'params' => $params], 600);
  540. Wechat::sendTplMsg($openid, $params);
  541. }
  542. }
  543. // 操作日志
  544. UserLog::saveLog(['user_id' => $userId, 'type' => 3, 'content' => "购买人工牵线服务:支付{$orderPayMoney}元"]);
  545. db()->commit();
  546. // 分销收益结算
  547. $inviteInfo = MemberModel::getInviteInfo($userId);
  548. $inviteId = isset($inviteInfo['invite_id'])? $inviteInfo['invite_id'] : 0;
  549. if($inviteInfo && $inviteId>0){
  550. PRedis::set('markets:hand:entry' . $outTradeNo, ['notify' => $notifyData, 'inviteInfo'=> $inviteInfo, 'params' => $params], 7200);
  551. Award::marketAward($inviteId, $userId, 3, $orderPayMoney);
  552. }
  553. Payment::rebackOk();
  554. return true;
  555. } catch (\Exception $exception){
  556. PRedis::set('payments:hand:error:'.$outTradeNo, $exception, 600);
  557. db()->rollback();
  558. return $exception->getMessage();
  559. }
  560. }
  561. }