OrderPay.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. <?php
  2. namespace app\common\logic;
  3. use app\common\model\LedgerTokenChangeModel;
  4. use app\common\model\LedgerWalletModel;
  5. use app\common\model\OfflineRechargePayLogModel;
  6. use app\common\model\OfflineRechargeRecordModel;
  7. use app\common\model\OfflineRechargeVerifyModel;
  8. use Exception;
  9. use fast\Action;
  10. use fast\Asset;
  11. use fast\Http;
  12. use think\Config;
  13. use think\Db;
  14. use think\Env;
  15. use think\Error;
  16. use think\Model;
  17. use function EasyWeChat\Kernel\data_to_array;
  18. class OrderPay
  19. {
  20. const CheckCount = 5;//同一支付订单,如果前面判断失败,可以重复判断的次数。
  21. public function scanOrderPay()
  22. {
  23. $order_list = (new OfflineRechargeRecordModel())
  24. ->with('userInfo')
  25. ->whereNotNull('tx_hash')
  26. ->where('status',OfflineRechargeRecordModel::StatusConfirm)
  27. ->order('id')
  28. ->limit(10)
  29. ->select();
  30. if (empty($order_list)) {
  31. return '暂无可用订单';
  32. }
  33. $bonus_arr = Config::get('bonus');
  34. $pay_address = Env::get('rental.pay_address');
  35. foreach ($order_list as $item) {
  36. dump($item['order_no'],true,'开始处理订单');
  37. // 请求api,判断是否到账
  38. $result = $this->updateOrderPayStatus($item, $pay_address);
  39. dump($result,true,'校验结果');
  40. $insert_data = [
  41. 'order_no' => $item['order_no'],
  42. 'user_id' => $item['user_id'],
  43. 'hash' => $item['tx_hash'],
  44. 'result' => 1,
  45. 'fail_reason' => '成功',
  46. ];
  47. if($result['code'] == 0){//失败
  48. $insert_data['fail_reason'] = $result['msg'];
  49. $insert_data['result'] = 0;
  50. $check_count = (new OfflineRechargePayLogModel())->where('order_no', $item['order_no'])->count();
  51. if($check_count >= self::CheckCount){
  52. //扫描次数是否大于 5次,则改订单支付失败
  53. //更新支付记录
  54. (new OfflineRechargeRecordModel())
  55. ->where('id', $item['id'])
  56. ->update([
  57. 'status' => OfflineRechargeRecordModel::StatusFail,//支付失败
  58. 'note' => '支付失败,校验次数:' . self::CheckCount,
  59. 'update_time' => time(),
  60. ]);
  61. }
  62. }
  63. // 记录执行记录
  64. $log_id = (new OfflineRechargePayLogModel())->insertGetId($insert_data);
  65. //增加业绩或发放佣金
  66. if($result['code'] == 1 && $item['cha_bao'] > 0){
  67. switch ($item['order_type']){
  68. case 1://产品
  69. $uid = $item['user_id'];
  70. $amount= $item['amount'];
  71. $num = $item['cha_bao'];
  72. // 启动事务
  73. Db::startTrans();
  74. try {
  75. //充值茶宝
  76. (new LedgerWalletModel)->changeWalletAccount($uid, Asset::TOKEN, $num, LedgerTokenChangeModel::Recharge, $item['id']);
  77. //
  78. // // 更新自己(有效会员时间)和所有上级的信息(有效直推人数和团队总算力)
  79. // (new UserModel())->updateForRental($uid, $power);
  80. //
  81. //// // 发放直推USDT收益
  82. // (new LedgerWalletModel)->sendUsdtProfit($uid, $amount);
  83. //
  84. // // 发放直推算力收益
  85. // (new LedgerWalletModel)->sendDirectProfit($uid, $power);
  86. // // 间推奖
  87. // (new LedgerWalletModel)->sendGenerateProfit($uid, $amount);
  88. // // 发放见点奖
  89. // (new LedgerWalletModel)->sendRegBonus($uid);
  90. // 提交事务
  91. Db::commit();
  92. } catch (Exception $e) {
  93. // 回滚事务
  94. Db::rollback();
  95. return $e->getMessage();
  96. }
  97. dump($item['order_no'],true,'处理结束');
  98. break;
  99. case 2://服务器
  100. break;
  101. }
  102. }
  103. }
  104. }
  105. /*
  106. * 扫描收款地址
  107. */
  108. public function updateOrderPayStatus($pay_info, $to_address)
  109. {
  110. $pay_info['from_address'] = strtolower($pay_info['from_address']);
  111. if($pay_info['from_address'] != strtolower($pay_info['user_info']['address'])){
  112. return _error('from_adress不一致:用户地址:' . $pay_info['user_info']['address'] . ',充值表地址' . $pay_info['from_address']);
  113. }
  114. $get_transaction_info = (new MyBscApi())->getInfoByTransactionHash($pay_info['tx_hash']);
  115. if($get_transaction_info['code'] == 0){
  116. return $get_transaction_info;
  117. }
  118. $hash_info = $get_transaction_info['data'];
  119. if(!$hash_info['success']){
  120. return _error('交易失败');
  121. }
  122. //$pay_info['from_address'] = strtolower($pay_info['user_info']['address']);
  123. $pay_info['to_address'] = strtolower($to_address);
  124. $hash_info['from_address'] = strtolower($hash_info['from_address']);
  125. $hash_info['to_address'] = strtolower($hash_info['to_address']);
  126. if(!($hash_info['from_address'] == $pay_info['from_address'])){
  127. return _error('from_adress不一致:用户地址:' . $pay_info['from_address'] . ',链上' . $hash_info['from_address']);
  128. }
  129. if(!($hash_info['to_address'] == $pay_info['to_address'])){
  130. return _error('to_adress不一致:用户地址:' . $pay_info['to_address'] . ',链上' . $hash_info['to_address']);
  131. }
  132. if(!($hash_info['contract_address'] == '0x55d398326f99059fF775485246999027B3197955')){
  133. return _error('合约地址不是USDT,链上' . $hash_info['contract_address']);
  134. }
  135. if(!($hash_info['amount'] - $pay_info['amount'] == 0)){
  136. return _error('金额不一致:订单金额:' . $pay_info['amount'] . ',链上' . $hash_info['amount']);
  137. }
  138. //更新订单
  139. Db::startTrans();
  140. try {
  141. //更新支付记录
  142. (new OfflineRechargeRecordModel())
  143. ->where('id', $pay_info['id'])
  144. ->update([
  145. 'status'=> OfflineRechargeRecordModel::StatusSuccess,//支付成功
  146. 'update_time' => time(),
  147. ]);
  148. // 提交事务
  149. Db::commit();
  150. } catch (Exception $e) {
  151. // 回滚事务
  152. Db::rollback();
  153. return _error('提交失败:' . $e->getMessage());
  154. }
  155. return _success('');
  156. }
  157. public function scanOrders()
  158. {
  159. $recharges = (new OfflineRechargeRecordModel())
  160. ->where('status',OfflineRechargeRecordModel::StatusConfirm)
  161. ->order('id')
  162. ->limit(10)
  163. ->select();
  164. if (!is_null($recharges)) {
  165. foreach ($recharges as $v) {
  166. $vArr = $v->toArray();
  167. // 请求api
  168. $result = $this->verifyTxHash($vArr);
  169. // 记录执行记录
  170. (new OfflineRechargeVerifyModel())->insert([
  171. 'order_id' => $vArr['id'],
  172. 'user_id' => $vArr['user_id'],
  173. 'result' => $result == '',
  174. 'fail_reason' => $result,
  175. 'create_time' => time(),
  176. ]);
  177. }
  178. }
  179. }
  180. /**
  181. * 取消订单
  182. *
  183. * 同时会有判断是否恢复订单
  184. * @return void
  185. */
  186. public function cancelOrder()
  187. {
  188. $times = 60*10;//十分钟
  189. //筛选10分钟前创建订单却未支付的订单
  190. $order_info = (new OfflineRechargeRecordModel())
  191. ->field('r.id,r.user_id,u.address,r.create_time,r.amount')
  192. ->alias('r')
  193. ->join('user u','u.id = r.user_id')
  194. ->where('r.status',OfflineRechargeRecordModel::StatusDefault)
  195. ->where('r.create_time', '<', time() - $times)
  196. ->order('r.id')
  197. ->find();
  198. if(empty($order_info)){
  199. dump('本次没有未处理订单');
  200. return;
  201. }
  202. $to_address = Env::get('rental.pay_address');
  203. $get_block = (new BscApi())->getBlockNoByTime($order_info['create_time']);
  204. if($get_block['code'] == 0){
  205. \think\Log::info($get_block['msg'] . date('Y-m-d H:i:s'));
  206. dump($get_block, true, '获取区块高度有误');
  207. return;
  208. }
  209. //获取开始预约前的区块高度
  210. $start_block = $get_block['data'];
  211. dump('对应区块高度:' . $start_block);
  212. $pay_info = (new BscApi())->getTransactionRecordsByAddress($order_info['address'], $to_address, $start_block);
  213. dump($pay_info);
  214. if($pay_info['code'] != 1) {
  215. dump($pay_info['msg'], true, '获取交易数据失败');
  216. return;
  217. }
  218. $pay_data = $pay_info['data'];
  219. if (empty($pay_data)) {//无交易记录,则取消
  220. $result = (new OfflineRechargeRecordModel())
  221. ->where('id', $order_info['id'])
  222. ->update([
  223. 'status' => OfflineRechargeRecordModel::StatusFail,
  224. 'update_time' => time(),
  225. 'note' => '无交易记录,则取消',
  226. ]);
  227. return;
  228. }
  229. //找出金额匹配的交易数据
  230. $pay_arr = [];
  231. foreach ($pay_data as $pay) {
  232. if ($pay['amount'] - $order_info['amount'] == 0) {
  233. $pay_arr[] = $pay;
  234. }
  235. }
  236. if (empty($pay_arr)) {
  237. $result = (new OfflineRechargeRecordModel())
  238. ->where('id', $order_info['id'])
  239. ->update([
  240. 'status' => OfflineRechargeRecordModel::StatusFail,
  241. 'update_time' => time(),
  242. 'note' => '有交易记录,金额不匹配,则取消',
  243. ]);
  244. return;
  245. }
  246. //判断匹配上金额的数据,有没有存在
  247. foreach ($pay_arr as $pay) {
  248. $check = (new OfflineRechargeRecordModel())
  249. ->where('tx_hash', $pay['hash'])
  250. ->count();
  251. if ($check == 0 && $pay['time'] > $order_info['create_time']) {
  252. //hash不存在,并且交易时间大于订单创建时间,则捡回订单,改成待确认
  253. $result = (new OfflineRechargeRecordModel())
  254. ->where('id', $order_info['id'])
  255. ->update([
  256. 'status' => OfflineRechargeRecordModel::StatusConfirm,
  257. 'tx_hash' => $pay['hash'],
  258. 'update_time' => time(),
  259. 'note' => '捡回订单',
  260. ]);
  261. return;
  262. }
  263. }
  264. $result = (new OfflineRechargeRecordModel())
  265. ->where('id', $order_info['id'])
  266. ->update([
  267. 'status' => OfflineRechargeRecordModel::StatusFail,
  268. 'update_time' => time(),
  269. 'note' => '有交易记录,hash已存在或交易时间小于订单创建时间,则取消',
  270. ]);
  271. return;
  272. }
  273. }