PayOrdersService.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. <?php
  2. namespace App\Services\Common;
  3. use App\Models\ActionLogModel;
  4. use App\Models\PayOrdersModel;
  5. use App\Services\Api\SettleService;
  6. use App\Services\BaseService;
  7. use App\Services\DyrPayService;
  8. use App\Services\PaymentService;
  9. use App\Services\RedisService;
  10. use Illuminate\Support\Facades\DB;
  11. /**
  12. * 充值缴费订单服务
  13. */
  14. class PayOrdersService extends BaseService
  15. {
  16. /**
  17. * 构造函数
  18. * @author laravel开发员
  19. * @since 2020/11/11
  20. * AccountService constructor.
  21. */
  22. public function __construct()
  23. {
  24. $this->model = new PayOrdersModel();
  25. }
  26. /**
  27. * 获取列表
  28. */
  29. public function getList()
  30. {
  31. $params = request()->all();
  32. $page = $params['page'] ?? 1;
  33. $limit = $params['limit'] ?? 20;
  34. $type = $params['type'] ?? '';
  35. $status = $params['status'] ?? '';
  36. $keyword = $params['keyword'] ?? '';
  37. $startTime = $params['start_time'] ?? '';
  38. $endTime = $params['end_time'] ?? '';
  39. $query = PayOrdersModel::where('mark', 1);
  40. // 类型筛选
  41. if ($type !== '') {
  42. $query->where('type', $type);
  43. }
  44. // 状态筛选
  45. if ($status !== '') {
  46. $query->where('status', $status);
  47. }
  48. // 关键词搜索
  49. if (!empty($keyword)) {
  50. $query->where(function ($q) use ($keyword) {
  51. $q->where('order_no', 'like', "%{$keyword}%")
  52. ->orWhere('account', 'like', "%{$keyword}%")
  53. ->orWhere('transaction_id', 'like', "%{$keyword}%")
  54. ->orWhereHas('user', function ($sq) use ($keyword) {
  55. $sq->where('nickname', 'like', "%{$keyword}%")
  56. ->orWhere('mobile', 'like', "%{$keyword}%");
  57. });
  58. });
  59. }
  60. // 时间范围
  61. if (!empty($startTime)) {
  62. $query->where('create_time', '>=', strtotime($startTime));
  63. }
  64. if (!empty($endTime)) {
  65. $query->where('create_time', '<=', strtotime($endTime . ' 23:59:59'));
  66. }
  67. $total = $query->count();
  68. $list = $query->with(['user:id,nickname,mobile','recUser'])
  69. ->orderBy('create_time', 'desc')
  70. ->offset(($page - 1) * $limit)
  71. ->limit($limit)
  72. ->get()
  73. ->toArray();
  74. // 格式化数据
  75. foreach ($list as &$item) {
  76. $item['total'] = number_format($item['total'], 2, '.', '');
  77. $item['discount'] = number_format($item['discount'], 2, '.', '');
  78. $item['pay_total'] = number_format($item['pay_total'], 2, '.', '');
  79. $item['charge_amount'] = number_format($item['charge_amount'] ?? 0, 2, '.', '');
  80. $item['refund_money'] = number_format($item['refund_money'] ?? 0, 2, '.', '');
  81. $item['create_time_text'] = date('Y-m-d H:i:s', strtotime($item['create_time']));
  82. $item['update_time_text'] = date('Y-m-d H:i:s', strtotime($item['update_time']));
  83. $item['pay_at_text'] = $item['pay_at'] ? date('Y-m-d H:i:s', strtotime($item['pay_at'])) : '-';
  84. // 用户信息
  85. if (isset($item['user'])) {
  86. $item['user_nickname'] = $item['user']['nickname'] ?? '';
  87. $item['user_mobile'] = $item['user']['mobile'] ?? '';
  88. }
  89. }
  90. return [
  91. 'code' => 0,
  92. 'msg' => '获取成功',
  93. 'data' => $list,
  94. 'count' => $total
  95. ];
  96. }
  97. /**
  98. * 获取详情
  99. */
  100. public function getInfo($id = null)
  101. {
  102. if ($id === null) {
  103. $id = request()->input('id');
  104. }
  105. $info = PayOrdersModel::where('id', $id)
  106. ->where('mark', 1)
  107. ->with(['user:id,nickname,mobile', 'meal','recUser'])
  108. ->first();
  109. if (!$info) {
  110. return ['code' => 1, 'msg' => '记录不存在'];
  111. }
  112. $info = $info->toArray();
  113. $info['total'] = number_format($info['total'], 2, '.', '');
  114. $info['discount'] = number_format($info['discount'], 2, '.', '');
  115. $info['pay_total'] = number_format($info['pay_total'], 2, '.', '');
  116. $info['charge_amount'] = number_format($info['charge_amount'] ?? 0, 2, '.', '');
  117. $info['refund_money'] = number_format($info['refund_money'] ?? 0, 2, '.', '');
  118. $info['create_time_text'] = date('Y-m-d H:i:s', (int)$info['create_time']);
  119. $info['update_time_text'] = date('Y-m-d H:i:s', (int)$info['update_time']);
  120. $info['pay_at_text'] = $info['pay_at'] ? date('Y-m-d H:i:s', strtotime($info['pay_at'])) : '-';
  121. // 三要素验证方式文本
  122. $ytypeMap = [1 => '身份证后6位', 2 => '银行卡后6位', 3 => '营业执照后6位'];
  123. $info['ytype_text'] = $ytypeMap[$info['ytype'] ?? 0] ?? '-';
  124. // 用户信息
  125. if (isset($info['user'])) {
  126. $info['user_nickname'] = $info['user']['nickname'] ?? '';
  127. $info['user_mobile'] = $info['user']['mobile'] ?? '';
  128. }
  129. return [
  130. 'code' => 0,
  131. 'msg' => '获取成功',
  132. 'data' => $info
  133. ];
  134. }
  135. /**
  136. * 删除
  137. */
  138. public function delete()
  139. {
  140. $id = request()->input('id');
  141. $order = PayOrdersModel::where('id', $id)
  142. ->where('mark', 1)
  143. ->first();
  144. if (!$order) {
  145. return ['code' => 1, 'msg' => '记录不存在'];
  146. }
  147. $order->mark = 0;
  148. $order->save();
  149. return ['code' => 0, 'msg' => '删除成功'];
  150. }
  151. /**
  152. * 批量删除
  153. */
  154. public function deleteAll($ids = null)
  155. {
  156. if ($ids === null) {
  157. $ids = request()->input('ids', []);
  158. }
  159. $count = PayOrdersModel::whereIn('id', $ids)
  160. ->where('mark', 1)
  161. ->update(['mark' => 0]);
  162. return [
  163. 'code' => 0,
  164. 'msg' => "成功删除{$count}条记录"
  165. ];
  166. }
  167. /**
  168. * 已支付或充值中的订单
  169. * @return array|mixed
  170. */
  171. public function getCheckOrderList()
  172. {
  173. $cacheKey = "caches:orders:payCheckList";
  174. $datas = RedisService::get($cacheKey);
  175. if ($datas) {
  176. return $datas;
  177. }
  178. $datas = $this->model->where(['mark' => 1])
  179. ->whereIn('status', [2, 3])
  180. ->select(['id', 'order_no', 'transaction_id', 'pay_total as money', 'status'])
  181. ->orderBy('id', 'desc')
  182. ->limit(500)
  183. ->get()
  184. ->keyBy('order_no');
  185. $datas = $datas ? $datas->toArray() : [];
  186. if ($datas) {
  187. $datas = array_chunk($datas, 100);
  188. RedisService::set($cacheKey, $datas, rand(20, 30));
  189. }
  190. return $datas;
  191. }
  192. /**
  193. * 已支付充值失败退款失败订单
  194. * @return array|mixed
  195. */
  196. public function getFailedOrderList()
  197. {
  198. $cacheKey = "caches:orders:failedList";
  199. $datas = RedisService::get($cacheKey);
  200. if ($datas) {
  201. return $datas;
  202. }
  203. $datas = $this->model->where(['refund_status'=>3,'status'=>5,'mark' => 1])
  204. ->select(['id', 'order_no', 'transaction_id', 'pay_total as money', 'status'])
  205. ->orderBy('id', 'desc')
  206. ->limit(500)
  207. ->get()
  208. ->keyBy('order_no');
  209. $datas = $datas ? $datas->toArray() : [];
  210. if ($datas) {
  211. $datas = array_chunk($datas, 100);
  212. RedisService::set($cacheKey, $datas, rand(20, 30));
  213. }
  214. return $datas;
  215. }
  216. /**
  217. * 充值订单退款(补充处理)
  218. * @param $orders
  219. * @return array
  220. * @throws \Yansongda\Pay\Exception\ContainerException
  221. * @throws \Yansongda\Pay\Exception\InvalidParamsException
  222. * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
  223. */
  224. public function failedOrderRefund($orders)
  225. {
  226. $success = [];
  227. if ($orders) {
  228. foreach ($orders as $order) {
  229. $total = isset($order['money']) ? $order['money'] : 0;
  230. $refundStatus = PaymentService::make()->refund($order, 'pay');
  231. $updateData = ['refund_status' => $refundStatus ? 1 : 3, 'status' => 5, 'failed_remark' => '充值失败原路退款','refund_remark'=>PaymentService::make()->getError(), 'refund_money' => $refundStatus ? $total : 0,'refund_at'=>date('Y-m-d H:i:s'), 'update_time' => time()];
  232. if (!PayOrdersModel::where(['id' => $order['id']])->update($updateData)) {
  233. $errors[$order['order_no']] = '充值失败退款处理失败';
  234. } else {
  235. $success[$order['order_no']] = "退款{$total}成功";
  236. $errors[$order['order_no']] = $refundStatus ? '充值失败原路退款' : '充值失败退款失败';
  237. }
  238. sleep(2);
  239. }
  240. }
  241. if($success){
  242. RedisService::clear("caches:orders:failedList");
  243. }
  244. $this->error = '充值订单退款处理成功';
  245. return ['success' => $success, 'errors' => $errors];
  246. }
  247. /**
  248. * 验证订单状态
  249. * @param $orders
  250. * @return array
  251. * @throws \Yansongda\Pay\Exception\ContainerException
  252. * @throws \Yansongda\Pay\Exception\InvalidParamsException
  253. * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
  254. */
  255. public function checkOrder($orders)
  256. {
  257. $nos = array_keys($orders);
  258. $noStr = implode(',', $nos);
  259. $result = DyrPayService::make()->query($noStr);
  260. $datas = isset($result['data']) ? $result['data'] : [];
  261. $errors = [];
  262. $success = [];
  263. if ($datas) {
  264. foreach ($datas as $item) {
  265. $no = isset($item['out_trade_num']) ? $item['out_trade_num'] : '';
  266. $remark = isset($item['remark']) ? $item['remark'] : '充值失败';
  267. $order_number = isset($item['order_number']) ? $item['order_number'] : '';
  268. $charge_amount = isset($item['charge_amount']) ? $item['charge_amount'] : 0;
  269. $charge_kami = isset($item['charge_kami']) ? $item['charge_kami'] : '';
  270. $state = isset($item['state']) ? $item['state'] : -1;
  271. if (in_array($state, [1, 3])) {
  272. $success[$no] = $state;
  273. $updateData = ['status' => $state == 3 ? 6 : 4, 'order_trade_no' => $order_number, 'charge_kami' => $charge_kami, 'charge_amount' => $charge_amount, 'update_time' => time()];
  274. if (!PayOrdersModel::where(['order_no' => $no])->update($updateData)) {
  275. $errors[$no] = '充值处理失败';
  276. }
  277. unset($orders[$no]);
  278. } else if ($state == 0) {
  279. unset($orders[$no]);
  280. $errors[$no] = '充值中';
  281. } else {
  282. $errors[$no] = $remark;
  283. }
  284. }
  285. }
  286. // 未查询到充值记录,批量退款
  287. if ($orders) {
  288. foreach ($orders as $order) {
  289. $total = isset($order['money']) ? $order['money'] : 0;
  290. $refundStatus = PaymentService::make()->refund($order, 'pay');
  291. $updateData = ['refund_status' => $refundStatus ? 1 : 3, 'status' => 5, 'failed_remark' => '充值失败原路退款','refund_remark'=>PaymentService::make()->getError(), 'refund_money' => $refundStatus ? $total : 0,'refund_at'=>date('Y-m-d H:i:s'), 'update_time' => time()];
  292. if (!PayOrdersModel::where(['id' => $order['id']])->update($updateData)) {
  293. $errors[$order['order_no']] = '充值失败退款处理失败';
  294. } else {
  295. $errors[$order['order_no']] = $refundStatus ? '充值失败原路退款' : '充值失败退款失败';
  296. }
  297. sleep(2);
  298. }
  299. }
  300. $this->error = '订单状态验证处理成功';
  301. return ['success' => $success, 'errors' => $errors];
  302. }
  303. /**
  304. * 取消订单
  305. */
  306. public function settleOrder()
  307. {
  308. $id = request()->post('id');
  309. if (!$id) {
  310. return ['code' => 1, 'msg' => '参数错误'];
  311. }
  312. $cacheLockKey = "caches:orders:pay_settle_".$id.'_lock';
  313. if(RedisService::get($cacheLockKey)){
  314. return ['code' => 1, 'msg' => '结算中'];
  315. }
  316. $order = $this->model->find($id);
  317. $orderNo = isset($order['order_no'])?$order['order_no']:'';
  318. $userId = isset($order['user_id'])?$order['user_id']:0;
  319. if (!$order) {
  320. return ['code' => 1, 'msg' => '订单不存在'];
  321. }
  322. if ($order->bonus_settle == 1) {
  323. return ['code' => 1, 'msg' => '佣金收益已结算'];
  324. }
  325. if ($order->status != 4) {
  326. return ['code' => 1, 'msg' => '订单未完成'];
  327. }
  328. RedisService::set($cacheLockKey, $order, rand(10,20));
  329. DB::beginTransaction();
  330. // 代理佣金结算
  331. $result = SettleService::make()->agentBonus($userId, $order['rec_bonus'], $order, $order['rec_bonus_id']);
  332. if ($result < 0) {
  333. DB::rollBack();
  334. $this->error = SettleService::make()->getError();
  335. RedisService::clear($cacheLockKey);
  336. \App\Services\Api\OrderService::make()->saveLog("caches:settle:{$orderNo}:agent_{$userId}_error",SettleService::make()->getError());
  337. return false;
  338. }
  339. \App\Services\Api\OrderService::make()->saveLog("caches:settle:{$orderNo}:agent_{$userId}",$result);
  340. DB::commit();
  341. ActionLogModel::setTitle("订单结算");
  342. ActionLogModel::record();
  343. RedisService::keyDel("caches:orders:*");
  344. return ['code' => 0, 'msg' => '订单结算'];
  345. }
  346. }