TradeOrderService.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2017~2021 LARAVEL研发中心
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://www.laravel.cn
  8. // +----------------------------------------------------------------------
  9. // | Author: laravel开发员 <laravel.qq.com>
  10. // +----------------------------------------------------------------------
  11. namespace App\Services\Oapi;
  12. use App\Models\ApiModel;
  13. use App\Models\CapitalLogModel;
  14. use App\Models\MemberModel;
  15. use App\Models\MemberPaymentModel;
  16. use App\Models\TradeOrderModel;
  17. use App\Services\Api\MemberPaymentService;
  18. use App\Services\BaseService;
  19. use App\Services\ChatMessageService;
  20. use App\Services\Common\ApiService;
  21. use App\Services\Common\MemberService;
  22. use App\Services\ConfigService;
  23. use App\Services\RedisService;
  24. /**
  25. * 用户交易订单-服务类
  26. * Class TradeOrderService
  27. * @package App\Services\Oapi
  28. */
  29. class TradeOrderService extends BaseService
  30. {
  31. // 静态对象
  32. protected static $instance = null;
  33. /**
  34. * 构造函数
  35. * @since 2020/11/10
  36. * TradeOrderService constructor.
  37. */
  38. public function __construct()
  39. {
  40. $this->model = new TradeOrderModel();
  41. $this->memberModel = new MemberModel();
  42. $this->apiModel = new ApiModel();
  43. $this->capitalModel = new CapitalLogModel();
  44. $this->paymentModel = new MemberPaymentModel();
  45. }
  46. /**
  47. * 静态入口
  48. * @return static|null
  49. */
  50. public static function make()
  51. {
  52. if (!self::$instance) {
  53. self::$instance = (new static());
  54. }
  55. return self::$instance;
  56. }
  57. /**
  58. * @param $orderNo
  59. * @return array
  60. */
  61. public function getInfoByNo($orderNo, $userId=0)
  62. {
  63. $info = $this->model->from('trade_order as a')
  64. ->leftJoin('member as b', 'b.id', '=', 'a.business_id')
  65. ->leftJoin('member as c', 'c.id', '=', 'a.user_id')
  66. ->leftJoin('user as u', 'u.user_id', '=', 'a.business_id')
  67. ->where(['order_no'=> $orderNo])
  68. ->where(function ($query) use($userId){
  69. $query->where(['a.mark' => 1])->where('a.status', '>=', 0);
  70. if($userId>0){
  71. $query->where(['a.user_id'=> $userId]);
  72. }
  73. })
  74. ->select(['a.*', 'b.username','b.realname','b.idcard_check','b.credit','u.bond', 'c.username as c_username','c.realname as c_realname'])
  75. ->first();
  76. $info = $info? $info->toArray() : [];
  77. if($info){
  78. $overTime = ConfigService::make()->getConfigByCode('trade_order_overtime');
  79. $overTime = $overTime ? $overTime : 5;
  80. $info['idcardData'] = $info['idcard_data'] ? json_decode($info['idcard_data'], true) : [];
  81. $info['paymentData'] = $info['payment_data'] ? json_decode($info['payment_data'], true) : [];
  82. $info['create_time_text'] = $info['create_time'] ? datetime($info['create_time'], 'Y-m-d H:i:s') : '';
  83. $info['update_time_text'] = $info['update_time'] ? datetime($info['update_time'], 'Y-m-d H:i:s') : '';
  84. $info['time_text'] = $info['create_time'] ? datetime($info['create_time'], 'H:i') : '';
  85. $info['utime_text'] = $info['update_time'] ? datetime($info['update_time'], 'H:i') : '';
  86. $info['pay_time_text'] = $info['pay_time'] ? datetime($info['pay_time'], 'Y-m-d H:i') : '';
  87. $info['username_text'] = $info['username'] ? format_account($info['username']) : '';
  88. $info['c_username_text'] = $info['c_username'] ? format_account($info['c_username']) : '';
  89. $info['exception_img'] = $info['exception_img'] ? get_image_url($info['exception_img']) : '';
  90. $info['pay_img'] = $info['pay_img'] ? get_image_url($info['pay_img']) : '';
  91. $info['paymentData']['qrcode'] = isset($info['paymentData']['qrcode']) && $info['paymentData']['qrcode'] ? get_image_url($info['paymentData']['qrcode']) : '';
  92. $payType = isset($info['pay_type']) ? $info['pay_type'] : 0;
  93. $info['pay_name'] = isset($payTypes[$payType]) ? $payTypes[$payType] : '其他';
  94. $info['chat_key'] = getChatKey($info['user_id'],$info['business_id']);
  95. $overTime = max(0, intval(strtotime($info['create_time'])) + $overTime * 60 - time());
  96. $info['overtime_text'] = in_array($info['status'], [1, 2]) && $overTime ? date('i:s', $overTime) : '00:00';
  97. $info['overtime'] = $overTime;
  98. }
  99. return $info;
  100. }
  101. /**
  102. *
  103. * @param $txid 币交易单号
  104. * @return array
  105. */
  106. public function getInfoByTradeHash($txid, $userId=0)
  107. {
  108. $info = $this->model->from('trade_order as a')
  109. ->leftJoin('member as b', 'b.id', '=', 'a.business_id')
  110. ->leftJoin('member as c', 'c.id', '=', 'a.user_id')
  111. ->leftJoin('user as u', 'u.user_id', '=', 'a.business_id')
  112. ->where(['txid'=> $txid])
  113. ->where(function ($query) use($userId){
  114. $query->where(['a.mark' => 1])->where('a.status', '>=', 0);
  115. if($userId>0){
  116. $query->where(['a.user_id'=> $userId]);
  117. }
  118. })
  119. ->select(['a.*', 'b.username','b.realname','b.idcard_check','b.credit','u.bond', 'c.username as c_username','c.realname as c_realname'])
  120. ->first();
  121. $info = $info? $info->toArray() : [];
  122. if($info){
  123. $overTime = ConfigService::make()->getConfigByCode('trade_order_overtime');
  124. $overTime = $overTime ? $overTime : 5;
  125. $info['idcardData'] = $info['idcard_data'] ? json_decode($info['idcard_data'], true) : [];
  126. $info['paymentData'] = $info['payment_data'] ? json_decode($info['payment_data'], true) : [];
  127. $info['create_time_text'] = $info['create_time'] ? datetime($info['create_time'], 'Y-m-d H:i:s') : '';
  128. $info['update_time_text'] = $info['update_time'] ? datetime($info['update_time'], 'Y-m-d H:i:s') : '';
  129. $info['time_text'] = $info['create_time'] ? datetime($info['create_time'], 'H:i') : '';
  130. $info['utime_text'] = $info['update_time'] ? datetime($info['update_time'], 'H:i') : '';
  131. $info['pay_time_text'] = $info['pay_time'] ? datetime($info['pay_time'], 'Y-m-d H:i') : '';
  132. $info['username_text'] = $info['username'] ? format_account($info['username']) : '';
  133. $info['c_username_text'] = $info['c_username'] ? format_account($info['c_username']) : '';
  134. $info['exception_img'] = $info['exception_img'] ? get_image_url($info['exception_img']) : '';
  135. $info['pay_img'] = $info['pay_img'] ? get_image_url($info['pay_img']) : '';
  136. $info['paymentData']['qrcode'] = isset($info['paymentData']['qrcode']) && $info['paymentData']['qrcode'] ? get_image_url($info['paymentData']['qrcode']) : '';
  137. $payType = isset($info['pay_type']) ? $info['pay_type'] : 0;
  138. $info['pay_name'] = isset($payTypes[$payType]) ? $payTypes[$payType] : '其他';
  139. $info['chat_key'] = getChatKey($info['user_id'],$info['business_id']);
  140. $overTime = max(0, intval(strtotime($info['create_time'])) + $overTime * 60 - time());
  141. $info['overtime_text'] = in_array($info['status'], [1, 2]) && $overTime ? date('i:s', $overTime) : '00:00';
  142. $info['overtime'] = $overTime;
  143. }
  144. return $info;
  145. }
  146. /**
  147. * 获取未支付或处理的订单数
  148. * @param $userId
  149. * @param int $type
  150. * @return mixed
  151. */
  152. public function checkOrderNoCatch($userId, $type = 1)
  153. {
  154. return $this->model->where(['user_id' => $userId, 'type' => $type, 'mark' => 1])->whereIn('status', [1, 2, 5, 7])->count('id');
  155. }
  156. /**
  157. * 客户买入
  158. * @param $userId
  159. * @param $params
  160. * @return false|int|number
  161. */
  162. public function buy($userId, $params)
  163. {
  164. $num = isset($params['num']) ? floatval($params['num']) : 0;
  165. $tradeType = isset($params['trade_type']) ? intval($params['trade_type']) : 0;
  166. $apiId = isset($params['api_id']) ? intval($params['api_id']) : 0;
  167. $contactType = isset($params['contact_type']) ? intval($params['contact_type']) : 0;
  168. $usdtAddress = isset($params['usdt_address']) ? trim($params['usdt_address']) : '';
  169. $ptOrderNo = isset($params['order_no']) ? trim($params['order_no']) : '';
  170. $notifyUrl = isset($params['notify_url']) ? trim($params['notify_url']) : '';
  171. $tradeType = $tradeType==3? $tradeType : 2;
  172. // 外汇平台需要注册登录
  173. if ($userId <= 0 && $tradeType == 3) {
  174. $this->error = '1013';
  175. return false;
  176. }
  177. if(empty($notifyUrl)){
  178. $this->error = '6007';
  179. return false;
  180. }
  181. if(empty($ptOrderNo)){
  182. $this->error = '6006';
  183. return false;
  184. }
  185. if($apiId<=0){
  186. $this->error = '6005';
  187. return false;
  188. }
  189. if(!in_array($contactType, [1,2])){
  190. $this->error = '2209';
  191. return false;
  192. }
  193. if(empty($usdtAddress)){
  194. $this->error = '2235';
  195. return false;
  196. }
  197. // 验证参数
  198. $config = ConfigService::make()->getConfigOptionByGroup(5);
  199. $tradeOpen = isset($config['trade_usdt_open']) ? $config['trade_usdt_open'] : 0;
  200. $tradeMinNum = isset($config['trade_min_num']) ? $config['trade_min_num'] : 0;
  201. $tradeMaxNum = isset($config['trade_max_num']) ? $config['trade_max_num'] : 0;
  202. $trademinMoney = isset($config['trade_min_money']) ? $config['trade_min_money'] : 0;
  203. $tradeMaxMoney = isset($config['trade_max_money']) ? $config['trade_max_money'] : 0;
  204. $tradePrice = isset($config['usdt_buy_price']) ? $config['usdt_buy_price'] : 0;
  205. $tradeLimitNum = isset($config['trade_no_catch']) ? $config['trade_no_catch'] : 0;
  206. // 是否开启交易
  207. if ($tradeOpen != 1) {
  208. $this->error = '1013';
  209. return false;
  210. }
  211. if ($tradePrice <= 0) {
  212. $this->error = '3002';
  213. return false;
  214. }
  215. // 验证数量或金额
  216. if ($num < $tradeMinNum || $num > $tradeMaxNum) {
  217. $this->error = '3003';
  218. return false;
  219. }
  220. $total = moneyFormat($num * $tradePrice, 6);
  221. // 用户信息,BC平台需要注册认证
  222. if($tradeType == 3){
  223. $userInfo = MemberService::make()->getInfo($userId);
  224. $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
  225. $idcardCheck = isset($userInfo['idcard_check']) ? $userInfo['idcard_check'] : 0;
  226. //$username = isset($userInfo['username']) && $userInfo['username'] ? format_account($userInfo['username']) : '';
  227. if ($status != 1) {
  228. $this->error = '2009';
  229. return false;
  230. }
  231. if ($idcardCheck != 1) {
  232. $this->error = '2014';
  233. return false;
  234. }
  235. }
  236. // 客户身份信息
  237. $idcardData = [
  238. 'idcard' => isset($userInfo['idcard']) ? $userInfo['idcard'] : $params['idcard'],
  239. 'realname' => isset($userInfo['realname']) ? $userInfo['realname'] : $params['realname'],
  240. 'bank_name' => isset($params['bank_name']) ? $params['bank_name'] : $params['bank_name'],
  241. 'bank_card' => isset($params['bank_card']) ? $params['bank_card'] : $params['bank_card'],
  242. 'idcard_check' => isset($userInfo['idcard_check']) ? $userInfo['idcard_check'] : (($params['realname'] && $params['idcard'])? 1:2),
  243. 'idcard_front_img' => isset($userInfo['idcard_front_img']) ? $userInfo['idcard_front_img'] : '',
  244. 'idcard_back_img' => isset($userInfo['idcard_back_img']) ? $userInfo['idcard_back_img'] : '',
  245. 'idcard_hand_img' => isset($userInfo['idcard_hand_img']) ? $userInfo['idcard_hand_img'] : '',
  246. ];
  247. $apiInfo = ApiService::make()->getInfo($apiId);
  248. $apiName = isset($apiInfo['account'])? $apiInfo['account'] : '';
  249. if(empty($apiInfo)){
  250. $this->error = '6005';
  251. return false;
  252. }
  253. // 未处理订单
  254. /*$noCatchOrder = $this->checkOrderNoCatch($userId, 1);
  255. if ($tradeLimitNum > 0 && $noCatchOrder >= $tradeLimitNum) {
  256. $this->error = lang(3005, ['num' => $tradeLimitNum]);
  257. return false;
  258. }*/
  259. // 匹配交易商家
  260. $businessInfo = \App\Services\Api\MemberService::make()->getTradeMember($num, 1, $userId);
  261. if (empty($businessInfo)) {
  262. $this->error = '3004';
  263. return false;
  264. }
  265. if($businessInfo['usdt_num']<$num){
  266. $this->error = '3004';
  267. return false;
  268. }
  269. // 币商收款方式
  270. $payment = MemberPaymentService::make()->getPayment($businessInfo['id']);
  271. if (empty($payment)) {
  272. $this->error = '3015';
  273. return false;
  274. }
  275. $this->model->startTrans();
  276. $orderNo = get_order_num('PT');
  277. $data = [
  278. 'user_id' => $userId,
  279. 'api_id' => $apiId,
  280. 'business_id' => $businessInfo['id'],
  281. 'order_no' => $orderNo,
  282. 'type' => 1,
  283. 'source' => $apiName,
  284. 'usdt_address' => $usdtAddress,
  285. 'pt_order_no' => $ptOrderNo,
  286. 'notify_url' => $notifyUrl,
  287. 'contact_type' => $contactType,
  288. 'trade_type' => $tradeType==2? $tradeType : 3,
  289. 'pay_type' => isset($params['pay_type']) ? floatval($params['pay_type']) : 1,
  290. 'price' => $tradePrice,
  291. 'num' => $num,
  292. 'total' => $total,
  293. 'payment_id' => isset($payment['id']) ? intval($payment['id']) : 0,
  294. 'idcard_data' => $idcardData ? json_encode($idcardData, 256) : '',
  295. 'payment_data' => $payment ? json_encode($payment, 256) : '',
  296. 'create_time' => time(),
  297. 'update_time' => time(),
  298. 'status' => 1,
  299. 'mark' => 1,
  300. ];
  301. if (!$order = $this->model->edit($data)) {
  302. $this->model->rollBack();
  303. $this->error = '3023';
  304. return false;
  305. }
  306. if(!$this->memberModel->where(['id'=> $businessInfo['id']])->decrement('usdt_num', $num)){
  307. $this->model->rollBack();
  308. $this->error = '3020';
  309. return false;
  310. }
  311. $data = [
  312. 'order_no'=> $orderNo,
  313. 'user_id'=> $businessInfo['id'],
  314. 'type'=> 7,
  315. 'pay_type'=> 1,
  316. 'change_type'=> 2,
  317. 'num'=> $num,
  318. 'total'=> $total,
  319. 'balance'=> floatval($businessInfo['usdt_num']-$num),
  320. 'create_time'=> time(),
  321. 'update_time'=> time(),
  322. 'status'=> 1,
  323. 'mark'=>1,
  324. 'remark'=> '交易员卖给平台',
  325. ];
  326. if(!$this->capitalModel->edit($data)){
  327. $this->model->rollBack();
  328. $this->error = '3014';
  329. return false;
  330. }
  331. // 订单通知
  332. $data = [
  333. 'from_uid' => $userId,
  334. 'to_uid' => $businessInfo['id'],
  335. 'type' => 2,
  336. 'order_no' => $orderNo,
  337. 'chat_key' => getChatKey($userId, $businessInfo['id']),
  338. 'message' => "您有来自外来客户买单订单:{$orderNo}的消息,请尽快回复!",
  339. 'message_type' => 1,
  340. 'data_type' => 2,
  341. 'create_time' => time(),
  342. 'update_time' => time(),
  343. 'status' => 1,
  344. 'mark' => 1,
  345. ];
  346. if (!ChatMessageService::make()->pushMessage($data)) {
  347. $this->model->rollBack();
  348. $this->error = '3031';
  349. return false;
  350. }
  351. $this->model->commit();
  352. return ['token'=> isset($params['token'])? $params['token'] : '', 'order_no'=> $data['order_no']];
  353. }
  354. /**
  355. * 客户卖出
  356. * @param $userId
  357. * @param $params
  358. * @return false|int|number
  359. */
  360. public function sell($userId, $params)
  361. {
  362. $num = isset($params['num']) ? floatval($params['num']) : 0;
  363. $tradeType = isset($params['trade_type']) ? intval($params['trade_type']) : 0;
  364. $apiId = isset($params['api_id']) ? intval($params['api_id']) : 0;
  365. $contactType = isset($params['contact_type']) ? intval($params['contact_type']) : 0;
  366. $usdtAddress = isset($params['usdt_address']) ? trim($params['usdt_address']) : '';
  367. $txid = isset($params['txid']) ? trim($params['txid']) : '';
  368. $ptOrderNo = isset($params['order_no']) ? trim($params['order_no']) : '';
  369. $notifyUrl = isset($params['notify_url']) ? trim($params['notify_url']) : '';
  370. $tradeType = $tradeType==3? $tradeType : 2;
  371. if ($userId <= 0 && $tradeType == 3) {
  372. $this->error = '1013';
  373. return false;
  374. }
  375. if(empty($notifyUrl)){
  376. $this->error = '6007';
  377. return false;
  378. }
  379. if(empty($txid)){
  380. $this->error = '6008';
  381. return false;
  382. }
  383. if(empty($ptOrderNo)){
  384. $this->error = '6006';
  385. return false;
  386. }
  387. if($apiId<=0){
  388. $this->error = '2209';
  389. return false;
  390. }
  391. if(!in_array($contactType, [1,2])){
  392. $this->error = '2209';
  393. return false;
  394. }
  395. if(empty($usdtAddress)){
  396. $this->error = '2235';
  397. return false;
  398. }
  399. // 收款银行信息
  400. $bankCard = isset($params['bank_card'])? $params['bank_card'] : '';
  401. $bankName = isset($params['bank_name'])? $params['bank_name'] : '';
  402. $realname = isset($params['realname'])? $params['realname'] : '';
  403. if(empty($bankCard) || empty($bankName) || empty($realname)){
  404. $this->error = '6009';
  405. return false;
  406. }
  407. // 验证参数
  408. $config = ConfigService::make()->getConfigOptionByGroup(5);
  409. $tradeOpen = isset($config['trade_usdt_open']) ? $config['trade_usdt_open'] : 0;
  410. $tradeMinNum = isset($config['trade_min']) ? $config['trade_min'] : 0;
  411. $tradeMaxNum = isset($config['trade_max']) ? $config['trade_max'] : 0;
  412. $tradePrice = isset($config['usdt_sell_price']) ? $config['usdt_sell_price'] : 0;
  413. $tradeLimitNum = isset($config['trade_no_catch']) ? $config['trade_no_catch'] : 0;
  414. // 是否开启交易
  415. if ($tradeOpen != 1) {
  416. $this->error = '1013';
  417. return false;
  418. }
  419. if ($tradePrice <= 0) {
  420. $this->error = '3002';
  421. return false;
  422. }
  423. // 验证数量或金额
  424. $total = moneyFormat($num * $tradePrice, 6);
  425. if ($num < $tradeMinNum || ($tradeMaxNum && $num > $tradeMaxNum)) {
  426. $this->error = '3003';
  427. return false;
  428. }
  429. // 用户信息
  430. if($tradeType == 3){
  431. $userInfo = MemberService::make()->getInfo($userId);
  432. $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
  433. $idcardCheck = isset($userInfo['idcard_check']) ? $userInfo['idcard_check'] : 0;
  434. $username = isset($userInfo['username']) && $userInfo['username'] ? format_account($userInfo['username']) : '';
  435. if ($status != 1) {
  436. $this->error = '2009';
  437. return false;
  438. }
  439. if ($idcardCheck != 1) {
  440. $this->error = '2014';
  441. return false;
  442. }
  443. }
  444. $idcardData = [
  445. 'idcard' => isset($userInfo['idcard']) ? $userInfo['idcard'] : $params['idcard'],
  446. 'realname' => isset($userInfo['realname']) ? $userInfo['realname'] : $params['realname'],
  447. 'bank_name' => isset($params['bank_name']) ? $params['bank_name'] : $params['bank_name'],
  448. 'bank_card' => isset($params['bank_card']) ? $params['bank_card'] : $params['bank_card'],
  449. 'idcard_check' => isset($userInfo['idcard_check']) ? $userInfo['idcard_check'] : (($params['realname'] && $params['idcard'])? 1:2),
  450. 'idcard_front_img' => isset($userInfo['idcard_front_img']) ? $userInfo['idcard_front_img'] : '',
  451. 'idcard_back_img' => isset($userInfo['idcard_back_img']) ? $userInfo['idcard_back_img'] : '',
  452. 'idcard_hand_img' => isset($userInfo['idcard_hand_img']) ? $userInfo['idcard_hand_img'] : '',
  453. ];
  454. $apiInfo = ApiService::make()->getInfo($apiId);
  455. $apiName = isset($apiInfo['account'])? $apiInfo['account'] : '';
  456. if(empty($apiInfo)){
  457. $this->error = '6005';
  458. return false;
  459. }
  460. // 未处理订单
  461. /*$noCatchOrder = $this->checkOrderNoCatch($userId, 2);
  462. if ($tradeLimitNum > 0 && $noCatchOrder >= $tradeLimitNum) {
  463. $this->error = lang(3005, ['num' => $tradeLimitNum]);
  464. return false;
  465. }*/
  466. $paymentData = [
  467. 'payment_id' => 0,
  468. 'type' => isset($params['type'])? intval($params['type']) : 1,
  469. 'logo' => isset($params['logo']) ? get_image_url($params['logo']) : '',
  470. 'real_name' => isset($params['realname'])? trim($params['realname']) : '',
  471. 'bank_name' => isset($params['bank_name'])? $params['bank_name'] : '',
  472. 'bank_card' => isset($params['bank_card'])? $params['bank_card'] : '',
  473. 'branch_name' => isset($params['branch_name'])? $params['branch_name'] : '',
  474. 'qrcode' => isset($params['qrcode']) && $params['qrcode'] ? get_image_url($params['qrcode']) : '',
  475. 'account' => isset($params['account'])? $params['account'] : '',
  476. ];
  477. $orderNo = get_order_num('PS');
  478. $data = [
  479. 'user_id' => $userId,
  480. 'api_id' => $apiId,
  481. 'business_id' => 0,
  482. 'order_no' => $orderNo,
  483. 'txid' => $txid,
  484. 'type' => 2,
  485. 'source' => $apiName,
  486. 'usdt_address' => $usdtAddress,
  487. 'pt_order_no' => $ptOrderNo,
  488. 'notify_url' => $notifyUrl,
  489. 'contact_type' => $contactType,
  490. 'trade_type' => $tradeType==2? $tradeType : 3,
  491. 'pay_type' => isset($params['pay_type']) ? floatval($params['pay_type']) : 1,
  492. 'price' => $tradePrice,
  493. 'num' => $num,
  494. 'payment_id' => 0,
  495. 'idcard_data' => json_encode($idcardData, 256),
  496. 'payment_data' => json_encode($paymentData, 256),
  497. 'total' => $total,
  498. 'create_time' => time(),
  499. 'status' => 0,
  500. 'mark' => 1,
  501. ];
  502. $this->model->startTrans();
  503. if (!$order = $this->model->edit($data)) {
  504. $this->error = '3012';
  505. $this->model->rollBack();
  506. return false;
  507. }
  508. $this->model->commit();
  509. return ['token'=> isset($params['token'])? $params['token'] : '', 'order_no'=> $data['order_no']];
  510. }
  511. /**
  512. * 订单打款处理
  513. * @param $userId 用户ID
  514. * @param $params 打款参数
  515. * @return false
  516. */
  517. public function pay($userId, $params)
  518. {
  519. $orderId = isset($params['id']) ? $params['id'] : 0;
  520. if ($orderId <= 0) {
  521. $this->error = '1013';
  522. return false;
  523. }
  524. $orderInfo = $this->model->where(['id' => $orderId, 'mark' => 1, 'type' => 1])
  525. ->whereIn('status', [1, 2, 5, 7])
  526. ->select(['id', 'order_no','api_id','user_id', 'business_id', 'type','trade_type', 'payment_id', 'num', 'total', 'status'])
  527. ->first();
  528. $type = isset($orderInfo['type']) ? $orderInfo['type'] : 0;
  529. $tradeType = isset($orderInfo['trade_type']) ? $orderInfo['trade_type'] : 0;
  530. $apiId = isset($orderInfo['api_id']) ? $orderInfo['api_id'] : 0;
  531. $orderUserId = isset($orderInfo['user_id']) ? $orderInfo['user_id'] : 0;
  532. if (empty($orderInfo)) {
  533. $this->error = '3016';
  534. return false;
  535. }
  536. if($tradeType == 3 && ($userId<=0 || $orderUserId != $userId)){
  537. $this->error = '6012';
  538. return false;
  539. }
  540. if ($type != 1) {
  541. $this->error = '3024';
  542. return false;
  543. }
  544. if(empty($apiId)){
  545. $this->error = '6011';
  546. return false;
  547. }
  548. // 用户信息
  549. if($userId>0){
  550. $userInfo = MemberService::make()->getInfo($userId);
  551. $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
  552. if ($status != 1) {
  553. $this->error = '2009';
  554. return false;
  555. }
  556. }
  557. if($apiId>0){
  558. $apiInfo = ApiService::make()->getInfo($apiId);
  559. if (empty($apiInfo)) {
  560. $this->error = '6011';
  561. return false;
  562. }
  563. }
  564. $data = [
  565. 'status' => 3,
  566. 'pay_type' => $params['pay_type'],
  567. 'pay_img' => $params['pay_img'],
  568. 'pay_remark' => $params['pay_remark'],
  569. 'pay_time' => time(),
  570. ];
  571. if (!$this->model->where(['user_id' => $userId, 'id' => $orderId, 'mark' => 1])->update($data)) {
  572. $this->error = '3018';
  573. return false;
  574. }
  575. return true;
  576. }
  577. /**
  578. * 订单确认处理
  579. * @param $userId 用户ID
  580. * @param $params 打款参数
  581. * @return false
  582. */
  583. public function collection($userId, $params)
  584. {
  585. $orderId = isset($params['id']) ? $params['id'] : 0;
  586. if ($orderId <= 0) {
  587. $this->error = '1013';
  588. return false;
  589. }
  590. $orderInfo = $this->model->where(['user_id' => $userId, 'id' => $orderId, 'mark' => 1, 'type' => 2])
  591. ->select(['id', 'user_id', 'order_no', 'business_id', 'payment_id', 'type', 'num', 'total', 'status'])
  592. ->first();
  593. $businessId = isset($orderInfo['business_id']) ? $orderInfo['business_id'] : 0;
  594. $tradeType = isset($orderInfo['type']) ? $orderInfo['type'] : 0;
  595. if (empty($orderInfo) || empty($businessId)) {
  596. $this->error = '3016';
  597. return false;
  598. }
  599. if ($orderInfo['status'] != 3) {
  600. $this->error = '3026';
  601. return false;
  602. }
  603. if ($tradeType != 2) {
  604. $this->error = '3024';
  605. return false;
  606. }
  607. $this->model->startTrans();
  608. // 订单状态更新
  609. if (!$this->model->where(['user_id' => $userId, 'id' => $orderId, 'mark' => 1])->update(['status' => 4, 'update_time' => time()])) {
  610. $this->model->rollBack();
  611. $this->error = '3023';
  612. return false;
  613. }
  614. // 交易处理
  615. if ($orderInfo['num'] > 0) {
  616. $info = $this->memberModel->where(['id' => $businessId, 'status' => 1, 'mark' => 1])->select(['id', 'username','usdt_num', 'user_type'])->first();
  617. if (empty($info)) {
  618. $this->model->rollBack();
  619. $this->error = '3019';
  620. return false;
  621. }
  622. // 商家进币
  623. if (!$this->memberModel->where(['id' => $businessId, 'mark' => 1])->increment('usdt_num', $orderInfo['num'])) {
  624. $this->model->rollBack();
  625. $this->error = '3019';
  626. return false;
  627. }
  628. // 明细处理
  629. $data = [
  630. 'order_no' => $orderInfo['order_no'],
  631. 'user_id' => $businessId,
  632. 'type' => 1,
  633. 'pay_type' => 1,
  634. 'change_type' => 1,
  635. 'num' => $orderInfo['num'],
  636. 'total' => $orderInfo['total'],
  637. 'balance' => floatval($info['usdt_num'] + $orderInfo['num']),
  638. 'create_time' => time(),
  639. 'remark' => '交易员买入',
  640. 'status' => 1,
  641. 'mark' => 1,
  642. ];
  643. if (!$this->capitalModel->edit($data)) {
  644. $this->error = '3014';
  645. $this->model->rollBack();
  646. return false;
  647. }
  648. }
  649. $this->model->commit();
  650. return true;
  651. }
  652. /**
  653. * 取消订单
  654. * @param $userId
  655. * @param $params
  656. * @return false
  657. */
  658. public function cancel($userId, $params)
  659. {
  660. $orderId = isset($params['id']) ? intval($params['id']) : 0;
  661. if ($orderId <= 0) {
  662. $this->error = '1013';
  663. return false;
  664. }
  665. $orderInfo = $this->model->where(['user_id' => $userId, 'id' => $orderId, 'mark' => 1])
  666. ->select(['id', 'order_no', 'business_id', 'type', 'num', 'total', 'status'])
  667. ->first();
  668. $tradeType = isset($orderInfo['type']) ? $orderInfo['type'] : 0;
  669. $businessId = isset($orderInfo['business_id']) ? $orderInfo['business_id'] : 0;
  670. if (empty($orderInfo) || $businessId<=0) {
  671. $this->error = '3016';
  672. return false;
  673. }
  674. if ($orderInfo['status'] == 3) {
  675. $this->error = '3027';
  676. return false;
  677. }
  678. if ($orderInfo['status'] == 4) {
  679. $this->error = '3028';
  680. return false;
  681. }
  682. if ($orderInfo['status'] == 7) {
  683. $this->error = '3030';
  684. return false;
  685. }
  686. if (!in_array($orderInfo['status'], [1, 2])) {
  687. $this->error = '3029';
  688. return false;
  689. }
  690. $this->model->startTrans();
  691. // 订单状态更新
  692. $updateData = ['status' => 8, 'update_time' => time(), 'exception_remark' => '客户取消'];
  693. if (!$this->model->where(['user_id' => $userId, 'id' => $orderId, 'mark' => 1])->update($updateData)) {
  694. $this->model->rollBack();
  695. $this->error = '3023';
  696. return false;
  697. }
  698. // 出售订单,USDT退回
  699. if ($tradeType == 2 && $orderInfo['num']>0) {
  700. $info = $this->memberModel->where(['id' => $userId, 'status' => 1, 'mark' => 1])->select(['id', 'username', 'usdt_num', 'user_type'])->first();
  701. if (empty($info)) {
  702. $this->model->rollBack();
  703. $this->error = '3019';
  704. return false;
  705. }
  706. // 退还币给客户
  707. if (!$this->memberModel->where(['id' => $userId, 'mark' => 1])->increment('usdt_num', $orderInfo['num'])) {
  708. $this->model->rollBack();
  709. $this->error = '3019';
  710. return false;
  711. }
  712. // 明细处理
  713. $data = [
  714. 'order_no' => $orderInfo['order_no'],
  715. 'user_id' => $userId,
  716. 'type' => 3,
  717. 'pay_type' => 1,
  718. 'change_type' => 1,
  719. 'num' => $orderInfo['num'],
  720. 'total' => $orderInfo['total'],
  721. 'balance' => floatval($info['usdt_num'] + $orderInfo['num']),
  722. 'create_time' => time(),
  723. 'update_time' => time(),
  724. 'remark' => '客户取消退还',
  725. 'status' => 1,
  726. 'mark' => 1,
  727. ];
  728. if (!$this->capitalModel->edit($data)) {
  729. $this->error = '3014';
  730. $this->model->rollBack();
  731. return false;
  732. }
  733. }
  734. // 买入取消
  735. else if($tradeType == 1 && $orderInfo['num']>0){
  736. $info = $this->memberModel->where(['id' => $businessId, 'status' => 1, 'mark' => 1])->select(['id', 'username', 'usdt_num', 'user_type'])->first();
  737. if (empty($info)) {
  738. $this->model->rollBack();
  739. $this->error = '3019';
  740. return false;
  741. }
  742. // 退还币给客户
  743. if (!$this->memberModel->where(['id' => $businessId, 'mark' => 1])->increment('usdt_num', $orderInfo['num'])) {
  744. $this->model->rollBack();
  745. $this->error = '3019';
  746. return false;
  747. }
  748. // 明细处理
  749. $data = [
  750. 'order_no' => $orderInfo['order_no'],
  751. 'user_id' => $businessId,
  752. 'type' => 3,
  753. 'pay_type' => 1,
  754. 'change_type' => 1,
  755. 'num' => $orderInfo['num'],
  756. 'total' => $orderInfo['total'],
  757. 'balance' => floatval($info['usdt_num'] + $orderInfo['num']),
  758. 'create_time' => time(),
  759. 'update_time' => time(),
  760. 'remark' => '客户取消退还',
  761. 'status' => 1,
  762. 'mark' => 1,
  763. ];
  764. if (!$this->capitalModel->edit($data)) {
  765. $this->error = '3014';
  766. $this->model->rollBack();
  767. return false;
  768. }
  769. }
  770. $this->model->commit();
  771. return true;
  772. }
  773. /**
  774. * 回调通知
  775. * @param $notifyUrl
  776. * @param $data
  777. * @return bool
  778. */
  779. public function notify($notifyUrl, $data)
  780. {
  781. if(empty($notifyUrl) || empty($data)){
  782. return false;
  783. }
  784. $orderNo = isset($data['transaction_id'])? $data['transaction_id'] : '';
  785. $cacheKey = "caches:notify:no_{$orderNo}";
  786. if(RedisService::get($cacheKey.'_lock')){
  787. return false;
  788. }
  789. RedisService::set($cacheKey.'_lock', ['url'=> $notifyUrl,'data'=> $data], rand(3, 5));
  790. $result = curl_api($notifyUrl, $data,[], 10);
  791. RedisService::set($cacheKey, ['url'=> $notifyUrl,'data'=> $data,'result'=> $result], 7200);
  792. return true;
  793. }
  794. }