OrderPay.php 12 KB

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