TradeOrderService.php 74 KB

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