* @date 2020-01-29 10:10:06 */ declare(strict_types=1); namespace App\Repositories; use App\Constants\ChangeLogConstant; use App\Constants\CommonConstant; use App\Exception\ApiException; use App\Model\CoinsLogModel; use App\Model\CollectionsModel; use App\Model\UserModel; use App\Model\VipCardModel; use App\Model\VipOrderModel; use App\Repositories\Service\CommonService; use App\Repositories\Service\PaymentService; use App\Repositories\Service\QueueService; use App\Repositories\UserRepository; use Carbon\Carbon; use Hyperf\DbConnection\Db; use KZ2\Repositories\Model\Repository; use Psr\SimpleCache\CacheInterface; use App\Repositories\Utils\M3u8CacheRepository; class VipRepository extends Repository { public function model() { return VipCardModel::class; } /** * 获取vip套餐信息 * @return array */ public function getCanUseVipList($id = 0) { $list = make(CacheInterface::class) ->remember( 'vip_list', 60 * 60, function () { $arrItems = []; $items = VipCardModel::query() ->where('status', 1) ->orderByDesc('sort') ->get()->keyBy('id'); if ($items->count()) { $arrItems = $items->toArray(); foreach ($arrItems as $k => $v) { $arrJson = []; if (!empty($v['jdata'])) { $arrJson = json_decode($v['jdata'], true); } $arrItems[$k]['jdata'] = $arrJson; } } return $arrItems; } ); if ($id) { return isset($list[$id]) ? $list[$id] : []; } else { return $list; } } /** * 删除vip套餐缓存 后台相关操作的时候调用此方法 * @return bool */ public function delUserVipCache() { return make(CacheInterface::class)->delete('vip_list'); } /** * 获取vip套餐信息 * @return array */ public function getVipPackageData() { $result = array(); $vipList = $this->getCanUseVipList(); if ($vipList) { foreach ($vipList as $item) { $item['true_price'] = floatval($item['true_price']); $payment = make(PaymentService::class) ->getPayGatewayByAmount($item['true_price']); $tempItem = array( 'id' => $item['id'], 'title' => $item['title'], 'remark' => $item['remark'], 'day' => $item['day'] >= 9999 ? '永久无限' : $item['day'] . '天', 'price' => round($item['true_price']) . '', 'payment' => $payment, 'color' => $item['color'] ?? '', 'jdata' => $item['jdata'], 'intro' => $item['intro'] ?? '', 'mark' => $item['mark'] ?? '', 'is_super' => $item['is_super'] ?? 0, 'send_type' => $item['send_type'] ?? 0, 'send_num' => $item['send_num'] ?? 0, 'send_remark' => $item['send_remark'] ?? '', ); $result [] = $tempItem; } } return $result; } /** * 获取vip套餐信息(大鲨鱼版) * @return array */ public function getVipPackage($coins = 0, $deviceType = '') { $result = array(); $vipList = $this->getCanUseVipList(); $paymentList = make(PaymentService::class)->getAllPayments(); if ($vipList) { $price_array = []; foreach ($vipList as $item) { $item['true_price'] = floatval($item['true_price']); $price_array[] = $item['true_price']; $truePrice = (float)$item['true_price']; $price = (float)$item['price']; $payment = make(PaymentService::class) ->getPayGatewayByAmount($item['true_price'], $deviceType, $paymentList); if ($coins >= $item['true_price']) { $cotnType = [ 'id' => 1, 'name' => '金币', 'img' => M3u8CacheRepository::getImageUrl('f2|/'. env('STATIC_DIR_NAME', 'doukui') . '/pay_type/4_144x144.ceb'), 'pay_type' => 4 ]; array_push($payment, $cotnType); } $tempItem = array( 'id' => $item['id'], 'title' => $item['title'], 'remark' => $item['remark'], 'day' => $item['day'] >= 9999 ? '永久无限' : $item['day'] . '天', 'price' => $price, 'true_price' => $truePrice, 'payment' => $payment, 'color' => $item['color'] ?? '', 'jdata' => $item['jdata'], 'intro' => $item['intro'] ?? '', 'mark' => $item['mark'] ?? '', 'is_super' => $item['is_super'] ?? 0, 'send_type' => $item['send_type'] ?? 0, 'send_num' => $item['send_num'] ?? 0, 'send_remark' => $item['send_remark'] ?? '', 'coins' => $item['coins'] ?? 0, 'coin_remark' => $item['coin_remark'] ?? '', // 花金币购买促销描述,例如文案:金币支付优惠20元 ); $result[] = $tempItem; } /*$payment = [ [ 'pay_type' => 'ali', 'gatway' => 'ali:ys', 'pay_name' => '支付宝', 'img' => 'f2|/'. env('STATIC_DIR_NAME', 'doukui') . '/pay_type/ali_144x144.ceb', ], [ 'pay_type' => 'wx', 'gatway' => 'wx:hf', 'pay_name' => '微信', 'img' => 'f2|/'. env('STATIC_DIR_NAME', 'doukui') . '/pay_type/wx_144x144.ceb', ], [ 'pay_type' => 'union', 'gatway' => 'union:ys', 'pay_name' => '银联', 'img' => 'f2|/'. env('STATIC_DIR_NAME', 'doukui') . '/pay_type/union_144x144.ceb', ], [ 'pay_type' => 'coin', 'gatway' => 'coin:coin', 'pay_name' => '金币', 'img' => 'f2|/'. env('STATIC_DIR_NAME', 'doukui') . '/pay_type/coin_144x144.ceb', ], ];*/ } return $result; } /** * 创建vip订单 * @param array $requestData 请求参数 * @return mixed */ public function createVipOrder($requestData) { $userInfo = make(UserRepository::class) ->getUserInfoFromCache($requestData['user_id']); if (!$userInfo) { throw new ApiException('账号异常'); } $vipItem = $this->getCanUseVipList($requestData['vip_id']); if (!$vipItem) { throw new ApiException('vip套餐不存在'); } $vipItem['true_price'] = floatval($vipItem['true_price']); //次数控制 十秒钟内同支付方式只允许一单 $queryTime = Carbon::now()->modify('-10 second')->toDateTimeString(); $orderNum = VipOrderModel::query() ->where('user_id', '=', $userInfo['id']) ->where('created_at', '>', $queryTime)->count(); if ($orderNum > 0) { throw new ApiException('亲,麻烦歇一会呢'); } //生成订单 $orderSn = make(CommonService::class)->createOrderSn(CommonConstant::APP_SHORT_NAME); $insertData = array( 'order_sn' => $orderSn, 'order_type' => $requestData['order_type'], 'user_id' => $userInfo['id'], 'user_code' => $userInfo['code'], 'user_parent_id' => $userInfo['parent_uid'] ?: 0, 'user_channel_id' => $userInfo['channel_id'], 'vip_title' => $vipItem['title'], 'vip_id' => $requestData['vip_id'], 'vip_days' => $vipItem['day'], 'pay_type' => $requestData['pay_type'], 'device_type' => $userInfo['device_type'], 'order_amount' => $vipItem['true_price'], 'real_amount' => $vipItem['true_price'], 'package_info' => json_encode($vipItem), 'trade_no' => $orderSn, 'status'=>3, ); $result = VipOrderModel::query()->create($insertData); $jobData = clone $result; if (empty($result)) { return []; } $jobData = $jobData->toArray(); $jobData['user_info'] = $userInfo; // 代理系统异步订单 make(QueueService::class)->agentOrderIncJob($jobData); return $result; } /** * 金币购买vip * * @param $requestData * @return bool */ public function createCoinVipOrder($requestData) { $userInfo = make(UserRepository::class)->findBy('code', $requestData['user_id']); if (!$userInfo) { throw new ApiException('账号异常'); } $vipItem = $this->getCanUseVipList($requestData['vip_id']); if (!$vipItem) { throw new ApiException('vip套餐不存在'); } if ($userInfo->coins < $vipItem['coins']) { throw new ApiException('金币不足,请充值金币后购买会员'); } //次数控制 一分钟内同支付方式只允许一单 $queryTime = Carbon::now()->modify('-1 minute')->toDateTimeString(); $orderNum = VipOrderModel::query() ->where('user_id', '=', $userInfo['id']) ->where('created_at', '>', $queryTime)->count(); if ($orderNum > 0) { throw new ApiException('亲,麻烦歇一会呢'); } Db::beginTransaction(); //订单号 $orderSn = make(CommonService::class)->createOrderSn(CommonConstant::APP_SHORT_NAME); $orderData = [ 'order_sn' => $orderSn, 'order_type' => $requestData['order_type'], 'user_id' => $userInfo['id'], 'user_code' => $userInfo['code'], 'user_parent_id' => $userInfo['parent_uid'] ?: 0, 'user_channel_id' => $userInfo['channel_id'], 'vip_title' => $vipItem['title'], 'vip_id' => $requestData['vip_id'], 'vip_days' => $vipItem['day'], 'pay_type' => $requestData['pay_type'], //4 金币类型 'device_type' => $userInfo['device_type'], 'order_amount' => $vipItem['true_price'], 'real_amount' => $vipItem['true_price'], 'status' => 1, 'pay_time' => Carbon::now()->toDateTimeString(), 'trade_no' => $orderSn, 'package_info' => json_encode($vipItem), ]; $result = VipOrderModel::query()->create($orderData); if (!$result) { Db::rollBack(); throw new ApiException('亲,麻烦歇一会呢'); } //写收款单 // $collectionsData = [ // 'user_id' => $userInfo['id'], // 'user_code' => $userInfo['code'], // 'order_sn' => $orderSn, // 'type' => $requestData['order_type'], // 'pay_type' => $requestData['pay_type'], // 'device_type' => $userInfo['device_type'], // 'channel' => $userInfo['channel_id'], // 'trade_sn' => $orderSn, // 'order_amount' => $vipItem['true_price'], // 'real_amount' => $vipItem['true_price'], // ]; // $result1 = CollectionsModel::query()->create($collectionsData); //加会员天数 $userInfoCache = make(UserRepository::class) ->getUserInfoFromCache($userInfo['code']); if ($userInfoCache['is_vip'] == 'y') { $vipTime = Carbon::parse($userInfoCache['vip_expired']) ->addDays($vipItem['day']) ->toDateTimeString(); } else { $vipTime = Carbon::now() ->addDays($vipItem['day']) ->toDateTimeString(); } $houseCount = 0; $userCoins = 0; foreach ($vipItem['jdata']['feature'] as $packVal) { switch ($packVal['type']) { case 'house': $houseCount = $packVal['count']; break; } } if ($vipItem['send_type'] == 2) { $userCoins = $vipItem['send_num']; } //扣除金币 todo 这个地方不用考虑并发问题,加金币和买会员不会同时进行 $coin = $userInfo->coins - $vipItem['coins'] + $userCoins; $houseCount = $userInfo['max_open_house'] + $houseCount; $result2 = UserModel::query() ->where('id', $userInfo['id']) ->update(['vip_expired' => $vipTime, 'vip_level' => $vipItem['id'], 'coins' => $coin, 'max_open_house' => $houseCount]); if ($result2) { Db::commit(); // 送金币帐变记录 if ($userCoins > 0) { $changeData = [ 'user_uid' => $userInfo->code, 'currency_type' => ChangeLogConstant::CHANGE_COIN, 'amount' => $userCoins, 'way' => ChangeLogConstant::WAY_1, 'type' => ChangeLogConstant::TYPE_23, ]; make(QueueService::class)->saveChangeLogJob($changeData); } // 帐变记录 $changeData = [ 'user_uid' => $userInfo->code, 'currency_type' => ChangeLogConstant::CHANGE_COIN, 'amount' => $vipItem['coins'], 'way' => ChangeLogConstant::WAY_2, 'type' => ChangeLogConstant::TYPE_2, ]; make(QueueService::class)->saveChangeLogJob($changeData); make(UserRepository::class)->delUserCache($userInfo['code']); return true; } Db::rollBack(); return false; } /** * 处理支付回调 * @param int $orderId * @param string $tradeNo * @param float $payMoney * @param int $orderType * @return bool */ public function doBuy($orderId, $tradeNo, $payMoney, $orderType) { if (!$orderId || !$tradeNo || !$payMoney || !$orderType) { return false; } Db::beginTransaction(); try { $orderItem = VipOrderModel::query()->where('id', $orderId) ->first(); if (!$orderItem || $orderItem['status'] == 1) { logger('订单状态异常:', [$orderItem['status']]); Db::rollBack(); return false; } $orderItem = $orderItem->toArray(); //金额校验 $orderMoney = floatval($orderItem['order_amount']); $payMoney = floatval($payMoney); $minusMoney = $orderMoney - $payMoney; $minusMoney = abs(round($minusMoney, 2)); if ($minusMoney > 2) { //只允许订单金额和付款金额相差2元内 Db::rollBack(); return false; } //修改订单状态 $updateData = array( 'real_amount' => $payMoney, 'status' => 1, 'pay_time' => Carbon::now()->toDateTimeString(), 'trade_no' => $tradeNo, ); $result1 = VipOrderModel::query() ->where('id', $orderId) ->update($updateData); //写收款单 $collectionsData = array( 'user_id' => $orderItem['user_id'], 'user_code' => $orderItem['user_code'], 'order_sn' => $orderItem['order_sn'], 'type' => $orderType, 'pay_type' => $orderItem['pay_type'], 'device_type' => $orderItem['device_type'], 'channel' => $orderItem['user_channel_id'], 'trade_sn' => $tradeNo, 'order_amount' => $orderMoney, 'real_amount' => $payMoney, ); $result2 = CollectionsModel::query()->create($collectionsData); //加会员天数 $userInfo = make(UserRepository::class) ->getUserInfoFromCache($orderItem['user_code']); if ($userInfo['is_vip'] == 'y') { $vipTime = Carbon::parse($userInfo['vip_expired']) ->addDays($orderItem['vip_days']) ->toDateTimeString(); } else { $vipTime = Carbon::now() ->addDays($orderItem['vip_days']) ->toDateTimeString(); } $package = json_decode($orderItem['package_info'], true); $houseCount = 0; $userCoins = 0; foreach ($package['jdata']['feature'] as $packVal) { switch ($packVal['type']) { case 'house': $houseCount = $packVal['count']; break; } } if ($package['send_type'] == 2) { $userCoins = $package['send_num']; } $houseCount = $userInfo['max_open_house'] + $houseCount; $coins = $userInfo['coins'] + $userCoins; $result3 = UserModel::query() ->where('id', $orderItem['user_id']) ->update(['vip_expired' => $vipTime, 'vip_level' => $orderItem['vip_id'], 'max_open_house' => $houseCount, 'coins' => $coins]); if ($result1 && $result2 && $result3) { Db::commit(); $queue = make(QueueService::class); //返佣计算 异步 $queue->rebateTwoUserJob(['amount' => $orderMoney, 'user_id' =>$orderItem['user_code']]); // 帐变记录 if ($userCoins > 0) { // 帐变记录 $changeData = [ 'user_uid' => $orderItem['user_code'], 'currency_type' => ChangeLogConstant::CHANGE_COIN, 'amount' => $userCoins, 'way' => ChangeLogConstant::WAY_1, 'type' => ChangeLogConstant::TYPE_23, ]; $queue->saveChangeLogJob($changeData); } // 代理系统异步订单 $jobData = VipOrderModel::query()->where('id', $orderId)->first()->toArray(); $jobData['user_info'] = UserModel::query()->find($orderItem['user_id'])->toArray(); $queue->agentOrderIncJob($jobData); make(UserRepository::class)->delUserCache($orderItem['user_code']); return true; } } catch (\Exception $e) { logger('支付回调失败:', [$e->getMessage()]); } Db::rollBack(); return false; } }