TradeService.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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\Api;
  12. use App\Models\AcceptorModel;
  13. use App\Models\AccountLogModel;
  14. use App\Models\MemberBankModel;
  15. use App\Models\MemberModel;
  16. use App\Models\TradeModel;
  17. use App\Models\VideoCollectModel;
  18. use App\Models\VideoModel;
  19. use App\Services\BaseService;
  20. use App\Services\ConfigService;
  21. use App\Services\RedisService;
  22. use Illuminate\Support\Facades\DB;
  23. /**
  24. * 承兑商交易管理-服务类
  25. * @author laravel开发员
  26. * @since 2020/11/11
  27. * @package App\Services\Api
  28. */
  29. class TradeService extends BaseService
  30. {
  31. // 静态对象
  32. protected static $instance = null;
  33. /**
  34. * 构造函数
  35. * @author laravel开发员
  36. * @since 2020/11/11
  37. * GoodsService constructor.
  38. */
  39. public function __construct()
  40. {
  41. $this->model = new TradeModel();
  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 = 18, $field = '', $userId = 0)
  61. {
  62. $where = ['a.mark' => 1, 'b.mark' => 1];
  63. $field = $field ? $field : 'lev_a.*';
  64. $order = 'lev_a.id desc';
  65. $list = $this->model->with(['member', 'acceptor'])->from('trade as a')
  66. ->leftJoin('member as b', 'b.id', '=', 'a.user_id')
  67. ->where($where)
  68. ->where(function ($query) use ($params, $userId) {
  69. $type = isset($params['type']) ? $params['type'] : 0;
  70. if ($type > 0) {
  71. $query->where('a.type', $type);
  72. }
  73. $status = isset($params['status']) ? $params['status'] : 0;
  74. if ($status > 0) {
  75. $query->where('a.status', $status);
  76. }
  77. $appectorUid = isset($params['acceptor_uid']) ? $params['acceptor_uid'] : 0;
  78. $uid = isset($params['user_id']) ? $params['user_id'] : 0;
  79. if ($uid > 0) {
  80. $query->where('a.user_id', $uid);
  81. }else if(!$appectorUid){
  82. $query->where('a.user_id', $userId);
  83. }
  84. if ($appectorUid > 0) {
  85. $query->where('a.acceptor_uid', $appectorUid);
  86. }
  87. $appectorId = isset($params['acceptor_id']) ? $params['acceptor_id'] : 0;
  88. if ($appectorId > 0) {
  89. $query->where('a.acceptor_id', $appectorId);
  90. }
  91. })
  92. ->where(function ($query) use ($params) {
  93. $keyword = isset($params['kw']) ? $params['kw'] : '';
  94. if ($keyword) {
  95. $query->where('a.order_no', 'like', "%{$keyword}%")
  96. ->orWhere('b.nickname', 'like', "%{$keyword}%")
  97. ->orWhere('b.id', '=', "%{$keyword}%");
  98. }
  99. })
  100. ->selectRaw($field)
  101. ->orderByRaw($order)
  102. ->paginate($pageSize > 0 ? $pageSize : 9999999);
  103. $list = $list ? $list->toArray() : [];
  104. if ($list && $list['data']) {
  105. foreach ($list['data'] as &$item) {
  106. $item['time_text'] = isset($item['create_time']) ? datetime($item['create_time'], 'Y-m-d H:i') : '';
  107. // $item['time_text'] = isset($item['create_time']) ? dateFormat($item['create_time'], 'Y-m-d H:i') : '';
  108. $member = isset($item['member']) ? $item['member'] : [];
  109. if ($member) {
  110. $member['avatar'] = isset($member['avatar']) && $member['avatar'] ? get_image_url($member['avatar']) : get_image_url('/images/member/logo.png');
  111. }
  112. $item['member'] = $member;
  113. }
  114. }
  115. return [
  116. 'pageSize' => $pageSize,
  117. 'total' => isset($list['total']) ? $list['total'] : 0,
  118. 'list' => isset($list['data']) ? $list['data'] : []
  119. ];
  120. }
  121. /**
  122. * 详情
  123. * @param $id
  124. * @return array
  125. */
  126. public function getInfo($id, $userId = 0, $field = [])
  127. {
  128. $field = $field ? $field : ['a.*'];
  129. $info = $this->model->with(['member', 'acceptor'])->from('trade as a')
  130. ->leftJoin('member as b', 'b.id', '=', 'a.user_id')
  131. ->where(['a.id' => $id, 'a.mark' => 1, 'b.mark' => 1])
  132. ->select($field)
  133. ->first();
  134. $info = $info ? $info->toArray() : [];
  135. if ($info) {
  136. $member = isset($info['member']) ? $info['member'] : [];
  137. if ($member) {
  138. $member['avatar'] = isset($member['avatar']) && $member['avatar'] ? get_image_url($member['avatar']) : get_image_url('/images/member/logo.png');
  139. }
  140. $info['member'] = $member;
  141. $info['time_text'] = isset($info['create_time']) ? dateFormat($info['create_time'], 'Y-m-d H:i') : '';
  142. $info['memberBank'] = MemberBankModel::where(['id' => $info['account_id']])->first();
  143. if (isset($info['memberBank'])) {
  144. $info['memberBank']['qrcode'] = get_image_url($info['memberBank']['qrcode']);
  145. }
  146. $info['custom_uid'] = ConfigService::make()->getConfigByCode('xl_custom_id',100001);
  147. }
  148. return $info;
  149. }
  150. /**
  151. * 状态设置
  152. * @return bool
  153. */
  154. public function status()
  155. {
  156. $id = request()->post('id', 0);
  157. $status = request()->post('status', 1);
  158. if ($id && !$this->model->where(['id' => $id, 'mark' => 1])->value('id')) {
  159. $this->error = 2981;
  160. return false;
  161. }
  162. if ($this->model->where(['id' => $id, 'mark' => 1])->update(['status' => $status, 'update_time' => time()])) {
  163. $this->error = 1002;
  164. return true;
  165. }
  166. $this->error = 1003;
  167. return true;
  168. }
  169. /**
  170. * 删除
  171. * @return bool
  172. */
  173. public function delete()
  174. {
  175. // 参数
  176. $param = request()->all();
  177. $id = getter($param, "id");
  178. if (empty($id)) {
  179. $this->error = 2014;
  180. return false;
  181. }
  182. if (!$this->model->where(['id' => $id])->value('id')) {
  183. $this->error = 1039;
  184. return false;
  185. }
  186. if ($this->model->where(['id' => $id])->update(['mark' => 0, 'update_time' => time()])) {
  187. $this->model->where(['mark' => 0])->where('update_time', '<=', time() - 3 * 86400)->delete();
  188. $this->error = 1025;
  189. return true;
  190. } else {
  191. $this->error = 1026;
  192. return false;
  193. }
  194. }
  195. /**
  196. * C2C交易,确认
  197. * @param $userId
  198. * @param $params
  199. * @return array|false
  200. */
  201. public function confirm($userId, $params)
  202. {
  203. $cacheKey = "caches:trade:confirm:lock_{$userId}";
  204. $role = isset($params['role']) ? trim($params['role']) : '';
  205. if (RedisService::get($cacheKey)) {
  206. $this->error = 1034;
  207. return false;
  208. }
  209. // 交易订单记录
  210. $info = $this->getInfo($params['id']);
  211. if (!in_array($info['status'], [1, 2])) {
  212. $this->error = 1003;
  213. return false;
  214. }
  215. $confirmUser = '';
  216. // 购买 确认付款是用户user_id 确认完成是承兑商acceptor_uid
  217. // 卖出 确认付款是承兑商acceptor_uid 确认完成是用户user_id
  218. if (($info['type'] == 1 && $info['status'] == 1) || ($info['type'] == 2 && $info['status'] == 2)) {
  219. $confirmUser = $info['user_id'];
  220. }
  221. if (($info['type'] == 1 && $info['status'] == 2) || ($info['type'] == 2 && $info['status'] == 1)) {
  222. $confirmUser = $info['user_id'];
  223. }
  224. if ($info['type'] == 1) {
  225. if ($info['status'] == 1) {
  226. $confirmUser = $info['acceptor_uid'];
  227. }
  228. if ($info['status'] == 2) {
  229. $confirmUser = $info['acceptor_uid'];
  230. }
  231. }
  232. // 卖出, 确认收款主体是用户
  233. $member = MemberModel::where(['id' => $confirmUser])->first();
  234. if (empty($member)) {
  235. $this->error = 1003;
  236. return false;
  237. }
  238. // 确认密码
  239. $payPassword = isset($params['pay_password']) ? trim($params['pay_password']) : '';
  240. if ($member['pay_password'] != get_password($payPassword)) {
  241. $this->error = 2038;
  242. return false;
  243. }
  244. // 星豆
  245. DB::beginTransaction();
  246. RedisService::set($cacheKey, $info, rand(2, 3));
  247. // 买入
  248. // 更新trade状态
  249. // 更新account 状态
  250. // 更新member.balance
  251. if ($info['status'] == 1) {
  252. TradeModel::where(['id' => $info['id']])->update(['update_time' => time(), 'remark' => ($info['type'] == 1 ? '购买' : '卖出') . '星豆,订单已付款', 'status' => 2]);
  253. // 消息
  254. if ($info['type'] == 1) {
  255. MessageService::make()->pushMessage($userId, '星豆购买已确认', "您在{$info['create_time']}(UTC+8)下单¥{$info['total']}购买{$info['num']}星豆,已确认付款", 3);
  256. } else {
  257. MessageService::make()->pushMessage($userId, '星豆卖出已确认', "您在{$info['create_time']}(UTC+8)下单¥{$info['total']}卖出{$info['num']}星豆,已确认付款", 3);
  258. }
  259. }
  260. // 订单已完成,放币
  261. if ($info['status'] == 2) {
  262. TradeModel::where(['id' => $info['id']])->update(['update_time' => time(), 'remark' => ($info['type'] == 1 ? '购买' : '卖出') . '星豆,订单完成', 'status' => 3]);
  263. if ($info['type'] == 1) {
  264. $updateData = ['balance' => DB::raw("balance + {$info['num']}"), 'update_time' => time()];
  265. if (!MemberModel::where(['id' => $info['user_id']])->update($updateData)) {
  266. $this->error = 2036;
  267. DB::rollBack();
  268. return false;
  269. }
  270. } else {
  271. $updateData = ['quota' => DB::raw("quota + {$info['num']}"), 'update_time' => time()];
  272. if (!AcceptorModel::where(['id' => $info['acceptor_id']])->update($updateData)) {
  273. $this->error = 2036;
  274. DB::rollBack();
  275. return false;
  276. }
  277. }
  278. // 承兑商佣金添加
  279. $acceptorInfo = AcceptorModel::where(['id'=>$info['acceptor_id']])->first();
  280. $updateData = ['usdt' => DB::raw("usdt + {$info['bonus_usdt']}"), 'update_time' => time()];
  281. if (!AcceptorModel::where(['id' => $info['acceptor_id']])->update($updateData)) {
  282. $this->error = 2036;
  283. DB::rollBack();
  284. return false;
  285. }
  286. // 增加accountLog记录
  287. $log = [
  288. 'user_id' => $info['acceptor_id'],
  289. 'source_id' => $info['id'],
  290. 'source_order_no' => $info['order_no'],
  291. 'type' => 10,
  292. 'coin_type' => 1,
  293. 'user_type' => 3,
  294. 'money' => round($info['bonus_usdt'], 4),
  295. 'actual_money' => round($info['bonus_usdt'], 4),
  296. 'balance' => $acceptorInfo['usdt'],
  297. 'create_time' => time(),
  298. 'update_time' => time(),
  299. 'remark' => "C2C交易-承兑商佣金",
  300. 'status' => 1,
  301. 'mark' => 1,
  302. ];
  303. if (!AccountLogModel::insertGetId($log)) {
  304. $this->error = 2407;
  305. DB::rollBack();
  306. RedisService::clear($cacheKey);
  307. return false;
  308. }
  309. // 用户交易获取待返积分
  310. $userInfo = MemberModel::where(['id'=>$info['user_id']])->first();
  311. $c2cRewardPoints = ConfigService::make()->getConfigByCode('c2c_reward_points', 100);
  312. $poins = round( $info['num'] * $c2cRewardPoints/100, 2);
  313. $updateData = ['wait_score' => DB::raw("wait_score + {$poins}"), 'update_time' => time()];
  314. if (!MemberModel::where(['id' => $info['user_id']])->update($updateData)) {
  315. $this->error = 2036;
  316. DB::rollBack();
  317. return false;
  318. }
  319. // 增加accountLog记录
  320. $log = [
  321. 'user_id' => $info['user_id'],
  322. 'source_id' => $info['id'],
  323. 'source_order_no' => $info['order_no'],
  324. 'type' => 102,
  325. 'coin_type' => 4,
  326. 'user_type' => 1,
  327. 'money' => $poins,
  328. 'actual_money' => $poins,
  329. 'balance' => $userInfo['wait_score'],
  330. 'create_time' => time(),
  331. 'update_time' => time(),
  332. 'remark' => "C2C交易-用户待返积分",
  333. 'status' => 1,
  334. 'mark' => 1,
  335. ];
  336. if (!AccountLogModel::insertGetId($log)) {
  337. $this->error = 2407;
  338. DB::rollBack();
  339. RedisService::clear($cacheKey);
  340. return false;
  341. }
  342. // 消息
  343. if ($info['type'] == 1) {
  344. MessageService::make()->pushMessage($userId, '星豆购买已完成', "您在{$info['create_time']}(UTC+8)下单¥{$info['total']}购买{$info['num']}星豆,已成功到账", 3);
  345. } else {
  346. MessageService::make()->pushMessage($userId, '星豆卖出已完成', "您在{$info['create_time']}(UTC+8)下单¥{$info['total']}卖出{$info['num']}星豆,已成功扣减", 3);
  347. }
  348. }
  349. DB::commit();
  350. $this->error = 2037;
  351. RedisService::clear($cacheKey);
  352. return ['trade_id' => $info['id']];
  353. }
  354. /**
  355. * 取消订单
  356. * @param $userId
  357. * @param $params
  358. * @return bool
  359. */
  360. public function cancel($userId, $params)
  361. {
  362. $id = request()->post('id', 0);
  363. $type = request()->post('type', 1);
  364. if (!$id || !$info = $this->model->where(['id' => $id, 'mark' => 1])->select(['id','user_id','num','acceptor_id','acceptor_uid','status'])->first()) {
  365. $this->error = 3031;
  366. return false;
  367. }
  368. if($info['status'] != 1){
  369. $this->error = 3032;
  370. return false;
  371. }
  372. if($userId && ($userId != $info['user_id'] || $userId != $info['acceptor_uid'])){
  373. $this->error = 2913;
  374. return false;
  375. }
  376. if($type <=0){
  377. $this->error = 3033;
  378. return false;
  379. }
  380. DB::beginTransaction();
  381. if ($this->model->where(['id' => $id, 'mark' => 1])->update(['status' => -1,'cancel_type'=> $type, 'update_time' => time()])) {
  382. $this->error = 1002;
  383. DB::rollBack();
  384. return true;
  385. }
  386. // 买,返还承兑商额度
  387. if($info['type'] == 1){
  388. $acceptor = AcceptorModel::where(['id'=> $info['acceptor_id']])->select(['id','usdt','quota'])->first();
  389. $updateData = ['quota'=> DB::raw("quota + {$info['num']}"),'update_time'=>time()];
  390. if(!AcceptorModel::where(['id'=> $info['acceptor_id']])->update($updateData)){
  391. $this->error = 1002;
  392. DB::rollBack();
  393. return true;
  394. }
  395. $log = [
  396. 'user_id' => $info['acceptor_id'],
  397. 'source_id' => $info['user_id'],
  398. 'source_order_no' => $info['order_no'],
  399. 'type' => 101,
  400. 'coin_type' => 6,
  401. 'user_type' => 3,
  402. 'money' => $info['num'],
  403. 'actual_money' => $info['num'],
  404. 'balance' => $acceptor['quota'],
  405. 'create_time' => time(),
  406. 'update_time' => time(),
  407. 'remark' => "取消交易-退还交易额度",
  408. 'status' => 1,
  409. 'mark' => 1,
  410. ];
  411. if (!AccountLogModel::insertGetId($log)) {
  412. $this->error = 2407;
  413. DB::rollBack();
  414. return false;
  415. }
  416. }else if($info['type'] == 2){
  417. $userInfo = MemberModel::where(['id'=> $info['user_id']])->select(['id','usdt','balance'])->first();
  418. $updateData = ['balance'=> DB::raw("balance + {$info['num']}"),'update_time'=>time()];
  419. if(!MemberModel::where(['id'=> $info['user_id']])->update($updateData)){
  420. $this->error = 1002;
  421. DB::rollBack();
  422. return true;
  423. }
  424. $log = [
  425. 'user_id' => $info['user_id'],
  426. 'source_id' => $info['acceptor_id'],
  427. 'source_order_no' => $info['order_no'],
  428. 'type' => 101,
  429. 'coin_type' => 6,
  430. 'user_type' => 3,
  431. 'money' => $info['num'],
  432. 'actual_money' => $info['num'],
  433. 'balance' => $userInfo['balance'],
  434. 'create_time' => time(),
  435. 'update_time' => time(),
  436. 'remark' => "取消交易-退还星豆",
  437. 'status' => 1,
  438. 'mark' => 1,
  439. ];
  440. if (!AccountLogModel::insertGetId($log)) {
  441. $this->error = 2407;
  442. DB::rollBack();
  443. return false;
  444. }
  445. }
  446. DB::commit();
  447. $this->error = 1003;
  448. return true;
  449. }
  450. }