TradeOrderService.php 31 KB

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