CronLogic.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. <?php
  2. namespace App\Http\Logic\Cron;
  3. use App\Exceptions\CommonException;
  4. use App\Http\Bean\Cron\logic\HandleOrderParamBean;
  5. use App\Http\Bean\Util\Jutuike\GetOrderListParamBean;
  6. use App\Http\Bean\Util\Meituan\OrderListParamBean;
  7. use App\Http\Bean\Util\Pdd\Ddk\OrderListIncrementGetParamBean;
  8. use App\Http\Enum\ErrorEnum;
  9. use App\Http\Enum\OrderStatusEnum;
  10. use App\Http\Enum\PlatformTypeEnum;
  11. use App\Http\Logic\BaseLogic;
  12. use App\Http\Logic\Order\OrderLogic;
  13. use App\Http\Utils\BaseUtil;
  14. use App\Http\Utils\Jutuike\JutuikeUtil;
  15. use App\Http\Utils\LoggerFactoryUtil;
  16. use App\Http\Utils\Meituan\MeituanLianmengUtil;
  17. use App\Http\Utils\Pdd\DuoDuoKeUtil;
  18. use App\Http\Utils\WechatAccountUtil;
  19. use App\Models\CategoryModel;
  20. use App\Models\UserCashModel;
  21. use App\Models\UserFinanceModel;
  22. use App\Models\UserModel;
  23. use App\Models\UserOrderCommissionModel;
  24. use App\Models\UserOrderModel;
  25. use App\Models\WechatAccountModel;
  26. use EasyWeChat\Factory;
  27. use Illuminate\Support\Facades\DB;
  28. class CronLogic extends BaseLogic
  29. {
  30. /**
  31. * 获取美团订单
  32. */
  33. public static function meituanOrderslogic()
  34. {
  35. $params = request()->all();
  36. $arr = [
  37. "appkey"=>env("MEITUAN_LIANMENG_KEY"),
  38. "type"=>$params["order_type"],
  39. "startTime"=>time()-$params["minute"]*60,
  40. "endTime"=>time(),
  41. // "startTime"=>strtotime("2021-09-22 11:25:00"),
  42. // "endTime"=>time(),
  43. "page"=>1,
  44. "limit"=>30,
  45. "queryTimeType"=>2,
  46. ];
  47. $instance = new LoggerFactoryUtil(CronLogic::class);
  48. $instance->info("获取订单数据开始");
  49. $bean = new OrderListParamBean($arr);
  50. $res = MeituanLianmengUtil::orderList($bean);
  51. // dd($res);
  52. $instance->info("美团返回数据:".json_encode($res));
  53. $instance->info("订单数量:".$res["total"]);
  54. if($res){
  55. //存在数据,写入订单数据表
  56. if($res["total"]){
  57. $instance->info("订单数据:".json_encode($res));
  58. BaseUtil::sendBaoJing("","获取到订单数量:".$res["total"],"定时获取美团订单");
  59. //处理订单
  60. self::checkOrder($res["dataList"],$params["order_type"]);
  61. //判断订单数量是否大于分页
  62. $pageNum = ceil($res["total"]/100)-1;
  63. if($pageNum){
  64. for ($i=1;$i<=$pageNum;$i++){
  65. $arr["page"]++;
  66. $bean = new OrderListParamBean($arr);
  67. $res = MeituanLianmengUtil::orderList($bean);
  68. if ($res) {
  69. //存在数据,写入订单数据表
  70. if ($res["total"]) {
  71. self::checkOrder($res["dataList"],$params["order_type"]);
  72. }
  73. }
  74. }
  75. }
  76. }
  77. }
  78. }
  79. /**
  80. * 处理订单
  81. */
  82. protected static function checkOrder($orders,$orderType)
  83. {
  84. foreach ($orders as $data) {
  85. switch ($data["status"]) {
  86. case 1://已付款
  87. $orderStatus = OrderStatusEnum::ALREADY_PAY;
  88. break;
  89. case 8://已收货
  90. $orderStatus = OrderStatusEnum::ALREADY_RECEIVE;
  91. break;
  92. case 9://已退款或风控
  93. $orderStatus = OrderStatusEnum::ALREADY_REFUND;
  94. break;
  95. }
  96. $params = [
  97. "spreadSonType" => 0,//订单子类型
  98. "orderNumber" => $data["orderid"],//订单编号
  99. "payTime" => date("Y-m-d H:i:s", $data["paytime"]),//支付时间
  100. "orderPrice" => $data["payprice"] * 100,//订单金额
  101. "orderCommission" => $data["profit"] * 100,//订单佣金
  102. "orderTitle" => $data["smstitle"],//订单标题
  103. "orderRefundPrice" => isset($data["refundprice"]) ? $data["refundprice"] * 100 : 0,//退款金额
  104. "orderRefundTime" => isset($data["refundtime"]) ? date("Y-m-d H:i:s", $data["refundtime"]) : null,//退款时间
  105. "orderRefundCommission" => isset($data["refundprofit"]) ? $data["refundprofit"] : 0,//退款佣金
  106. "orderStatus" => $orderStatus,//订单状态
  107. "orderCouponPrice" => 0,//订单优惠
  108. "productImgUrl" => "https://pic.rmb.bdstatic.com/bjh/f049242a789a22fb1a412bb6418c52e2.jpeg",//商品图片
  109. "spreadType"=>PlatformTypeEnum::PLATFORM_MEITUAN,//订单类型
  110. "userSpreadId"=>$data["sid"],//用户推广位
  111. "platformSpreadId"=>$data["sid"],//平台推广位
  112. "createdAt"=>date("Y-m-d H:i:s", $data["paytime"])
  113. ];
  114. $bean = new HandleOrderParamBean($params);
  115. OrderLogic::handleOrderLogic($bean);
  116. }
  117. }
  118. /**
  119. * 聚推客订单逻辑
  120. */
  121. public static function jutuikeOrdersLogic()
  122. {
  123. $params = request()->all();
  124. $startTime = date("Y-m-d H:i:s",time()-600);
  125. $endTime = date("Y-m-d H:i:s");
  126. if(isset($params["start_time"])){
  127. $startTime = $params["start_time"];
  128. }
  129. if (isset($params["end_time"])){
  130. $endTime= $params["end_time"];
  131. }
  132. $page = 1;
  133. $params = [
  134. "start_time"=>$startTime,
  135. "end_time"=>$endTime,
  136. "query_type"=>2,
  137. "page"=>$page,
  138. "pageSize"=>100
  139. ];
  140. $bean = new GetOrderListParamBean($params);
  141. $data = JutuikeUtil::getOrderList($bean);
  142. $instance = new LoggerFactoryUtil(CronLogic::class);
  143. $instance->info("上游返回数据:".json_encode($data));
  144. if($data["code"]!=1){
  145. //上游错误
  146. return;
  147. }
  148. //判断是否存在订单
  149. $orderLists = $data["data"]["data"];
  150. if(count($orderLists)){
  151. BaseUtil::sendBaoJing("","获取到订单数量:".count($orderLists),"定时获取聚推客订单");
  152. }
  153. foreach ($orderLists as $orderList){
  154. self::handleOrderLogic($orderList);
  155. }
  156. }
  157. public static function handleOrderLogic($orderList)
  158. {
  159. //判断订单状态
  160. switch ($orderList["status"]){
  161. case 0://未付款
  162. $orderStatus = OrderStatusEnum::PRE_PAY;
  163. break;
  164. case 1://已付款
  165. $orderStatus = OrderStatusEnum::ALREADY_PAY;
  166. break;
  167. case 2://待结算
  168. $orderStatus = OrderStatusEnum::ALREADY_RECEIVE;
  169. break;
  170. case 3://已结算
  171. $orderStatus = OrderStatusEnum::ALREADY_FINISH;
  172. break;
  173. case 4://无效订单
  174. $orderStatus = OrderStatusEnum::ALREADY_CANCEL;
  175. break;
  176. }
  177. //获取活动图片
  178. $actImgUrl = CategoryModel::query()
  179. ->where("platform_type",PlatformTypeEnum::PLATFORM_JUTUIKE)
  180. ->where("activity_id",$orderList["act_id"])
  181. ->value("category_img_url");
  182. $params = [
  183. "spreadSonType" => 0,//订单子类型
  184. "orderNumber" => $orderList["order_sn"],//订单编号
  185. "payTime" => $orderList["pay_time"],//支付时间
  186. "orderPrice" => $orderList["order_price"] * 100,//订单金额
  187. "orderCommission" => $orderList["jtk_share_fee"] * 100,//订单佣金
  188. "orderTitle" => $orderList["order_title"],//订单标题
  189. "orderRefundPrice" => 0,//退款金额
  190. "orderRefundTime" => null,//退款时间
  191. "orderRefundCommission" => 0,//退款佣金
  192. "orderStatus" => $orderStatus,//订单状态
  193. "orderCouponPrice" => 0,//订单优惠
  194. "productImgUrl" => $actImgUrl,//商品图片
  195. "spreadType"=>PlatformTypeEnum::PLATFORM_JUTUIKE,//订单类型
  196. "userSpreadId"=>$orderList["sid"],//用户推广位
  197. "platformSpreadId"=>$orderList["sid"],//平台推广位
  198. "createdAt"=>$orderList["create_time"],//订单创建时间
  199. ];
  200. $bean = new HandleOrderParamBean($params);
  201. OrderLogic::handleOrderLogic($bean);
  202. }
  203. /**
  204. * 获取拼多多订单逻辑
  205. */
  206. public static function pddOrdersLogic()
  207. {
  208. $params = [
  209. "startUpdateTime"=>time()-600,
  210. "endUpdateTime"=>time()
  211. ];
  212. $bean = new OrderListIncrementGetParamBean($params);
  213. $res = DuoDuoKeUtil::orderListIncrementGet($bean);
  214. $instance = new LoggerFactoryUtil(CronLogic::class);
  215. $instance->info("上游返回信息:".json_encode($res));
  216. if (isset($res["error_response"])){
  217. return;
  218. }
  219. if($res["order_list_get_response"]["total_count"]){
  220. BaseUtil::sendBaoJing("","获取到订单数量:".$res["order_list_get_response"]["total_count"],"定时获取拼多多订单");
  221. }
  222. //获取数据
  223. $datas = $res["order_list_get_response"]["order_list"];
  224. foreach ($datas as $orderList){
  225. switch ($orderList["order_status"]){
  226. case 0:
  227. //已支付
  228. $orderStatus = OrderStatusEnum::ALREADY_PAY;
  229. break;
  230. case 1:
  231. //已成团
  232. $orderStatus = OrderStatusEnum::ALREADY_PAY;
  233. break;
  234. case 2:
  235. //确认收货
  236. $orderStatus = OrderStatusEnum::ALREADY_RECEIVE;
  237. break;
  238. case 3:
  239. //审核成功
  240. $orderStatus = OrderStatusEnum::ALREADY_RECEIVE;
  241. break;
  242. case 4:
  243. //审核失败(不可提现)
  244. $orderStatus = OrderStatusEnum::ALREADY_CANCEL;
  245. break;
  246. case 5:
  247. //已经结算
  248. $orderStatus = OrderStatusEnum::ALREADY_RECEIVE;
  249. break;
  250. case 10:
  251. //已处罚
  252. $orderStatus = OrderStatusEnum::ALREADY_CANCEL;
  253. break;
  254. }
  255. $params = [
  256. "spreadSonType" => 0,//订单子类型
  257. "orderNumber" => $orderList["order_sn"],//订单编号
  258. "payTime" => date("Y-m-d H:i:s",$orderList["order_pay_time"]),//支付时间
  259. "orderPrice" => $orderList["order_amount"],//订单金额
  260. "orderCommission" => $orderList["promotion_amount"],//订单佣金
  261. "orderTitle" => $orderList["goods_name"],//订单标题
  262. "orderRefundPrice" => 0,//退款金额
  263. "orderRefundTime" => null,//退款时间
  264. "orderRefundCommission" => 0,//退款佣金
  265. "orderStatus" => $orderStatus,//订单状态
  266. "orderCouponPrice" => 0,//订单优惠
  267. "productImgUrl" => "https://pic.rmb.bdstatic.com/bjh/6d9fb4a81eb5fc933da8949854c4fab2.jpeg",//商品图片
  268. "spreadType"=>PlatformTypeEnum::PLATFORM_PINGDUODUO,//订单类型
  269. "userSpreadId"=>$orderList["p_id"],//用户推广位
  270. "platformSpreadId"=>$orderList["p_id"],//平台推广位
  271. "createdAt"=>date("Y-m-d H:i:s",$orderList["order_create_time"]),//订单创建时间
  272. ];
  273. $bean = new HandleOrderParamBean($params);
  274. OrderLogic::handleOrderLogic($bean);
  275. }
  276. }
  277. /**
  278. * 发送用户下单模版
  279. */
  280. public static function sendOrderTemplateLogic()
  281. {
  282. $instance = new LoggerFactoryUtil(CronLogic::class);
  283. //1.新增粉丝通知
  284. $userFans = UserModel::query()
  285. ->where("invite_user_id","<>",0)
  286. ->where("user_notify_status",0)
  287. ->get();
  288. foreach ($userFans as $userFan){
  289. //获取推荐人
  290. $inviteUser = UserModel::findById($userFan->invite_user_id);
  291. if($inviteUser){
  292. try{
  293. //获取公众号实例
  294. $app = WechatAccountUtil::getAppByID($userFan->wechat_account_id);
  295. $data = [
  296. 'touser' => $inviteUser->user_open_id,
  297. 'template_id' => env("WECHAT_FANS_TEMPLATE_URL"),
  298. 'url' => env("WECHAT_FANS_URL"),
  299. 'data' => [
  300. 'first' => "亲,您有新的粉丝",
  301. 'keyword1' => $userFan->user_nickname,
  302. 'keyword2' => $userFan->id+100000,
  303. "remark"=>"粉丝将提供分享佣金,粉丝越多比例越高哦,点击查看详情"
  304. ],
  305. ];
  306. $res = $app->template_message->send($data);
  307. $instance->info("粉丝通知微信返回结果:".json_encode($res));
  308. }catch (\Throwable $exception){
  309. $instance->info("粉丝通知结果异常:".$exception->getMessage());
  310. }
  311. UserModel::query()->where("id",$userFan->id)->update(
  312. [
  313. "user_notify_status"=>1
  314. ]
  315. );
  316. }
  317. }
  318. //2.获取自购已支付且未通知进行模版推送
  319. $orders = UserOrderCommissionModel::query()
  320. ->where("commission_status",0)
  321. ->where("order_commission",">",0)
  322. ->where("user_id","<>",0)
  323. ->where("order_notify_status",0)
  324. ->limit(10)
  325. ->get();
  326. foreach ($orders as $order){
  327. //判断是否自购订单
  328. if($order->user_provider_id){
  329. //反佣订单
  330. $user = UserModel::findById($order->user_id);
  331. if($user){
  332. try{
  333. //获取公众号实例
  334. $app = WechatAccountUtil::getAppByID($user->wechat_account_id);
  335. $tmpOrder = UserOrderModel::query()->where("order_number",$order->order_number)->first();
  336. $privideUser = UserModel::findById($order->user_provider_id);
  337. $data = [
  338. 'touser' => $user->user_open_id,
  339. 'template_id' => env("WECHAT_FANS_ORDER_TEMPLATE_URL"),
  340. 'url' => env("WECHAT_FANS_ORDER_URL"),
  341. 'data' => [
  342. 'first' => "粉丝下单成功通知",
  343. 'keyword1' => $order->order_number,
  344. 'keyword2' => $tmpOrder->product_name,
  345. 'keyword3' => $order->created_at,
  346. 'keyword4' => round($tmpOrder->order_price/100,2)."元",
  347. 'keyword5' => $privideUser->user_nickname,
  348. "remark"=>"您的粉丝有新的订单,分享佣金已产生,3天后结算到您账户中,点击详情跳转粉丝订单"
  349. ],
  350. ];
  351. $res = $app->template_message->send($data);
  352. $instance->info("粉丝下单微信返回结果:".json_encode($res));
  353. }catch (\Throwable $exception){
  354. $instance->info("粉丝下单通知结果异常:".$exception->getMessage());
  355. }
  356. }
  357. }else{
  358. $user = UserModel::findById($order->user_id);
  359. if($user){
  360. try{
  361. //获取公众号实例
  362. $app = WechatAccountUtil::getAppByID($user->wechat_account_id);
  363. $tmpOrder = UserOrderModel::query()->where("order_number",$order->order_number)->first();
  364. $data = [
  365. 'touser' => $user->user_open_id,
  366. 'template_id' => env("WECHAT_ORDER_TEMPLATE_URL"),
  367. 'url' => env("WECHAT_ORDER_URL"),
  368. 'data' => [
  369. 'first' => "下单成功通知",
  370. 'keyword1' => $order->created_at,
  371. 'keyword2' => $tmpOrder->product_name,
  372. 'keyword3' => $order->order_number,
  373. "remark"=>"感谢您的使用,每月20号结算上个月的佣金,将会结算到您的账户中点击详情跳转我的订单"
  374. ],
  375. ];
  376. $res = $app->template_message->send($data);
  377. $instance->info("自购下单微信返回结果:".json_encode($res));
  378. }catch (\Throwable $exception){
  379. $instance->info("自购下单通知结果异常:".$exception->getMessage());
  380. }
  381. }
  382. }
  383. UserOrderCommissionModel::query()->where("id",$order->id)->update(
  384. [
  385. "order_notify_status"=>1
  386. ]
  387. );
  388. }
  389. //3.获取上月已结算订单,并通知
  390. $completeOrders = UserOrderCommissionModel::query()
  391. ->where("commission_status",1)
  392. ->where("order_commission",">",0)
  393. ->where("user_id","<>",0)
  394. ->where("order_complete_notify_status",0)
  395. ->groupBy("user_id")
  396. ->select(["user_id",DB::Raw("sum(order_commission) as total_order_commission"),DB::Raw("GROUP_CONCAT(id) as ids")])
  397. ->get();
  398. foreach ($completeOrders as $order){
  399. $user = UserModel::findById($order->user_id);
  400. if($user){
  401. try{
  402. //获取公众号实例
  403. $app = WechatAccountUtil::getAppByID($user->wechat_account_id);
  404. $data = [
  405. 'touser' => $user->user_open_id,
  406. 'template_id' => env("WECHAT_COMPLETE_ORDER_TEMPLATE_URL"),
  407. 'url' => env("WECHAT_BALANCE_URL"),
  408. 'data' => [
  409. 'first' => "上月订单佣金已结算完成",
  410. 'keyword1' => round($order["total_order_commission"]/100,2)."元",
  411. 'keyword2' => round($order["total_order_commission"]/100,2)."元",
  412. 'keyword3' => date("Y-m-d H:i:s"),
  413. "remark"=>"订单佣金已结算完成,可以立即提现哦!零钱秒到账"
  414. ],
  415. ];
  416. $res = $app->template_message->send($data);
  417. $instance->info("订单结算微信返回结果:".json_encode($res));
  418. }catch (\Throwable $exception){
  419. $instance->info("订单结算通知结果异常:".$exception->getMessage());
  420. }
  421. }
  422. UserOrderCommissionModel::query()->whereIn("id",explode(",",$order["ids"]))->update(
  423. [
  424. "order_complete_notify_status"=>1
  425. ]
  426. );
  427. }
  428. }
  429. /**
  430. * 结算佣金逻辑(每月的20号18点结算上个月的佣金)
  431. */
  432. public static function settlementOrderCommissionLogic()
  433. {
  434. //获取上个月的开始结束时间
  435. $startTime = date("Y-m-d",strtotime("-1 month"))." 00:00:00";
  436. $endTime = date("Y-m-")."01 00:00:00";
  437. //获取上个月未结算的订单且未退款
  438. //这里有个bug,chunk里面自己改自己会导致有的数据娶不到
  439. UserOrderCommissionModel::query()
  440. ->where("commission_status",0)
  441. ->where("order_commission",">",0)
  442. ->where("user_id","<>",0)
  443. ->where("order_complete_notify_status",0)
  444. ->where("created_at","<",$endTime)
  445. ->chunk(300,function ($orderCommissions){
  446. foreach ($orderCommissions as $orderCommission){
  447. try{
  448. //开启事务
  449. DB::beginTransaction();
  450. //1.修改用户的余额
  451. $user = UserModel::query()->lock(true)->find($orderCommission["user_id"]);
  452. if($user){
  453. $userRes = UserModel::query()
  454. ->where("id",$orderCommission["user_id"])
  455. ->increment("user_balance",$orderCommission["order_commission"]);
  456. if(!$userRes){
  457. DB::rollBack();
  458. throw new CommonException(ErrorEnum::ERROR_SYSTEM);
  459. }
  460. //2.添加用户流水记录
  461. $logRes = UserFinanceModel::query()
  462. ->insert(
  463. [
  464. "user_id"=>$orderCommission["id"],
  465. "order_number"=>$orderCommission["order_number"],
  466. "user_before_balance"=>$user["user_balance"],
  467. "user_after_balance"=>$orderCommission["order_commission"]+$user["user_balance"],
  468. "finance_balance"=>$orderCommission["order_commission"],
  469. "finance_remark"=>"订单佣金结算",
  470. "finance_type"=>1,
  471. "finance_number"=>uniqid("fbt-"),
  472. "created_at"=>date("Y-m-d H:i:s"),
  473. "updated_at"=>date("Y-m-d H:i:s"),
  474. "cash_status"=>1
  475. ]
  476. );
  477. if(!$logRes){
  478. DB::rollBack();
  479. throw new CommonException(ErrorEnum::ERROR_SYSTEM);
  480. }
  481. //3.修改佣金记录为已结算
  482. $commissionRes = UserOrderCommissionModel::query()
  483. ->where("id",$orderCommission["id"])
  484. ->update(
  485. [
  486. "commission_status"=>1,
  487. "updated_at"=>date("Y-m-d H:i:s")
  488. ]
  489. );
  490. if(!$commissionRes){
  491. DB::rollBack();
  492. throw new CommonException(ErrorEnum::ERROR_SYSTEM);
  493. }
  494. DB::commit();
  495. }
  496. }catch (\Throwable $exception){}
  497. }
  498. });
  499. }
  500. /**
  501. * 处理提现打款逻辑
  502. */
  503. public static function transferFinanceLogic()
  504. {
  505. $account = WechatAccountModel::query()
  506. ->where("wechat_app_code","fanbuting")
  507. ->first();
  508. $config = [
  509. "app_id"=>$account["wechat_app_id"],
  510. "mch_id"=>$account["account_mch_id"],
  511. "key"=>$account["account_key"],
  512. "cert_path"=>$account["account_cert_path"],
  513. "key_path"=>$account["account_key_path"]
  514. ];
  515. $app = Factory::payment($config);
  516. //获取已审核且未打款的提现记录
  517. $cashLogs = UserCashModel::query()
  518. ->where("check_status",2)
  519. ->where("cash_status",0)
  520. ->get();
  521. if(!$cashLogs){
  522. return ;
  523. }
  524. //将打款记录修改为执行中
  525. $logIds = [];
  526. foreach ($cashLogs as $cashLog){
  527. $logIds[] = $cashLog["id"];
  528. }
  529. UserCashModel::query()
  530. ->whereIn("id",$logIds)
  531. ->update(
  532. [
  533. "cash_status"=>1
  534. ]
  535. );
  536. foreach ($cashLogs as $cashLog){
  537. //1.获取用户的openId
  538. $user = UserModel::query()->find($cashLog["user_id"]);
  539. if($user){
  540. $res = $app->transfer->toBalance(
  541. [
  542. "partner_trade_no"=>$cashLog["cash_order_number"],
  543. "openid"=>$user["user_open_id"],
  544. "check_name"=>"NO_CHECK",//不校验姓名
  545. "re_user_name"=>"",//真实姓名
  546. "amount"=>$cashLog["cash_money"],
  547. "desc"=>"用户提现"
  548. ]
  549. );
  550. //判断是否支付成功
  551. if($res["return_code"]=="SUCCESS" && $res["result_code"]=="SUCCESS"){
  552. UserCashModel::query()
  553. ->where("id",$cashLog["id"])
  554. ->update(
  555. [
  556. "cash_status"=>2,
  557. "upstream_response"=>json_encode($res),
  558. "cash_receive_at"=>date("Y-m-d H:i:s")
  559. ]
  560. );
  561. $cash_status = 1;//打款成功
  562. }else{
  563. //打款失败
  564. UserCashModel::query()
  565. ->where("id",$cashLog["id"])
  566. ->update(
  567. [
  568. "cash_status"=>3,
  569. "upstream_response"=>json_encode($res)
  570. ]
  571. );
  572. $cash_status = 2;//打款失败
  573. }
  574. //修改提现流水的状态
  575. UserFinanceModel::query()->where("id",$cashLog["user_finance_id"])
  576. ->update(
  577. [
  578. "cash_status"=>$cash_status,
  579. "updated_at"=>date("Y-m-d H:i:s")
  580. ]
  581. );
  582. }
  583. }
  584. }
  585. /**
  586. * 打款失败退款逻辑
  587. */
  588. public static function callbackCashLogic()
  589. {
  590. //获取已审核且未打款的提现记录
  591. $cashLogs = UserCashModel::query()
  592. ->where("callback_status",0)
  593. ->where(function ($query){
  594. $query->where("check_status",3)
  595. ->orWhere("cash_status",3);
  596. })
  597. ->get();
  598. if(!$cashLogs){
  599. return;
  600. }
  601. foreach ($cashLogs as $cashLog){
  602. DB::beginTransaction();
  603. //获取用户
  604. $user = UserModel::query()->lock(true)->find($cashLog["user_id"]);
  605. //1.用户金额增加
  606. $userRes = UserModel::query()
  607. ->where("id",$user["user_id"])
  608. ->increment("user_balance",$cashLog["cash_money"]);
  609. if(!$userRes){
  610. DB::rollBack();
  611. break;
  612. }
  613. //2.添加流水记录
  614. $financeRes = UserFinanceModel::query()->insert(
  615. [
  616. "user_id"=>$cashLog["user_id"],
  617. "user_before_balance"=>$user["user_balance"],
  618. "user_after_balance"=>$user["user_balance"]+$cashLog["cash_money"],
  619. "finance_balance"=>$cashLog["cash_money"],
  620. "finance_remark"=>"提现失败退回,原提现记录ID为:".$cashLog["id"],
  621. "finance_type"=>1,
  622. "finance_number"=>BaseUtil::getOrderNumber(),
  623. "created_at"=>date("Y-m-d H:i:s"),
  624. "updated_at"=>date("Y-m-d H:i:s"),
  625. ]
  626. );
  627. if(!$financeRes){
  628. DB::rollBack();
  629. break;
  630. }
  631. //3.修改提现记录为退款成功
  632. $cashRes = UserCashModel::query()
  633. ->where("id",$cashLog["id"])
  634. ->update([
  635. "callback_status"=>1
  636. ]);
  637. if(!$cashRes){
  638. DB::rollBack();
  639. break;
  640. }
  641. DB::commit();
  642. }
  643. }
  644. }