* @date 2020-01-29 10:10:06 */ declare(strict_types=1); namespace App\Repositories; use App\Constants\ChangeLogConstant; use App\Constants\OrderConstrant; use App\Model\CoinsLogModel; use App\Model\CoinsModel; use App\Model\CoinsOrderModel; use App\Model\CollectionsModel; use App\Model\UserModel; use App\Repositories\Service\CommonService; use App\Repositories\Service\PaymentService; use App\Repositories\Service\QueueService; use Carbon\Carbon; use Hyperf\Database\Model\Builder; use Hyperf\DbConnection\Db; use KZ2\Repositories\Model\Repository; use Psr\SimpleCache\CacheInterface; use App\Constants\CommonConstant; class CoinsRepository extends Repository { /** * @return Builder|mixed */ public function model() { return CoinsModel::class; } /** * 定义金币记录类型 * @return array */ public function getCoinsTypeArr() { return array( 1 => '购买金币', 2 => '购买会员', //金币购买会员 ); } /** * 增加用户金币,在外层调用业务中使用事物、否则会存在事物套事物的情况 * @param array|int $user 用户 数组 or 用户id * @param float $amount 金额 大于0 * @param int $type 类型 * @param string $orderSn 流水号 如果是因为订单之类的、可以传订单流水号进来、方便后期查询 * @return bool */ public function addCoins($userCode, $amount, $type, $collectionsData = [], $orderId = '') { if (!$userCode || !$amount || !$type || $amount <= 0) { return false; } $user = UserModel::where('code', $userCode)->first(); if (!$user) { return false; } $user = $user->toArray(); //增加用户金币 $result1 = UserModel::where('id', $user['id'])->increment('coins', $amount); if ($result1) { // 帐变记录 $changeData = [ 'user_uid' => $userCode, 'currency_type' => ChangeLogConstant::CHANGE_COIN, 'amount' => $amount, 'way' => ChangeLogConstant::WAY_1, 'type' => ChangeLogConstant::TYPE_1, ]; make(QueueService::class)->saveChangeLogJob($changeData); // 写收款单据 $collectionsData['device_type'] = $user['device_type']; CollectionsModel::create($collectionsData); $jobData = CoinsOrderModel::query()->where('id', $orderId)->first()->toArray(); $jobData['user_info'] = $user; make(QueueService::class)->agentOrderIncJob($jobData); return true; } return false; } /** * 减少用户金币,在外层调用业务中使用事物、否则会存在事物套事物的情况 * @param array|int $user 用户 数组 or 用户id * @param float $amount 金额 小于0 * @param int $type 类型 * @param string $orderSn 流水号 如果是因为订单之类的、可以传订单流水号进来、方便后期查询 * @return bool */ public function reduceCoins($user, $amount, $type, $orderSn = '') { if (!$user || !$amount || !$type || $amount >= 0) { return false; } if (is_numeric($user)) { $user = UserModel::where('id', $user)->first()->toArray(); } if (!$user) { return false; } if (empty($orderSn)) { $orderSn = make(CommonService::class)->createOrderSn('C'); } //增加用户金币 $result1 = UserModel::where('id', $user['id'])->increment('coins', $amount); //写金币日志 $amountLog = $user['coins'] + $amount; $logData = array( 'user_id' => $user['id'], 'user_code' => $user['code'], 'amount' => $amount, 'amount_log' => $amountLog, 'coin_type' => $type, 'order_sn' => $orderSn, ); $result2 = CoinsLogModel::create($logData); if ($result1 && $result2) { return true; } return false; } /** * 获取所有能使用的金币套餐 * @return array */ public function getCanUseCoinsList() { $result = make(CacheInterface::class)->remember( 'user_coins_list', 60 * 60, function () { $tempData = array(); $tempResult = CoinsModel::query() ->where('status', 1) ->orderBy('sort', 'DESC') ->get() ->toArray(); if ($tempResult) { foreach ($tempResult as $tempItem) { $tempData[$tempItem['id']] = $tempItem; } } return $tempData; } ); return $result; } /** * 删除金币套餐缓存 后台相关操作的时候调用此方法 * @return bool */ public function delUserCoinsCache() { make(CacheInterface::class) ->deleteMultiple(array('user_coins_list')); return true; } /** * 获取用户金币套餐信息 * @return array */ public function getUserCoinsPackageData($deviceType = '') { $result = array(); $vipList = $this->getCanUseCoinsList(); $paymentList = make(PaymentService::class)->getAllPayments(); if ($vipList) { $buyNotice = make(ConfigRepoistory::class)->get('coins_intro', 'rule', ''); foreach ($vipList as $item) { $payment = make(PaymentService::class)->getPayGatewayByAmount($item['real_price'], $deviceType, $paymentList); $tempItem = array( 'id'=>$item['id'], 'coins'=>$item['coins'].'', 'price'=>round(floatval($item['price'])).'', 'real_price' => round(floatval($item['real_price'])).'', 'intro'=>$item['title_desc'], 'buy_notice'=>$buyNotice, 'payment'=>$payment, ); $result []= $tempItem; } } return $result; } /** * 生成金币订单 * @param array $requestData * @return int */ public function createCoinsOrder($requestData) { if (empty($requestData['pay_id']) || empty($requestData['user_id']) || empty($requestData['coin_id'])) { throw new \App\Exception\ApiException('参数错误'); } $userInfo = make(UserRepository::class)->getUserInfoFromCache($requestData['user_id']); if (!$userInfo) { throw new \App\Exception\ApiException('账号异常'); } $coinList = $this->getCanUseCoinsList(); if (!isset($coinList[$requestData['coin_id']])) { throw new \App\Exception\ApiException('套餐不存在'); } $coinItem = $coinList[$requestData['coin_id']]; //次数控制 一分钟内同支付方式只允许一单 $queryTime = Carbon::now()->modify('-1 minute')->toDateTimeString(); $orderNum = make(CoinsOrderModel::class) ->where('user_id', '=', $userInfo['id']) // ->where('payment_id', '=', $payment['id']) ->where('created_at', '>', $queryTime) ->count(); if ($orderNum > 0) { throw new \App\Exception\ApiException('亲,麻烦歇一会呢'); } //生成订单 Db::beginTransaction(); try { $orderSn = make(CommonService::class)->createOrderSn(CommonConstant::APP_SHORT_NAME); $insertData = array( 'order_sn' => $orderSn, 'user_id' => $userInfo['id'], 'user_code' => $userInfo['code'], 'user_parent_id' => $userInfo['parent_uid'] ?: 0, 'user_channel_id' => $userInfo['channel_id'], 'coins_id' => $requestData['coin_id'], 'coins' => $coinItem['coins'], 'order_amount' => $coinItem['price'], 'real_amount' => $coinItem['real_price'], 'payment_name' => OrderConstrant::$messages[$requestData['pay_type']] ?? '官方通道', 'status' => 3, 'trade_no' => $orderSn, 'package_info' => json_encode($coinItem), ); $result = CoinsOrderModel::create($insertData); if ($result) { Db::commit(); $jobData = clone $result; $jobData = $jobData->toArray(); $jobData['user_info'] = $userInfo; // 代理系统异步订单 make(QueueService::class)->agentOrderIncJob($jobData); return $result; } } catch (\Exception $e) { logger($e->getMessage()); } Db::rollBack(); return 0; } /** * 金额回调 * @param int $orderId 订单id * @param string $tradeNo 交易单号 * @param float $payMoney 支付金额 * @return bool */ public function doBuy($orderId, $tradeNo, $payMoney) { if (!$orderId || !$tradeNo || !$payMoney) { return false; } Db::beginTransaction(); try { $orderItem = CoinsOrderModel::where('id', $orderId)->first()->toArray(); if (!$orderItem || $orderItem['status'] == 1) { Db::rollBack(); return false; } //金额校验 $orderMoney = floatval($orderItem['real_amount']); $payMoney = floatval($payMoney); $minusMoney = floatval($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 = CoinsOrderModel::where('id', $orderId)->update($updateData); //写收款单 $collectionsData = array( 'user_id' => $orderItem['user_id'], 'user_code' => $orderItem['user_code'], 'order_sn' => $orderItem['order_sn'], 'trade_sn' => $tradeNo, 'order_amount' => $orderMoney, 'real_amount' => $payMoney, 'type' => 2, ); //加金币 $result3 = $this->addCoins($orderItem['user_code'], $orderItem['coins'], 2, $collectionsData, $orderId); if ($result1 && $result3) { Db::commit(); make(UserRepository::class)->delUserCache($orderItem['user_code']); return true; } } catch (\Exception $e) { Db::rollBack(); return false; } Db::rollBack(); return false; } }