OrderPay.php 12 KB

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