TradeOrderService.php 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921
  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\Common;
  12. use App\Models\CapitalLogModel;
  13. use App\Models\MemberModel;
  14. use App\Models\MemberPaymentModel;
  15. use App\Models\TradeOrderModel;
  16. use App\Services\Api\MemberPaymentService;
  17. use App\Services\BaseService;
  18. use App\Services\ChatMessageService;
  19. use App\Services\ConfigService;
  20. use App\Services\RedisService;
  21. use App\Services\UsdtWalletService;
  22. /**
  23. * 用户交易订单-服务类
  24. * Class TradeOrderService
  25. * @package App\Services\Common
  26. */
  27. class TradeOrderService extends BaseService
  28. {
  29. // 静态对象
  30. protected static $instance = null;
  31. /**
  32. * 构造函数
  33. * @since 2020/11/10
  34. * TradeOrderService constructor.
  35. */
  36. public function __construct()
  37. {
  38. $this->model = new TradeOrderModel();
  39. $this->memberModel = new MemberModel();
  40. $this->capitalModel = new CapitalLogModel();
  41. $this->paymentModel = new MemberPaymentModel();
  42. }
  43. /**
  44. * 静态入口
  45. * @return static|null
  46. */
  47. public static function make()
  48. {
  49. if (!self::$instance) {
  50. self::$instance = (new static());
  51. }
  52. return self::$instance;
  53. }
  54. /**
  55. * 订单列表
  56. * @param $params
  57. * @param int $pageSize
  58. * @return array
  59. */
  60. public function getDataList($params, $pageSize = 15)
  61. {
  62. $list = $this->model->from('trade_order as a')
  63. ->leftJoin('member as b', 'b.id', '=', 'a.business_id')
  64. ->leftJoin('member as c', 'c.id', '=', 'a.user_id')
  65. ->where(function ($query) use ($params) {
  66. $query->where(['a.mark' => 1])->where('a.status', '>', 0);
  67. $orderNo = isset($params['order_no']) && $params['order_no'] ? trim($params['order_no']) : '';
  68. if ($orderNo) {
  69. $query->where('a.order_no', 'like', "%{$orderNo}%");
  70. }
  71. $type = isset($params['type']) ? intval($params['type']) : 0;
  72. if ($type > 0) {
  73. $query->where(['a.type' => $type]);
  74. }
  75. $businessName = isset($params['business_name']) ? trim($params['business_name']) : '';
  76. if ($businessName) {
  77. $query->where('b.username','like',"%{$businessName}%");
  78. }
  79. $userName = isset($params['username']) ? trim($params['username']) : '';
  80. if ($userName) {
  81. $query->where('c.username','like',"%{$userName}%");
  82. }
  83. $apiId = isset($params['api_id']) ? intval($params['api_id']) : 0;
  84. if ($apiId > 0) {
  85. $query->where(['a.api_id' => $apiId]);
  86. }
  87. $tradeType = isset($params['trade_type']) ? intval($params['trade_type']) : 0;
  88. if ($tradeType > 0) {
  89. $query->where(['a.trade_type' => $tradeType]);
  90. }
  91. // 日期
  92. $date = isset($params['date']) ? $params['date'] : [];
  93. $start = isset($date[0]) ? $date[0] : '';
  94. $end = isset($date[1]) ? $date[1] : '';
  95. $end = $start >= $end ? '' : $end;
  96. if ($start) {
  97. $query->where('a.create_time', '>=', strtotime($start));
  98. }
  99. if ($end) {
  100. $query->where('a.create_time', '<', strtotime($end));
  101. }
  102. $exceptionStatus = isset($params['exception_status']) ? intval($params['exception_status']) : 0;
  103. if ($exceptionStatus > 0) {
  104. $query->where(['a.exception_status' => $exceptionStatus]);
  105. }
  106. $status = isset($params['status']) ? intval($params['status']) : 0;
  107. if ($status > 0) {
  108. $query->where(['a.status' => $status]);
  109. }
  110. $userId = isset($params['user_id']) ? $params['user_id'] : 0;
  111. if ($userId > 0) {
  112. $query->where('a.user_id', $userId);
  113. }
  114. $businessId = isset($params['business_id']) ? $params['business_id'] : 0;
  115. if ($businessId > 0) {
  116. $query->where('a.business_id', $businessId);
  117. }
  118. })
  119. ->select(['a.*', 'b.username','b.realname as realname', 'c.username as c_username','c.realname as c_realname'])
  120. ->orderBy('a.create_time', 'desc')
  121. ->orderBy('a.id', 'desc')
  122. ->paginate($pageSize > 0 ? $pageSize : 9999999);
  123. $list = $list ? $list->toArray() : [];
  124. if ($list) {
  125. $payTypes = [1 => '银行卡', 2 => '微信', 3 => '支付宝', 4 => '其他'];
  126. $overTime = ConfigService::make()->getConfigByCode('trade_order_overtime');
  127. $overTime = $overTime ? $overTime : 0;
  128. foreach ($list['data'] as &$item) {
  129. $item['idcardData'] = $item['idcard_data'] ? json_decode($item['idcard_data'], true) : [];
  130. $item['paymentData'] = $item['payment_data'] ? json_decode($item['payment_data'], true) : [];
  131. $item['create_time_text'] = $item['create_time'] ? datetime($item['create_time'], 'Y-m-d H:i:s') : '';
  132. $item['update_time_text'] = $item['update_time'] ? datetime($item['update_time'], 'Y-m-d H:i:s') : '';
  133. $item['time_text'] = $item['create_time'] ? datetime($item['create_time'], 'H:i') : '';
  134. $item['utime_text'] = $item['update_time'] ? datetime($item['update_time'], 'm-d H:i') : '';
  135. $item['pay_time_text'] = $item['pay_time'] ? datetime($item['pay_time'], 'Y-m-d H:i') : '';
  136. $item['username_text'] = $item['username'] ? format_account($item['username']) : '';
  137. $item['c_username_text'] = $item['c_username'] ? format_account($item['c_username']) : '';
  138. $item['exception_img'] = $item['exception_img'] ? get_image_url($item['exception_img']) : '';
  139. $item['exception_img1'] = $item['exception_img1'] ? get_image_url($item['exception_img1']) : '';
  140. $item['exception_img2'] = $item['exception_img2'] ? get_image_url($item['exception_img2']) : '';
  141. $item['pay_img'] = $item['pay_img'] ? get_image_url($item['pay_img']) : '';
  142. $item['paymentData']['qrcode'] = isset($item['paymentData']['qrcode']) && $item['paymentData']['qrcode'] ? get_image_url($item['paymentData']['qrcode']) : '';
  143. $overTime = max(0, intval(strtotime($item['create_time'])) + $overTime * 60 - time());
  144. $item['overtime_text'] = in_array($item['status'], [1, 2]) && $overTime ? date('H:i', $overTime) : '';
  145. $payType = isset($item['pay_type']) ? $item['pay_type'] : 0;
  146. $item['pay_name'] = isset($payTypes[$payType]) ? $payTypes[$payType] : '其他';
  147. $item['chat_key'] = getChatKey($item['user_id'], $item['business_id']);
  148. }
  149. }
  150. return [
  151. 'pageSize' => $pageSize,
  152. 'total' => isset($list['total']) ? $list['total'] : 0,
  153. 'list' => isset($list['data']) ? $list['data'] : []
  154. ];
  155. }
  156. /**
  157. * 用户交易量
  158. * @param $userId
  159. * @param $date
  160. * @return mixed
  161. */
  162. public function getTotalByDate($userId, $date)
  163. {
  164. $total = $this->model->where(['business_id'=> $userId, 'status'=> 4, 'mark'=>1])
  165. ->where(function($query) use($date){
  166. $start = isset($date[0]) ? $date[0] : '';
  167. $end = isset($date[1]) ? $date[1] : '';
  168. $end = $start >= $end ? '' : $end;
  169. if ($start) {
  170. $query->where('pay_time', '>=', strtotime($start));
  171. }
  172. if ($end) {
  173. $query->where('pay_time', '<', strtotime($end));
  174. }
  175. })->sum('total');
  176. return $total;
  177. }
  178. /**
  179. * @param $orderNo
  180. * @return array
  181. */
  182. public function getInfoByNo($orderNo, $userId = 0)
  183. {
  184. $info = $this->model->from('trade_order as a')
  185. ->leftJoin('member as b', 'b.id', '=', 'a.business_id')
  186. ->leftJoin('member as c', 'c.id', '=', 'a.user_id')
  187. ->leftJoin('user as u', 'u.user_id', '=', 'a.business_id')
  188. ->where(['order_no' => $orderNo])
  189. ->where(function ($query) use ($userId) {
  190. $query->where(['a.mark' => 1])->where('a.status', '>', 0);
  191. if ($userId > 0) {
  192. $query->where(['a.user_id' => $userId]);
  193. }
  194. })
  195. ->select(['a.*', 'b.username', 'b.idcard_check', 'b.credit', 'u.bond', 'c.username as c_username'])
  196. ->first();
  197. $info = $info ? $info->toArray() : [];
  198. if ($info) {
  199. $overTime = ConfigService::make()->getConfigByCode('trade_order_overtime');
  200. $overTime = $overTime ? $overTime : 5;
  201. $info['idcardData'] = $info['idcard_data'] ? json_decode($info['idcard_data'], true) : [];
  202. $info['paymentData'] = $info['payment_data'] ? json_decode($info['payment_data'], true) : [];
  203. $info['create_time_text'] = $info['create_time'] ? datetime($info['create_time'], 'Y-m-d H:i:s') : '';
  204. $info['update_time_text'] = $info['update_time'] ? datetime($info['update_time'], 'Y-m-d H:i:s') : '';
  205. $info['time_text'] = $info['create_time'] ? datetime($info['create_time'], 'H:i') : '';
  206. $info['utime_text'] = $info['update_time'] ? datetime($info['update_time'], 'H:i') : '';
  207. $info['pay_time_text'] = $info['pay_time'] ? datetime($info['pay_time'], 'Y-m-d H:i') : '';
  208. $info['username_text'] = $info['username'] ? format_account($info['username']) : '';
  209. $info['c_username_text'] = $info['c_username'] ? format_account($info['c_username']) : '';
  210. $info['exception_img'] = $info['exception_img'] ? get_image_url($info['exception_img']) : '';
  211. $info['pay_img'] = $info['pay_img'] ? get_image_url($info['pay_img']) : '';
  212. $info['paymentData']['qrcode'] = isset($info['paymentData']['qrcode']) && $info['paymentData']['qrcode'] ? get_image_url($info['paymentData']['qrcode']) : '';
  213. $payType = isset($info['pay_type']) ? $info['pay_type'] : 0;
  214. $info['pay_name'] = isset($payTypes[$payType]) ? $payTypes[$payType] : '其他';
  215. $info['chat_key'] = getChatKey($info['user_id'], $info['business_id']);
  216. $overTime = max(0, intval(strtotime($info['create_time'])) + $overTime * 60 - time());
  217. $info['overtime_text'] = in_array($info['status'], [1, 2]) && $overTime ? date('i:s', $overTime) : '';
  218. $info['overtime'] = $overTime;
  219. }
  220. return $info;
  221. }
  222. /**
  223. * 获取待处理订单
  224. * @param $params
  225. * @return array
  226. */
  227. public function getWaitOrder($params)
  228. {
  229. $info = $this->model->from('trade_order as a')
  230. ->leftJoin('member as b', 'b.id', '=', 'a.business_id')
  231. ->where(function ($query) use ($params) {
  232. $query->where(['a.mark' => 1])->whereIn('a.status', [1, 2, 3, 7])->where('a.status', '>', 0);
  233. $orderNo = isset($params['order_no']) && $params['order_no'] ? trim($params['order_no']) : '';
  234. if ($orderNo) {
  235. $query->where('a.order_no', 'like', "%{$orderNo}%");
  236. }
  237. $type = isset($params['type']) ? intval($params['type']) : 0;
  238. if ($type > 0) {
  239. $query->where(['a.type' => $type]);
  240. }
  241. $userId = isset($params['user_id']) ? $params['user_id'] : 0;
  242. if ($userId > 0) {
  243. $query->where('a.user_id', $userId);
  244. }
  245. $businessId = isset($params['business_id']) ? $params['business_id'] : 0;
  246. if ($businessId > 0) {
  247. $query->where('a.business_id', $businessId);
  248. }
  249. })
  250. ->select(['a.id', 'a.order_no', 'a.type', 'a.pay_type', 'a.user_id', 'a.business_id', 'a.num', 'a.total', 'a.payment_data', 'a.status', 'a.create_time', 'b.username'])
  251. ->orderBy('a.create_time', 'desc')
  252. ->first();
  253. $info = $info ? $info->toArray() : [];
  254. if ($info) {
  255. $overTime = ConfigService::make()->getConfigByCode('trade_order_overtime');
  256. $overTime = $overTime ? $overTime : 5;
  257. $info['paymentData'] = $info['payment_data'] ? json_decode($info['payment_data'], true) : [];
  258. $info['create_time_text'] = $info['create_time'] ? format_time(strtotime($info['create_time'])) : '';
  259. $info['time_text'] = $info['create_time'] ? datetime($info['create_time'], 'H:i') : '';
  260. $info['username_text'] = $info['username'] ? format_account($info['username']) : '';
  261. $info['paymentData']['qrcode'] = isset($info['paymentData']['qrcode']) && $info['paymentData']['qrcode'] ? get_image_url($info['paymentData']['qrcode']) : '';
  262. $info['paymentData']['bank_card_text'] = isset($info['paymentData']['bank_card']) && $info['paymentData']['bank_card'] ? format_bank_card($info['paymentData']['bank_card']) : '未设置';
  263. $info['paymentData']['account_text'] = isset($info['paymentData']['account']) && $info['paymentData']['account'] ? format_account($info['paymentData']['account']) : '未设置';
  264. $overTime = max(0, intval(strtotime($info['create_time'])) + $overTime * 60 - time());
  265. $info['overtime_text'] = in_array($info['status'], [1, 2]) && $overTime ? date('H:i', $overTime) : '';
  266. }
  267. return $info;
  268. }
  269. /**
  270. * 成交交易笔数
  271. * @param int $type 类型:1-买单,2-卖单
  272. * @param int $bsid 承兑商用户ID
  273. * @param int $status 状态:4-成交
  274. * @return mixed
  275. */
  276. public function getCompleteCount($type = 1, $bsid = 0, $status = 4)
  277. {
  278. return (int)$this->model->where(['type' => $type, 'status' => $status, 'mark' => 1])
  279. ->where(function ($query) use ($bsid) {
  280. if ($bsid > 0) {
  281. $query->where('business_id', '=', $bsid);
  282. }
  283. })->count('id');
  284. }
  285. /**
  286. * 成交交易金额
  287. * @param int $type 类型:1-买单,2-卖单
  288. * @param int $bsid 承兑商用户ID
  289. * @param int $status 状态:4-成交
  290. * @param string $field 统计字段:total-总金额(默认),num-交易USDT数量
  291. * @return mixed
  292. */
  293. public function getCompleteTotal($type = 1, $bsid = 0, $status = 4, $field = 'total')
  294. {
  295. $total = $this->model->where(['type' => $type, 'status' => $status, 'mark' => 1])
  296. ->where(function ($query) use ($bsid) {
  297. if ($bsid > 0) {
  298. $query->where('business_id', '=', $bsid);
  299. }
  300. })->sum($field);
  301. return moneyFormat($total, 2);
  302. }
  303. /**
  304. * 今日成交交易金额
  305. * @param int $type 类型:1-买单,2-卖单
  306. * @param int $bsid 承兑商用户ID
  307. * @param int $status 状态:4-成交
  308. * @param string $field 统计字段:total-总金额(默认),num-交易USDT数量
  309. * @return mixed
  310. */
  311. public function getCompleteTotalByDay($type = 1, $bsid = 0, $status = 4, $field = 'total')
  312. {
  313. $total = $this->model->where(['type' => $type, 'status' => $status, 'mark' => 1])
  314. ->where('pay_time', '>=', strtotime(date('Y-m-d')))
  315. ->where(function ($query) use ($bsid) {
  316. if ($bsid > 0) {
  317. $query->where('business_id', '=', $bsid);
  318. }
  319. })->sum($field);
  320. return moneyFormat($total, 6);
  321. }
  322. /**
  323. * 24小时成交交易金额
  324. * @param int $time 时间/小时
  325. * @param int $bsid 承兑商用户ID
  326. * @param int $status 状态:4-成交
  327. * @param string $field 统计字段:total-总金额(默认),num-交易USDT数量
  328. * @return mixed
  329. */
  330. public function getCompleteTotalByTime($time = 24, $bsid = 0, $status = 4, $field = 'total')
  331. {
  332. $total = $this->model->where(['status' => $status, 'mark' => 1])
  333. ->where('pay_time', '>=', time() - $time * 3600)
  334. ->where(function ($query) use ($bsid) {
  335. if ($bsid > 0) {
  336. $query->where('business_id', '=', $bsid);
  337. }
  338. })->sum($field);
  339. return moneyFormat($total, 4);
  340. }
  341. /**
  342. * 24小时成交交易金额
  343. * @param int $time 时间/小时
  344. * @param int $bsid 承兑商用户ID
  345. * @param int $status 状态:4-成交
  346. * @param string $field 统计字段:total-总金额(默认),num-交易USDT数量
  347. * @return mixed
  348. */
  349. public function getCompleteCountByTime($time = 24, $bsid = 0, $status = 4, $field = 'id')
  350. {
  351. $total = $this->model->where(['status' => $status, 'mark' => 1])
  352. ->where('pay_time', '>=', time() - $time * 3600)
  353. ->where(function ($query) use ($bsid) {
  354. if ($bsid > 0) {
  355. $query->where('business_id', '=', $bsid);
  356. }
  357. })->count($field);
  358. return intval($total);
  359. }
  360. /**
  361. * 获取某个时间段的买卖交易量比
  362. * @param int $type 状态类型:1-成交的
  363. * @param int $bsid 承兑商用户ID
  364. * @param int $time 时间/分钟,默认15分钟
  365. * @return array
  366. */
  367. public function getCountRateByTime($type = 1, $bsid = 0, $time = 15)
  368. {
  369. $where = ['mark' => 1];
  370. if ($type == 1) {
  371. $where['status'] = 4;
  372. }
  373. $buyCount = $this->model->where(['type' => 1])->where($where)
  374. ->where(function ($query) use ($bsid) {
  375. if ($bsid > 0) {
  376. $query->where('business_id', '=', $bsid);
  377. }
  378. })
  379. ->where('pay_time', '>=', time() - $time * 60)
  380. ->count('id');
  381. $sellCount = $this->model->where(['type' => 2])->where($where)
  382. ->where(function ($query) use ($bsid) {
  383. if ($bsid > 0) {
  384. $query->where('business_id', '=', $bsid);
  385. }
  386. })
  387. ->where('pay_time', '>=', time() - $time * 60)
  388. ->count('id');
  389. $rate = ($buyCount || $sellCount) > 0 ? moneyFormat($buyCount / ($buyCount + $sellCount)) * 100 : 0;
  390. return ['buy' => $buyCount, 'sell' => $sellCount, 'buy_rate' => $rate, 'sell_rate' => ($sellCount > 0 ? 100 - $rate : 0)];
  391. }
  392. /**
  393. * 获取某个时间段的交易成功率
  394. * @param int $type 状态类型:1-成交的
  395. * @param int $bsid 承兑商用户ID
  396. * @param int $time 时间/小时,默认24小时
  397. * @return array
  398. */
  399. public function getRateByTime($bsid = 0, $time = 24)
  400. {
  401. $successCount = $this->model->where(['status' => 4, 'mark' => 1])
  402. ->where(function ($query) use ($bsid) {
  403. if ($bsid > 0) {
  404. $query->where('business_id', '=', $bsid);
  405. }
  406. })
  407. ->where('pay_time', '>=', time() - $time * 3600)
  408. ->count('id');
  409. $count = $this->model->where(['mark' => 1])
  410. ->where(function ($query) use ($bsid) {
  411. if ($bsid > 0) {
  412. $query->where('business_id', '=', $bsid);
  413. }
  414. })
  415. ->where(function ($query) use ($time) {
  416. $time = time() - $time * 3600;
  417. $query->where('pay_time', '>=', $time)
  418. ->orWhereRaw("(pay_time = 0 and create_time >={$time})");
  419. })
  420. ->count('id');
  421. $rate = $count > 0 ? moneyFormat($successCount / $count * 100) : 0;
  422. return ['rate' => $rate, 'success' => $successCount, 'count' => $count];
  423. }
  424. /**
  425. * 获取未支付或处理的订单数
  426. * @param $userId
  427. * @param int $type
  428. * @return mixed
  429. */
  430. public function checkOrderNoCatch($userId, $type = 1)
  431. {
  432. return $this->model->where(['user_id' => $userId, 'type' => $type, 'mark' => 1])->whereIn('status', [1, 2, 5, 7])->count('id');
  433. }
  434. /**
  435. * 客户买入
  436. * @param $userId
  437. * @param $params
  438. * @return false|int|number
  439. */
  440. public function buy($userId, $params)
  441. {
  442. $num = isset($params['num']) ? floatval($params['num']) : 0;
  443. $numType = isset($params['num_type']) ? intval($params['num_type']) : 1;
  444. if ($userId <= 0) {
  445. $this->error = '1013';
  446. return false;
  447. }
  448. // 验证参数
  449. $config = ConfigService::make()->getConfigOptionByGroup(5);
  450. $tradeOpen = isset($config['trade_usdt_open']) ? $config['trade_usdt_open'] : 0;
  451. $tradeMinNum = isset($config['trade_min_num']) ? $config['trade_min_num'] : 0;
  452. $tradeMaxNum = isset($config['trade_max_num']) ? $config['trade_max_num'] : 0;
  453. $trademinMoney = isset($config['trade_min_money']) ? $config['trade_min_money'] : 0;
  454. $tradeMaxMoney = isset($config['trade_max_money']) ? $config['trade_max_money'] : 0;
  455. $tradePrice = isset($config['usdt_buy_price']) ? $config['usdt_buy_price'] : 0;
  456. $tradeLimitNum = isset($config['trade_no_catch']) ? $config['trade_no_catch'] : 0;
  457. // 是否开启交易
  458. if ($tradeOpen != 1) {
  459. $this->error = '1013';
  460. return false;
  461. }
  462. if ($tradePrice <= 0) {
  463. $this->error = '3002';
  464. return false;
  465. }
  466. // 验证数量或金额
  467. $total = 0;
  468. if ($numType == 1) {
  469. if ($num < $tradeMinNum || $num > $tradeMaxNum) {
  470. $this->error = '3003';
  471. return false;
  472. }
  473. $total = moneyFormat($num * $tradePrice, 6);
  474. } else {
  475. if ($num < $trademinMoney || $num > $tradeMaxMoney) {
  476. $this->error = '3003';
  477. return false;
  478. }
  479. $total = moneyFormat($num, 6);
  480. $num = moneyFormat($num / $tradePrice, 6);
  481. }
  482. // 用户信息
  483. $userInfo = MemberService::make()->getInfo($userId);
  484. $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
  485. $idcardCheck = isset($userInfo['idcard_check']) ? $userInfo['idcard_check'] : 0;
  486. $username = isset($userInfo['username']) && $userInfo['username'] ? format_account($userInfo['username']) : '';
  487. if ($status != 1) {
  488. $this->error = '2009';
  489. return false;
  490. }
  491. if ($idcardCheck != 1) {
  492. $this->error = '2014';
  493. return false;
  494. }
  495. // 未处理订单
  496. $noCatchOrder = $this->checkOrderNoCatch($userId, 1);
  497. if ($tradeLimitNum > 0 && $noCatchOrder >= $tradeLimitNum) {
  498. $this->error = lang(3005, ['num' => $tradeLimitNum]);
  499. return false;
  500. }
  501. // 匹配交易商家
  502. $businessInfo = \App\Services\Api\MemberService::make()->getTradeMember($num, 1, $userId);
  503. if (empty($businessInfo)) {
  504. $this->error = '3004';
  505. return false;
  506. }
  507. if ($businessInfo['usdt_num'] < $num) {
  508. $this->error = '3004';
  509. return false;
  510. }
  511. // 客户身份信息
  512. $idcardData = [
  513. 'idcard' => isset($userInfo['idcard']) ? $userInfo['idcard'] : '',
  514. 'idcard_check' => isset($userInfo['idcard_check']) ? $userInfo['idcard_check'] : 0,
  515. 'idcard_front_img' => isset($userInfo['idcard_front_img']) ? $userInfo['idcard_front_img'] : '',
  516. 'idcard_back_img' => isset($userInfo['idcard_back_img']) ? $userInfo['idcard_back_img'] : '',
  517. 'idcard_hand_img' => isset($userInfo['idcard_hand_img']) ? $userInfo['idcard_hand_img'] : '',
  518. ];
  519. // 币商收款方式
  520. $payment = MemberPaymentService::make()->getPayment($businessInfo['id']);
  521. if (empty($payment)) {
  522. $this->error = '3015';
  523. return false;
  524. }
  525. $this->model->startTrans();
  526. $orderNo = get_order_num('OT');
  527. $data = [
  528. 'user_id' => $userId,
  529. 'business_id' => isset($businessInfo['id']) ? $businessInfo['id'] : 0,
  530. 'order_no' => $orderNo,
  531. 'type' => 1,
  532. 'pay_type' => isset($params['pay_type']) ? floatval($params['pay_type']) : 1,
  533. 'price' => $tradePrice,
  534. 'num' => $num,
  535. 'total' => $total,
  536. 'payment_id' => isset($payment['id']) ? intval($payment['id']) : 0,
  537. 'idcard_data' => $idcardData ? json_encode($idcardData, 256) : '',
  538. 'payment_data' => $payment ? json_encode($payment, 256) : '',
  539. 'create_time' => time(),
  540. 'update_time' => time(),
  541. 'status' => 1,
  542. 'mark' => 1,
  543. ];
  544. if (!$order = $this->model->edit($data)) {
  545. $this->model->rollBack();
  546. $this->error = '3023';
  547. return false;
  548. }
  549. if (!$this->memberModel->where(['id' => $businessInfo['id']])->decrement('usdt_num', $num)) {
  550. $this->model->rollBack();
  551. $this->error = '3020';
  552. return false;
  553. }
  554. $data = [
  555. 'order_no' => $orderNo,
  556. 'user_id' => $businessInfo['id'],
  557. 'type' => 2,
  558. 'pay_type' => 1,
  559. 'change_type' => 2,
  560. 'num' => $num,
  561. 'total' => $total,
  562. 'balance' => floatval($businessInfo['usdt_num'] - $num),
  563. 'create_time' => time(),
  564. 'update_time' => time(),
  565. 'status' => 1,
  566. 'mark' => 1,
  567. 'remark' => '交易员卖出',
  568. ];
  569. if (!$this->capitalModel->edit($data)) {
  570. $this->model->rollBack();
  571. $this->error = '3014';
  572. return false;
  573. }
  574. // 订单通知
  575. $data = [
  576. 'from_uid' => $userId,
  577. 'to_uid' => $businessInfo['id'],
  578. 'type' => 2,
  579. 'order_no' => $orderNo,
  580. 'chat_key' => getChatKey($userId, $businessInfo['id']),
  581. 'message' => "您有来自客户买单订单:{$orderNo}的消息,请尽快回复!",
  582. 'message_type' => 1,
  583. 'data_type' => 2,
  584. 'create_time' => time(),
  585. 'update_time' => time(),
  586. 'status' => 1,
  587. 'mark' => 1,
  588. ];
  589. if (!ChatMessageService::make()->pushMessage($data)) {
  590. $this->model->rollBack();
  591. $this->error = '3031';
  592. return false;
  593. }
  594. $this->model->commit();
  595. return $order;
  596. }
  597. /**
  598. * 客户卖出
  599. * @param $userId
  600. * @param $params
  601. * @return false|int|number
  602. */
  603. public function sell($userId, $params)
  604. {
  605. $num = isset($params['num']) ? floatval($params['num']) : 0;
  606. if ($userId <= 0) {
  607. $this->error = '1013';
  608. return false;
  609. }
  610. // 验证参数
  611. $config = ConfigService::make()->getConfigOptionByGroup(5);
  612. $tradeOpen = isset($config['trade_usdt_open']) ? $config['trade_usdt_open'] : 0;
  613. $tradeMinNum = isset($config['trade_min']) ? $config['trade_min'] : 0;
  614. $tradeMaxNum = isset($config['trade_max']) ? $config['trade_max'] : 0;
  615. $tradePrice = isset($config['usdt_sell_price']) ? $config['usdt_sell_price'] : 0;
  616. $tradeLimitNum = isset($config['trade_no_catch']) ? $config['trade_no_catch'] : 0;
  617. // 是否开启交易
  618. if ($tradeOpen != 1) {
  619. $this->error = '1013';
  620. return false;
  621. }
  622. if ($tradePrice <= 0) {
  623. $this->error = '3002';
  624. return false;
  625. }
  626. // 验证数量或金额
  627. $total = moneyFormat($num * $tradePrice, 6);
  628. if ($num < $tradeMinNum || ($tradeMaxNum && $num > $tradeMaxNum)) {
  629. $this->error = '3003';
  630. return false;
  631. }
  632. // 用户信息
  633. $userInfo = MemberService::make()->getInfo($userId);
  634. $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
  635. $idcardCheck = isset($userInfo['idcard_check']) ? $userInfo['idcard_check'] : 0;
  636. $usdtNum = isset($userInfo['usdt_num']) ? $userInfo['usdt_num'] : 0;
  637. $username = isset($userInfo['username']) && $userInfo['username'] ? format_account($userInfo['username']) : '';
  638. if ($status != 1) {
  639. $this->error = '2009';
  640. return false;
  641. }
  642. if ($idcardCheck != 1) {
  643. $this->error = '2014';
  644. return false;
  645. }
  646. if ($usdtNum < $num) {
  647. $this->error = '3011';
  648. return false;
  649. }
  650. // 未处理订单
  651. $noCatchOrder = $this->checkOrderNoCatch($userId, 2);
  652. if ($tradeLimitNum > 0 && $noCatchOrder >= $tradeLimitNum) {
  653. $this->error = lang(3005, ['num' => $tradeLimitNum]);
  654. return false;
  655. }
  656. // 匹配交易商家
  657. $businessInfo = \App\Services\Api\MemberService::make()->getTradeMember($num, 2, $userId);
  658. if (empty($businessInfo)) {
  659. $this->error = '3004';
  660. return false;
  661. }
  662. $idcardData = [
  663. 'idcard' => isset($userInfo['idcard']) ? $userInfo['idcard'] : '',
  664. 'idcard_check' => isset($userInfo['idcard_check']) ? $userInfo['idcard_check'] : 0,
  665. 'idcard_front_img' => isset($userInfo['idcard_front_img']) ? $userInfo['idcard_front_img'] : '',
  666. 'idcard_back_img' => isset($userInfo['idcard_back_img']) ? $userInfo['idcard_back_img'] : '',
  667. 'idcard_hand_img' => isset($userInfo['idcard_hand_img']) ? $userInfo['idcard_hand_img'] : '',
  668. ];
  669. // 收款方式
  670. $paymentId = isset($params['payment_id']) ? $params['payment_id'] : 0;
  671. $paymentInfo = MemberPaymentService::make()->getInfo($paymentId);
  672. if (empty($paymentInfo)) {
  673. $this->error = '3010';
  674. return false;
  675. }
  676. $paymentData = [
  677. 'payment_id' => $paymentInfo['id'],
  678. 'type' => $paymentInfo['type'],
  679. 'logo' => $paymentInfo['logo'] ? get_image_url($paymentInfo['logo']) : '',
  680. 'real_name' => $paymentInfo['real_name'],
  681. 'bank_name' => $paymentInfo['bank_name'],
  682. 'bank_card' => $paymentInfo['bank_card'],
  683. 'branch_name' => $paymentInfo['branch_name'],
  684. 'qrcode' => $paymentInfo['qrcode'] ? get_image_url($paymentInfo['qrcode']) : '',
  685. 'account' => $paymentInfo['account'],
  686. ];
  687. $orderNo = get_order_num('OT');
  688. $data = [
  689. 'user_id' => $userId,
  690. 'business_id' => isset($businessInfo['id']) ? $businessInfo['id'] : 0,
  691. 'order_no' => $orderNo,
  692. 'type' => 2,
  693. 'pay_type' => isset($params['pay_type']) ? floatval($params['pay_type']) : 1,
  694. 'price' => $tradePrice,
  695. 'num' => $num,
  696. 'payment_id' => $paymentId,
  697. 'idcard_data' => json_encode($idcardData, 256),
  698. 'payment_data' => json_encode($paymentData, 256),
  699. 'total' => $total,
  700. 'create_time' => time(),
  701. 'status' => 1,
  702. 'mark' => 1,
  703. ];
  704. $this->model->startTrans();
  705. if (!$order = $this->model->edit($data)) {
  706. $this->error = '3012';
  707. $this->model->rollBack();
  708. return false;
  709. }
  710. // 扣除币
  711. if (!$this->memberModel->where(['id' => $userId])->decrement('usdt_num', $num)) {
  712. $this->error = '3013';
  713. $this->model->rollBack();
  714. return false;
  715. }
  716. // 账户明细
  717. $data = [
  718. 'order_no' => $data['order_no'],
  719. 'user_id' => $userId,
  720. 'type' => 2,
  721. 'change_type' => 2,
  722. 'num' => $num,
  723. 'total' => $total,
  724. 'balance' => floatval($userInfo['usdt_num'] - $num),
  725. 'create_time' => time(),
  726. 'update_time' => time(),
  727. 'remark' => '客户卖出',
  728. 'status' => 1,
  729. 'mark' => 1,
  730. ];
  731. if (!$this->capitalModel->edit($data)) {
  732. $this->error = '3014';
  733. $this->model->rollBack();
  734. return false;
  735. }
  736. // 订单通知
  737. $data = [
  738. 'from_uid' => $userId,
  739. 'to_uid' => $businessInfo['id'],
  740. 'type' => 2,
  741. 'order_no' => $orderNo,
  742. 'chat_key' => getChatKey($userId, $businessInfo['id']),
  743. 'message' => "您有来自客户卖单订单:{$orderNo}的消息,请尽快回复!",
  744. 'message_type' => 1,
  745. 'data_type' => 3,
  746. 'create_time' => time(),
  747. 'update_time' => time(),
  748. 'status' => 1,
  749. 'mark' => 1,
  750. ];
  751. if (!ChatMessageService::make()->pushMessage($data)) {
  752. $this->model->rollBack();
  753. $this->error = '3023';
  754. return false;
  755. }
  756. $this->model->commit();
  757. return $order;
  758. }
  759. /**
  760. * 订单打款处理
  761. * @param $userId 用户ID
  762. * @param $params 打款参数
  763. * @return false
  764. */
  765. public function pay($userId, $params)
  766. {
  767. $orderId = isset($params['id']) ? $params['id'] : 0;
  768. if ($orderId <= 0) {
  769. $this->error = '1013';
  770. return false;
  771. }
  772. $orderInfo = $this->model->where(['user_id' => $userId, 'id' => $orderId, 'mark' => 1, 'type' => 1])
  773. ->whereIn('status', [1, 2, 5, 7])
  774. ->select(['id', 'order_no', 'business_id', 'type', 'payment_id', 'num', 'total', 'status'])
  775. ->first();
  776. $tradeType = isset($orderInfo['type']) ? $orderInfo['type'] : 0;
  777. if (empty($orderInfo)) {
  778. $this->error = '3016';
  779. return false;
  780. }
  781. if ($tradeType != 1) {
  782. $this->error = '3024';
  783. return false;
  784. }
  785. // 用户信息
  786. $userInfo = MemberService::make()->getInfo($userId);
  787. $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
  788. if ($status != 1) {
  789. $this->error = '2009';
  790. return false;
  791. }
  792. // 交易密码
  793. $tradePassword = isset($params['trade_password']) ? trim($params['trade_password']) : '';
  794. $password = isset($userInfo['trade_password']) ? trim($userInfo['trade_password']) : '';
  795. if (empty($password)) {
  796. $this->error = '2015';
  797. return false;
  798. }
  799. if (!$tradePassword || get_password($tradePassword . md5($tradePassword . 'otc')) != $password) {
  800. $this->error = '2016';
  801. return false;
  802. }
  803. $data = [
  804. 'status' => 3,
  805. 'pay_type' => $params['pay_type'],
  806. 'pay_img' => $params['pay_img'],
  807. 'pay_remark' => $params['pay_remark'],
  808. 'pay_time' => time(),
  809. ];
  810. if (!$this->model->where(['user_id' => $userId, 'id' => $orderId, 'mark' => 1])->update($data)) {
  811. $this->error = '3018';
  812. return false;
  813. }
  814. return true;
  815. }
  816. /**
  817. * 商家订单打款处理
  818. * @param $userId 用户ID
  819. * @param $params 打款参数
  820. * @return false
  821. */
  822. public function businessPay($businessId, $params)
  823. {
  824. $orderId = isset($params['id']) ? $params['id'] : 0;
  825. if ($orderId <= 0) {
  826. $this->error = '1013';
  827. return false;
  828. }
  829. $orderInfo = $this->model->where(['business_id' => $businessId, 'id' => $orderId, 'mark' => 1, 'type' => 2])
  830. ->whereIn('status', [1, 2, 5, 7])
  831. ->select(['id', 'user_id', 'order_no', 'business_id', 'type', 'payment_id', 'num', 'total', 'status'])
  832. ->first();
  833. $tradeType = isset($orderInfo['type']) ? $orderInfo['type'] : 0;
  834. if (empty($orderInfo)) {
  835. $this->error = '3016';
  836. return false;
  837. }
  838. if ($tradeType != 2) {
  839. $this->error = '3025';
  840. return false;
  841. }
  842. // 用户信息
  843. $userInfo = MemberService::make()->getInfo($businessId);
  844. $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
  845. $username = isset($userInfo['username']) ? $userInfo['username'] : 0;
  846. if ($status != 1) {
  847. $this->error = '2009';
  848. return false;
  849. }
  850. // 交易密码
  851. $tradePassword = isset($params['trade_password']) ? trim($params['trade_password']) : '';
  852. $password = isset($userInfo['trade_password']) ? trim($userInfo['trade_password']) : '';
  853. if (empty($password)) {
  854. $this->error = '2015';
  855. return false;
  856. }
  857. if (!$tradePassword || get_password($tradePassword . md5($tradePassword . 'otc')) != $password) {
  858. $this->error = '2016';
  859. return false;
  860. }
  861. if (strpos($params['pay_img'], "temp")) {
  862. $params['pay_img'] = save_image($params['pay_img'], 'images');
  863. } else {
  864. $params['pay_img'] = str_replace(IMG_URL, "", $params['pay_img']);
  865. }
  866. $data = [
  867. 'status' => 3,
  868. 'pay_type' => $params['pay_type'],
  869. 'pay_img' => $params['pay_img'],
  870. 'pay_remark' => $params['pay_remark'],
  871. 'pay_time' => time(),
  872. ];
  873. if (!$this->model->where(['business_id' => $businessId, 'id' => $orderId, 'mark' => 1])->update($data)) {
  874. $this->error = '3018';
  875. return false;
  876. }
  877. $this->error = '3017';
  878. return true;
  879. }
  880. /**
  881. * 订单确认处理
  882. * @param $userId 用户ID
  883. * @param $params 打款参数
  884. * @return false
  885. */
  886. public function collection($userId, $params)
  887. {
  888. $orderId = isset($params['id']) ? $params['id'] : 0;
  889. if ($orderId <= 0) {
  890. $this->error = '1013';
  891. return false;
  892. }
  893. $orderInfo = $this->model->where(['user_id' => $userId, 'id' => $orderId, 'mark' => 1, 'type' => 2])
  894. ->select(['id', 'user_id', 'order_no', 'business_id', 'payment_id', 'type', 'num', 'total', 'status'])
  895. ->first();
  896. $businessId = isset($orderInfo['business_id']) ? $orderInfo['business_id'] : 0;
  897. $tradeType = isset($orderInfo['type']) ? $orderInfo['type'] : 0;
  898. if (empty($orderInfo) || empty($businessId)) {
  899. $this->error = '3016';
  900. return false;
  901. }
  902. if ($orderInfo['status'] != 3) {
  903. $this->error = '3026';
  904. return false;
  905. }
  906. if ($tradeType != 2) {
  907. $this->error = '3024';
  908. return false;
  909. }
  910. $this->model->startTrans();
  911. // 订单状态更新
  912. if (!$this->model->where(['user_id' => $userId, 'id' => $orderId, 'mark' => 1])->update(['status' => 4, 'update_time' => time()])) {
  913. $this->model->rollBack();
  914. $this->error = '3023';
  915. return false;
  916. }
  917. // 交易处理
  918. if ($orderInfo['num'] > 0) {
  919. $info = $this->memberModel->where(['id' => $businessId, 'status' => 1, 'mark' => 1])->select(['id', 'username', 'usdt_num', 'user_type'])->first();
  920. if (empty($info)) {
  921. $this->model->rollBack();
  922. $this->error = '3019';
  923. return false;
  924. }
  925. // 商家进币
  926. if (!$this->memberModel->where(['id' => $businessId, 'mark' => 1])->increment('usdt_num', $orderInfo['num'])) {
  927. $this->model->rollBack();
  928. $this->error = '3019';
  929. return false;
  930. }
  931. // 明细处理
  932. $data = [
  933. 'order_no' => $orderInfo['order_no'],
  934. 'user_id' => $businessId,
  935. 'type' => 1,
  936. 'pay_type' => 1,
  937. 'change_type' => 1,
  938. 'num' => $orderInfo['num'],
  939. 'total' => $orderInfo['total'],
  940. 'balance' => floatval($info['usdt_num'] + $orderInfo['num']),
  941. 'create_time' => time(),
  942. 'remark' => '交易员买入',
  943. 'status' => 1,
  944. 'mark' => 1,
  945. ];
  946. if (!$this->capitalModel->edit($data)) {
  947. $this->error = '3014';
  948. $this->model->rollBack();
  949. return false;
  950. }
  951. }
  952. $this->model->commit();
  953. return true;
  954. }
  955. /**
  956. * 商家订单确认处理
  957. * @param $businessId 币商用户ID,平台处理时为0
  958. * @param $params 打款参数
  959. * @return false
  960. */
  961. public function businessCollection($businessId, $params)
  962. {
  963. $orderId = isset($params['id']) ? $params['id'] : 0;
  964. $catchUid = isset($params['catch_uid']) ? $params['catch_uid'] : 0;
  965. $type = isset($params['type']) ? $params['type'] : 0;
  966. if ($orderId <= 0) {
  967. $this->error = '1013';
  968. return false;
  969. }
  970. // 平台或币商处理
  971. $where = ['id' => $orderId, 'mark' => 1];
  972. if ($businessId) {
  973. $where['business_id'] = $businessId;
  974. }
  975. if ($type) {
  976. $where['type'] = $type;
  977. }
  978. $orderInfo = $this->model->where($where)
  979. ->select(['id', 'user_id','api_id','pt_order_no', 'order_no', 'business_id', 'type','contact_type','usdt_address','notify_url', 'trade_type', 'num', 'total','pay_time', 'status'])
  980. ->first();
  981. $userId = isset($orderInfo['user_id']) ? $orderInfo['user_id'] : 0;
  982. $orderType = isset($orderInfo['type']) ? $orderInfo['type'] : 0;
  983. $tradeType = isset($orderInfo['trade_type']) ? $orderInfo['trade_type'] : 0;
  984. if (empty($orderInfo) || (empty($userId) && $tradeType != 2)) {
  985. $this->error = '3016';
  986. return false;
  987. }
  988. $status = isset($params['status']) ? intval($params['status']) : 4;
  989. if ($status == 4 && $orderInfo['status'] != 3 && $businessId > 0) {
  990. $this->error = '3026';
  991. return false;
  992. }
  993. if ($status == 5 && $orderInfo['status'] == 8 && $businessId > 0) {
  994. $this->error = '3026';
  995. return false;
  996. }
  997. if ($status == 5 && $businessId <= 0 && $orderInfo['status'] == 4) {
  998. $this->error = '3026';
  999. return false;
  1000. }
  1001. if ($orderType != 1 && $status != 5) {
  1002. $this->error = '3024';
  1003. return false;
  1004. }
  1005. // 用户信息
  1006. if ($businessId > 0) {
  1007. $userInfo = MemberService::make()->getInfo($businessId);
  1008. $userStatus = isset($userInfo['status']) ? $userInfo['status'] : 0;
  1009. $username = isset($userInfo['username']) ? $userInfo['username'] : 0;
  1010. if ($userStatus != 1) {
  1011. $this->error = '2009';
  1012. return false;
  1013. }
  1014. // 交易密码
  1015. $tradePassword = isset($params['trade_password']) ? trim($params['trade_password']) : '';
  1016. $password = isset($userInfo['trade_password']) ? trim($userInfo['trade_password']) : '';
  1017. if (empty($password)) {
  1018. $this->error = '2015';
  1019. return false;
  1020. }
  1021. if (!$tradePassword || get_password($tradePassword . md5($tradePassword . 'otc')) != $password) {
  1022. $this->error = '2016';
  1023. return false;
  1024. }
  1025. }
  1026. $this->model->startTrans();
  1027. // 订单状态更新,异常或确认
  1028. $updateData = ['status' => $status, 'exception_catch_user' => $catchUid, 'update_time' => time()];
  1029. // 异常处理数据
  1030. if (isset($params['exception_type'])) {
  1031. $updateData['exception_type'] = intval($params['exception_type']);
  1032. }
  1033. if (isset($params['exception_sub_type'])) {
  1034. $updateData['exception_sub_type'] = intval($params['exception_sub_type']);
  1035. }
  1036. if (isset($params['exception_img'])) {
  1037. $updateData['exception_img'] = trim($params['exception_img']);
  1038. if (strpos($updateData['exception_img'], "temp")) {
  1039. $updateData['exception_img'] = save_image($updateData['exception_img'], 'images');
  1040. } else {
  1041. $updateData['exception_img'] = str_replace(IMG_URL, "", $updateData['exception_img']);
  1042. }
  1043. }
  1044. if (isset($params['exception_img1'])) {
  1045. $updateData['exception_img1'] = trim($params['exception_img1']);
  1046. if (strpos($updateData['exception_img1'], "temp")) {
  1047. $updateData['exception_img1'] = save_image($updateData['exception_img1'], 'images');
  1048. } else {
  1049. $updateData['exception_img1'] = str_replace(IMG_URL, "", $updateData['exception_img1']);
  1050. }
  1051. }
  1052. if (isset($params['exception_img2'])) {
  1053. $updateData['exception_img2'] = trim($params['exception_img2']);
  1054. if (strpos($updateData['exception_img2'], "temp")) {
  1055. $updateData['exception_img2'] = save_image($updateData['exception_img2'], 'images');
  1056. } else {
  1057. $updateData['exception_img2'] = str_replace(IMG_URL, "", $updateData['exception_img2']);
  1058. }
  1059. }
  1060. if (isset($params['exception_remark'])) {
  1061. $updateData['exception_remark'] = trim($params['exception_remark']);
  1062. }
  1063. if (isset($params['exception_status'])) {
  1064. $updateData['exception_status'] = intval($params['exception_status']);
  1065. }
  1066. if (!$this->model->where($where)->update($updateData)) {
  1067. $this->model->rollBack();
  1068. $this->error = '3023';
  1069. return false;
  1070. }
  1071. // 交易处理,如果是确认状态
  1072. if ($orderInfo['num'] > 0 && $status == 4 && $userId > 0 && $tradeType == 1) {
  1073. $info = $this->memberModel->where(['id' => $userId, 'status' => 1, 'mark' => 1])->select(['id', 'username', 'usdt_num', 'user_type'])->first();
  1074. if (empty($info)) {
  1075. $this->model->rollBack();
  1076. $this->error = '3019';
  1077. return false;
  1078. }
  1079. // 客户币进账
  1080. if (!$this->memberModel->where(['id' => $userId, 'mark' => 1])->increment('usdt_num', $orderInfo['num'])) {
  1081. $this->model->rollBack();
  1082. $this->error = '3019';
  1083. return false;
  1084. }
  1085. // 明细处理
  1086. $data = [
  1087. 'order_no' => $orderInfo['order_no'],
  1088. 'user_id' => $userId,
  1089. 'type' => 1,
  1090. 'pay_type' => 1,
  1091. 'change_type' => 1,
  1092. 'num' => $orderInfo['num'],
  1093. 'total' => $orderInfo['total'],
  1094. 'balance' => floatval($info['usdt_num'] + $orderInfo['num']),
  1095. 'create_time' => time(),
  1096. 'update_time' => time(),
  1097. 'remark' => '客户买入',
  1098. 'status' => 1,
  1099. 'mark' => 1,
  1100. ];
  1101. if (!$this->capitalModel->edit($data)) {
  1102. $this->error = '3014';
  1103. $this->model->rollBack();
  1104. return false;
  1105. }
  1106. // 更新收款地址数据
  1107. $paymentId = isset($orderInfo['payment_id']) ? $orderInfo['payment_id'] : 0;
  1108. $info = $this->paymentModel->where(['id' => $paymentId, 'mark' => 1])->select(['id', 'used_at'])->first();
  1109. if ($paymentId && $info) {
  1110. $usedAt = isset($info['used_at']) ? $info['used_at'] : '';
  1111. if ($usedAt < date('Y-m-d')) {
  1112. if (!$this->paymentModel->where(['id' => $paymentId])->update(['used_num' => 1, 'used_quota' => $orderInfo['total'], 'update_time' => time()])) {
  1113. $this->model->rollBack();
  1114. $this->error = '3018';
  1115. return false;
  1116. }
  1117. } else {
  1118. $res1 = $this->paymentModel->where(['id' => $paymentId])->increment('used_num', 1);
  1119. $res2 = $this->paymentModel->where(['id' => $paymentId])->increment('used_quota', floatval($orderInfo['total']));
  1120. if (!$res1 || !$res2) {
  1121. $this->model->rollBack();
  1122. $this->error = '3014';
  1123. return false;
  1124. }
  1125. }
  1126. }
  1127. }
  1128. // 外来平台需要出币和回调通知
  1129. else if(in_array($tradeType, [2,3]) && $status == 4){
  1130. $usdtAddress = isset($orderInfo['usdt_address'])? $orderInfo['usdt_address'] : '';
  1131. $contactType = isset($orderInfo['contact_type'])? $orderInfo['contact_type'] : '';
  1132. $notifyUrl = isset($orderInfo['notify_url'])? $orderInfo['notify_url'] : '';
  1133. if($usdtAddress && $contactType && $notifyUrl){
  1134. // TRC 出币
  1135. if($contactType == 1 && !$result = UsdtWalletService::make()->usdtTrcTransfer($usdtAddress,$orderInfo['num'])){
  1136. $this->model->rollBack();
  1137. $this->error = '3045';
  1138. return false;
  1139. }
  1140. // ERC 出币
  1141. else if($contactType == 2 && !$result = UsdtWalletService::make()->usdtErcTransfer($usdtAddress,$orderInfo['num'])){
  1142. $this->model->rollBack();
  1143. $this->error = '3045';
  1144. return false;
  1145. }
  1146. // 更新出币数据和发送回调
  1147. $txid = isset($result['txID'])? $result['txID'] : '';
  1148. if($txid) {
  1149. if (!$this->model->where($where)->update(['txid' => $txid, 'notify_num' => 1, 'notify_time' => date('Y-m-d H:i:s')])) {
  1150. $this->model->rollBack();
  1151. $this->error = '3045';
  1152. return false;
  1153. }
  1154. // 发送回调通知
  1155. $notifyData = [
  1156. 'transaction_id' => $orderInfo['order_no'],
  1157. 'order_no' => $orderInfo['pt_order_no'],
  1158. 'usdt' => $orderInfo['num'],
  1159. 'amount' => $orderInfo['total'],
  1160. 'contact_type' => $orderInfo['contact_type'],
  1161. 'usdt_address' => $orderInfo['usdt_address'],
  1162. 'hash' => $txid,
  1163. 'status'=> 1,
  1164. 'pay_time'=> $orderInfo['pay_time']? $orderInfo['pay_time'] : time(),
  1165. 'trade_time'=> time(),
  1166. ];
  1167. \App\Services\Oapi\TradeOrderService::make()->notify($notifyUrl, $notifyData);
  1168. }
  1169. }
  1170. }
  1171. $this->model->commit();
  1172. $this->error = $status == 5 ? 3032 : 3021;
  1173. return true;
  1174. }
  1175. /**
  1176. * 取消订单
  1177. * @param $userId
  1178. * @param $params
  1179. * @return false
  1180. */
  1181. public function cancel($userId, $params)
  1182. {
  1183. $orderId = isset($params['id']) ? intval($params['id']) : 0;
  1184. if ($orderId <= 0) {
  1185. $this->error = '1013';
  1186. return false;
  1187. }
  1188. $orderInfo = $this->model->where(['user_id' => $userId, 'id' => $orderId, 'mark' => 1])
  1189. ->select(['id', 'order_no', 'business_id', 'type', 'num', 'total', 'status'])
  1190. ->first();
  1191. $tradeType = isset($orderInfo['type']) ? $orderInfo['type'] : 0;
  1192. $businessId = isset($orderInfo['business_id']) ? $orderInfo['business_id'] : 0;
  1193. if (empty($orderInfo) || $businessId <= 0) {
  1194. $this->error = '3016';
  1195. return false;
  1196. }
  1197. if ($orderInfo['status'] == 3) {
  1198. $this->error = '3027';
  1199. return false;
  1200. }
  1201. if ($orderInfo['status'] == 4) {
  1202. $this->error = '3028';
  1203. return false;
  1204. }
  1205. if ($orderInfo['status'] == 7) {
  1206. $this->error = '3030';
  1207. return false;
  1208. }
  1209. if (!in_array($orderInfo['status'], [1, 2])) {
  1210. $this->error = '3029';
  1211. return false;
  1212. }
  1213. $this->model->startTrans();
  1214. // 订单状态更新
  1215. $updateData = ['status' => 8, 'update_time' => time(), 'exception_remark' => '客户取消'];
  1216. if (!$this->model->where(['user_id' => $userId, 'id' => $orderId, 'mark' => 1])->update($updateData)) {
  1217. $this->model->rollBack();
  1218. $this->error = '3023';
  1219. return false;
  1220. }
  1221. // 出售订单,USDT退回
  1222. if ($tradeType == 2 && $orderInfo['num'] > 0) {
  1223. $info = $this->memberModel->where(['id' => $userId, 'status' => 1, 'mark' => 1])->select(['id', 'username', 'usdt_num', 'user_type'])->first();
  1224. if (empty($info)) {
  1225. $this->model->rollBack();
  1226. $this->error = '3019';
  1227. return false;
  1228. }
  1229. // 退还币给客户
  1230. if (!$this->memberModel->where(['id' => $userId, 'mark' => 1])->increment('usdt_num', $orderInfo['num'])) {
  1231. $this->model->rollBack();
  1232. $this->error = '3019';
  1233. return false;
  1234. }
  1235. // 明细处理
  1236. $data = [
  1237. 'order_no' => $orderInfo['order_no'],
  1238. 'user_id' => $userId,
  1239. 'type' => 3,
  1240. 'pay_type' => 1,
  1241. 'change_type' => 1,
  1242. 'num' => $orderInfo['num'],
  1243. 'total' => $orderInfo['total'],
  1244. 'balance' => floatval($info['usdt_num'] + $orderInfo['num']),
  1245. 'create_time' => time(),
  1246. 'update_time' => time(),
  1247. 'remark' => '客户取消退还',
  1248. 'status' => 1,
  1249. 'mark' => 1,
  1250. ];
  1251. if (!$this->capitalModel->edit($data)) {
  1252. $this->error = '3014';
  1253. $this->model->rollBack();
  1254. return false;
  1255. }
  1256. } // 买入取消
  1257. else if ($tradeType == 1 && $orderInfo['num'] > 0) {
  1258. $info = $this->memberModel->where(['id' => $businessId, 'status' => 1, 'mark' => 1])->select(['id', 'username', 'usdt_num', 'user_type'])->first();
  1259. if (empty($info)) {
  1260. $this->model->rollBack();
  1261. $this->error = '3019';
  1262. return false;
  1263. }
  1264. // 退还币给客户
  1265. if (!$this->memberModel->where(['id' => $businessId, 'mark' => 1])->increment('usdt_num', $orderInfo['num'])) {
  1266. $this->model->rollBack();
  1267. $this->error = '3019';
  1268. return false;
  1269. }
  1270. // 明细处理
  1271. $data = [
  1272. 'order_no' => $orderInfo['order_no'],
  1273. 'user_id' => $businessId,
  1274. 'type' => 3,
  1275. 'pay_type' => 1,
  1276. 'change_type' => 1,
  1277. 'num' => $orderInfo['num'],
  1278. 'total' => $orderInfo['total'],
  1279. 'balance' => floatval($info['usdt_num'] + $orderInfo['num']),
  1280. 'create_time' => time(),
  1281. 'update_time' => time(),
  1282. 'remark' => '客户取消退还',
  1283. 'status' => 1,
  1284. 'mark' => 1,
  1285. ];
  1286. if (!$this->capitalModel->edit($data)) {
  1287. $this->error = '3014';
  1288. $this->model->rollBack();
  1289. return false;
  1290. }
  1291. }
  1292. $this->model->commit();
  1293. return true;
  1294. }
  1295. /**
  1296. * 取消订单
  1297. * @param $businessId 币商用户,平台为0
  1298. * @param $params
  1299. * @return false
  1300. */
  1301. public function businessCancel($businessId, $params)
  1302. {
  1303. $orderId = isset($params['id']) ? intval($params['id']) : 0;
  1304. $catchUid = isset($params['catch_uid']) ? intval($params['catch_uid']) : 0;
  1305. if ($orderId <= 0) {
  1306. $this->error = '1013';
  1307. return false;
  1308. }
  1309. $where = ['id' => $orderId, 'mark' => 1];
  1310. if ($businessId) {
  1311. $where['business_id'] = $businessId;
  1312. }
  1313. $orderInfo = $this->model->where($where)
  1314. ->select(['id', 'user_id', 'order_no', 'business_id', 'type','contact_type','trade_type', 'num', 'total', 'status'])
  1315. ->first();
  1316. $type = isset($orderInfo['type']) ? $orderInfo['type'] : 0;
  1317. $tradeType = isset($orderInfo['trade_type']) ? $orderInfo['trade_type'] : 0;
  1318. $userId = isset($orderInfo['user_id']) ? $orderInfo['user_id'] : 0;
  1319. $orderBusinessId = isset($orderInfo['business_id']) ? $orderInfo['business_id'] : 0;
  1320. if (empty($orderInfo) || $orderBusinessId <= 0) {
  1321. $this->error = '3016';
  1322. return false;
  1323. }
  1324. if (empty($userId) && $tradeType != 2) {
  1325. $this->error = '3019';
  1326. return false;
  1327. }
  1328. if ($orderInfo['status'] == 4) {
  1329. $this->error = '3028';
  1330. return false;
  1331. }
  1332. if (!in_array($orderInfo['status'], [1, 2, 3, 5, 7])) {
  1333. $this->error = '3029';
  1334. return false;
  1335. }
  1336. // 用户信息
  1337. $status = isset($params['status']) ? $params['status'] : 8;
  1338. if ($businessId > 0 && $status != 8) {
  1339. $userInfo = MemberService::make()->getInfo($businessId);
  1340. $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
  1341. $username = isset($userInfo['username']) ? $userInfo['username'] : 0;
  1342. if ($status != 1) {
  1343. $this->error = '2009';
  1344. return false;
  1345. }
  1346. // 交易密码
  1347. $tradePassword = isset($params['trade_password']) ? trim($params['trade_password']) : '';
  1348. $password = isset($userInfo['trade_password']) ? trim($userInfo['trade_password']) : '';
  1349. if (empty($password)) {
  1350. $this->error = '2015';
  1351. return false;
  1352. }
  1353. if (!$tradePassword || get_password($tradePassword . md5($tradePassword . 'otc')) != $password) {
  1354. $this->error = '2016';
  1355. return false;
  1356. }
  1357. }
  1358. $this->model->startTrans();
  1359. // 订单状态更新,或异常处理
  1360. $updateData = ['status' => $status, 'exception_catch_user' => $catchUid, 'update_time' => time(), 'exception_remark' => '交易员取消'];
  1361. // 异常处理数据
  1362. if (isset($params['exception_type'])) {
  1363. $updateData['exception_type'] = intval($params['exception_type']);
  1364. }
  1365. if (isset($params['exception_sub_type'])) {
  1366. $updateData['exception_sub_type'] = intval($params['exception_sub_type']);
  1367. }
  1368. if (isset($params['exception_img'])) {
  1369. $updateData['exception_img'] = trim($params['exception_img']);
  1370. if (strpos($updateData['exception_img'], "temp")) {
  1371. $updateData['exception_img'] = save_image($updateData['exception_img'], 'images');
  1372. } else {
  1373. $updateData['exception_img'] = str_replace(IMG_URL, "", $updateData['exception_img']);
  1374. }
  1375. }
  1376. if (isset($params['exception_remark'])) {
  1377. $updateData['exception_remark'] = trim($params['exception_remark']);
  1378. }
  1379. if (isset($params['exception_status'])) {
  1380. $updateData['exception_status'] = intval($params['exception_status']);
  1381. }
  1382. if (isset($params['refund_status'])) {
  1383. $updateData['refund_status'] = intval($params['refund_status']);
  1384. }
  1385. if (isset($params['refund_money'])) {
  1386. $updateData['refund_money'] = intval($params['refund_money']);
  1387. }
  1388. if (!$this->model->where($where)->update($updateData)) {
  1389. $this->model->rollBack();
  1390. $this->error = '3023';
  1391. return false;
  1392. }
  1393. // 平台内部订单取消
  1394. if($tradeType == 1){
  1395. // 出售订单,状态已取消,USDT退回
  1396. if ($type == 2 && $status == 8 && $orderInfo['num'] > 0) {
  1397. $info = $this->memberModel->where(['id' => $userId, 'status' => 1, 'mark' => 1])->select(['id', 'username', 'usdt_num', 'user_type'])->first();
  1398. if (empty($info)) {
  1399. $this->model->rollBack();
  1400. $this->error = '3019';
  1401. return false;
  1402. }
  1403. // 退还币给客户
  1404. if (!$this->memberModel->where(['id' => $userId, 'mark' => 1])->increment('usdt_num', $orderInfo['num'])) {
  1405. $this->model->rollBack();
  1406. $this->error = '3019';
  1407. return false;
  1408. }
  1409. // 明细处理
  1410. $data = [
  1411. 'order_no' => $orderInfo['order_no'],
  1412. 'user_id' => $userId,
  1413. 'type' => 3,
  1414. 'pay_type' => 1,
  1415. 'change_type' => 1,
  1416. 'num' => $orderInfo['num'],
  1417. 'total' => $orderInfo['total'],
  1418. 'balance' => floatval($info['usdt_num'] + $orderInfo['num']),
  1419. 'create_time' => time(),
  1420. 'update_time' => time(),
  1421. 'remark' => '交易员取消买入退还',
  1422. 'status' => 1,
  1423. 'mark' => 1,
  1424. ];
  1425. if (!$this->capitalModel->edit($data)) {
  1426. $this->error = '3014';
  1427. $this->model->rollBack();
  1428. return false;
  1429. }
  1430. } // 客户买入订单取消
  1431. else if ($type == 1 && $status == 8 && $orderInfo['num'] > 0) {
  1432. $info = $this->memberModel->where(['id' => $orderBusinessId, 'status' => 1, 'mark' => 1])->select(['id', 'username', 'usdt_num', 'user_type'])->first();
  1433. if (empty($info)) {
  1434. $this->model->rollBack();
  1435. $this->error = '3019';
  1436. return false;
  1437. }
  1438. // 退还币给客户
  1439. if (!$this->memberModel->where(['id' => $orderBusinessId, 'mark' => 1])->increment('usdt_num', $orderInfo['num'])) {
  1440. $this->model->rollBack();
  1441. $this->error = '3019';
  1442. return false;
  1443. }
  1444. // 明细处理
  1445. $data = [
  1446. 'order_no' => $orderInfo['order_no'],
  1447. 'user_id' => $orderBusinessId,
  1448. 'type' => 3,
  1449. 'pay_type' => 1,
  1450. 'change_type' => 1,
  1451. 'num' => $orderInfo['num'],
  1452. 'total' => $orderInfo['total'],
  1453. 'balance' => floatval($info['usdt_num'] + $orderInfo['num']),
  1454. 'create_time' => time(),
  1455. 'update_time' => time(),
  1456. 'remark' => '交易员取消卖出退还',
  1457. 'status' => 1,
  1458. 'mark' => 1,
  1459. ];
  1460. if (!$this->capitalModel->edit($data)) {
  1461. $this->error = '3014';
  1462. $this->model->rollBack();
  1463. return false;
  1464. }
  1465. }
  1466. }else{
  1467. // 卖出取消不需要退平台USDT,需要客服处理,线上退还币给平台方
  1468. // 客户买入取消
  1469. if ($type == 1 && $status == 8 && $orderInfo['num'] > 0) {
  1470. $info = $this->memberModel->where(['id' => $orderBusinessId, 'status' => 1, 'mark' => 1])->select(['id', 'username', 'usdt_num', 'user_type'])->first();
  1471. if (empty($info)) {
  1472. $this->model->rollBack();
  1473. $this->error = '3019';
  1474. return false;
  1475. }
  1476. // 退还币给客户
  1477. if (!$this->memberModel->where(['id' => $orderBusinessId, 'mark' => 1])->increment('usdt_num', $orderInfo['num'])) {
  1478. $this->model->rollBack();
  1479. $this->error = '3019';
  1480. return false;
  1481. }
  1482. // 明细处理
  1483. $data = [
  1484. 'order_no' => $orderInfo['order_no'],
  1485. 'user_id' => $orderBusinessId,
  1486. 'type' => 3,
  1487. 'pay_type' => 1,
  1488. 'change_type' => 1,
  1489. 'num' => $orderInfo['num'],
  1490. 'total' => $orderInfo['total'],
  1491. 'balance' => floatval($info['usdt_num'] + $orderInfo['num']),
  1492. 'create_time' => time(),
  1493. 'update_time' => time(),
  1494. 'remark' => '交易员取消卖出退还',
  1495. 'status' => 1,
  1496. 'mark' => 1,
  1497. ];
  1498. if (!$this->capitalModel->edit($data)) {
  1499. $this->error = '3014';
  1500. $this->model->rollBack();
  1501. return false;
  1502. }
  1503. }
  1504. }
  1505. $this->model->commit();
  1506. $this->error = $status == 5 ? 3032 : 3034;
  1507. return true;
  1508. }
  1509. /**
  1510. * 无效订单处理
  1511. * @return false
  1512. */
  1513. public function catchInvalidOrder()
  1514. {
  1515. $cacheKey = "caches:trades:cancels:";
  1516. if (RedisService::get($cacheKey . 'lock')) {
  1517. return false;
  1518. }
  1519. RedisService::set($cacheKey . 'lock', 1, rand(3, 5));
  1520. $overtime = ConfigService::make()->getConfigByCode('trade_order_overtime');
  1521. $cancelTime = ConfigService::make()->getConfigByCode('trade_order_cancel');
  1522. $catchNum = ConfigService::make()->getConfigByCode('trade_order_catch_num');
  1523. $catchNum = $catchNum > 0 ? $catchNum : 200;
  1524. // 处理超时订单
  1525. if ($overtime > 0) {
  1526. $this->model->where(['mark' => 1])
  1527. ->where('status', '<=', 2)
  1528. ->where('status', '>', 0)
  1529. ->where('create_time', '<=', time() - $overtime * 60)
  1530. ->update(['status' => 7, 'catch_at' => time()]);
  1531. }
  1532. if ($cancelTime <= 0) {
  1533. $this->error = '1023';
  1534. return false;
  1535. }
  1536. $fail = 0;
  1537. $success = 0;
  1538. $this->model->where(function ($query) use ($cancelTime) {
  1539. // 已更新为超时的订单
  1540. $query->where(['mark' => 1, 'status' => 7])
  1541. ->where('catch_at', '<=', time() - $cancelTime * 60);
  1542. })
  1543. ->orWhere(function ($query) use ($cancelTime, $overtime) {
  1544. $query->where('mark', '=', 1)
  1545. ->where('status', '<=', 2)
  1546. ->where('status', '>', 0)
  1547. ->where('create_time', '<=', time() - ($cancelTime + $overtime) * 60);
  1548. })
  1549. ->select(['id', 'user_id', 'business_id', 'order_no', 'type', 'trade_type', 'num', 'total'])
  1550. ->take($catchNum)
  1551. ->get()
  1552. ->each(function ($item, $k) use ($cacheKey, &$fail, &$success) {
  1553. // 客户卖出订单退还
  1554. $date = date('Y-m-d H:i:s');
  1555. $type = isset($item['type']) ? $item['type'] : 0;
  1556. if ($type == 2) {
  1557. // 内部订单退还USDT给客户
  1558. if ($item['trade_type'] == 1) {
  1559. if (!$this->orderReback($item['user_id'], $item)) {
  1560. $fail++;
  1561. RedisService::set($cacheKey . "order_{$item['order_no']}:u{$item['user_id']}_fail", ['order' => $item, 'msg' => lang($this->error), 'date' => $date], 3600);
  1562. } else {
  1563. $success++;
  1564. RedisService::set($cacheKey . "order_{$item['order_no']}:u{$item['user_id']}_success", ['order' => $item, 'msg' => lang($this->error), 'date' => $date], 3600);
  1565. }
  1566. }
  1567. } else {
  1568. if (!$this->orderReback($item['business_id'], $item)) {
  1569. $fail++;
  1570. RedisService::set($cacheKey . "order_{$item['order_no']}:b{$item['business_id']}_fail", ['order' => $item, 'msg' => lang($this->error), 'date' => $date], 3600);
  1571. } else {
  1572. $success++;
  1573. RedisService::set($cacheKey . "order_{$item['order_no']}:b{$item['business_id']}_success", ['order' => $item, 'msg' => lang($this->error), 'date' => $date], 3600);
  1574. }
  1575. }
  1576. });
  1577. return ['success' => $success, 'fail' => $fail];
  1578. }
  1579. /**
  1580. * 订单取消退还处理
  1581. * @param $userId
  1582. * @param $orderInfo
  1583. * @return bool
  1584. */
  1585. protected function orderReback($userId, $orderInfo)
  1586. {
  1587. try {
  1588. if ($orderInfo['num'] <= 0) {
  1589. return false;
  1590. }
  1591. $this->model->startTrans();
  1592. $updateData = ['status' => 8, 'update_time' => time(), 'catch_at' => time(),'exception_status'=> 0, 'exception_remark' => '系统取消'];
  1593. if (!$this->model->where(['id' => $orderInfo['id']])->update($updateData)) {
  1594. $this->model->rollBack();
  1595. $this->error = '3043';
  1596. return false;
  1597. }
  1598. $info = $this->memberModel->where(['id' => $userId, 'status' => 1, 'mark' => 1])->select(['id', 'username', 'usdt_num', 'user_type'])->first();
  1599. if (empty($info)) {
  1600. $this->model->rollBack();
  1601. $this->error = '3019';
  1602. return false;
  1603. }
  1604. // 退还币给客户
  1605. if (!$this->memberModel->where(['id' => $userId, 'mark' => 1])->increment('usdt_num', $orderInfo['num'])) {
  1606. $this->model->rollBack();
  1607. $this->error = '3019';
  1608. return false;
  1609. }
  1610. // 明细处理
  1611. $data = [
  1612. 'order_no' => $orderInfo['order_no'],
  1613. 'user_id' => $userId,
  1614. 'type' => 3,
  1615. 'pay_type' => 1,
  1616. 'change_type' => 1,
  1617. 'num' => $orderInfo['num'],
  1618. 'total' => $orderInfo['total'],
  1619. 'balance' => floatval($info['usdt_num'] + $orderInfo['num']),
  1620. 'create_time' => time(),
  1621. 'update_time' => time(),
  1622. 'remark' => '系统自动取消退还',
  1623. 'status' => 1,
  1624. 'mark' => 1,
  1625. ];
  1626. if (!$this->capitalModel->edit($data)) {
  1627. $this->error = '3014';
  1628. $this->model->rollBack();
  1629. return false;
  1630. }
  1631. $this->model->commit();
  1632. $this->error = '3044';
  1633. return true;
  1634. } catch (\Exception $exception) {
  1635. $this->error = $exception->getMessage();
  1636. return false;
  1637. }
  1638. }
  1639. /**
  1640. * 重新派单
  1641. * @param $id 订单ID
  1642. * @param $businessId 新派单用户
  1643. * @return false
  1644. */
  1645. public function reassign($id, $businessId)
  1646. {
  1647. if (empty($id) || empty($businessId)) {
  1648. $this->error = '1013';
  1649. return false;
  1650. }
  1651. $orderInfo = $this->model->where(['id' => $id])
  1652. ->select(['id', 'user_id', 'order_no', 'business_id', 'type', 'num', 'total', 'status'])
  1653. ->first();
  1654. $tradeType = isset($orderInfo['type']) ? $orderInfo['type'] : 0;
  1655. if (empty($orderInfo)) {
  1656. $this->error = '3016';
  1657. return false;
  1658. }
  1659. // 状态
  1660. if (!in_array($orderInfo['status'], [1, 2, 3, 5, 7])) {
  1661. $this->error = '3039';
  1662. return false;
  1663. }
  1664. if ($businessId == $orderInfo['business_id']) {
  1665. $this->error = '3035';
  1666. return false;
  1667. }
  1668. // 派单用户信息
  1669. $businessInfo = $this->memberModel->from('member as a')
  1670. ->leftJoin('member_setting as ms', 'ms.user_id', '=', 'a.id')
  1671. ->where(['a.id' => $businessId, 'a.status' => 1, 'a.mark' => 1])
  1672. ->select(['a.id', 'a.username', 'a.usdt_num', 'ms.buy_online', 'ms.buy_online_time', 'ms.sell_online', 'ms.sell_online_time'])
  1673. ->first();
  1674. if (empty($businessInfo)) {
  1675. $this->error = '3036';
  1676. return false;
  1677. }
  1678. // 余额
  1679. if ($businessInfo['usdt_num'] < $orderInfo['num']) {
  1680. $this->error = '3036';
  1681. return false;
  1682. }
  1683. // 在线状态
  1684. if ($tradeType == 1) {
  1685. if ($businessInfo['buy_online'] != 1 || $businessInfo['buy_online_time'] <= time()) {
  1686. $this->error = '3036';
  1687. return false;
  1688. }
  1689. } else if ($tradeType == 2) {
  1690. if ($businessInfo['sell_online'] != 1 || $businessInfo['sell_online_time'] <= time()) {
  1691. $this->error = '3036';
  1692. return false;
  1693. }
  1694. }
  1695. $payment = MemberPaymentService::make()->getPayment($businessId);
  1696. if (empty($payment)) {
  1697. $this->error = '3040';
  1698. return false;
  1699. }
  1700. $updateData = ['business_id' => $businessId, 'status' => 1, 'mark' => 1, 'create_time' => time(), 'pay_time' => 0, 'pay_img' => '', 'payment_data' => json_encode($payment, 256), 'exception_type' => 0, 'exception_remark' => '平台重新派单'];
  1701. if ($this->model->where(['id' => $id])->update($updateData)) {
  1702. $this->error = '3041';
  1703. return true;
  1704. }
  1705. $this->error = '3042';
  1706. return false;
  1707. }
  1708. }