300 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
| <?php
 | ||
| 
 | ||
| namespace app\service;
 | ||
| 
 | ||
| use app\exception\LogicException;
 | ||
| use app\model\Order;
 | ||
| use app\model\Product;
 | ||
| use app\model\Sign;
 | ||
| use app\model\User;
 | ||
| use app\service\util\BlueBrothersClientUtil;
 | ||
| use app\service\util\CmbLifeUtils;
 | ||
| use app\service\util\SmsUtil;
 | ||
| use app\util\CmbHttpUtils;
 | ||
| use app\util\StringUtil;
 | ||
| use think\facade\Cache;
 | ||
| use think\facade\Log;
 | ||
| 
 | ||
| class CmbService extends BaseService
 | ||
| {
 | ||
|     /**
 | ||
|      * 生成登录授权协议
 | ||
|      * @param $params
 | ||
|      * @return string
 | ||
|      * @throws LogicException
 | ||
|      */
 | ||
|     public static function genApprovalProtocol($params): string
 | ||
|     {
 | ||
|         $callback = $params['callback'] ?? '';
 | ||
|         $funcName = 'approval';
 | ||
|         $params = [
 | ||
|             'clientType' => 'h5',
 | ||
|             'responseType' => 'code',
 | ||
|             'callback' => $callback,
 | ||
|             'scope' => 'default,getUserInfo',
 | ||
|             'state' => 'state'
 | ||
|         ];
 | ||
|         return CmbLifeUtils::genProtocol($funcName, $params);
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 获取accessToken
 | ||
|      * @param string $code
 | ||
|      * @return mixed|string
 | ||
|      * @throws LogicException
 | ||
|      */
 | ||
|     public static function accessToken(string $code)
 | ||
|     {
 | ||
|         $funcName = 'accessToken';
 | ||
|         $res = CmbHttpUtils::doPost($funcName, ['code' => $code, 'grantType' => 'authorizationCode']);
 | ||
|         if ($res['respCode'] == 1000) {
 | ||
|             // 判断是否存在
 | ||
|             $user = User::getUserByOpenId($res['cmbOpenId']);
 | ||
|             $mobile = '';
 | ||
|             if ($user->isEmpty()) {
 | ||
|                 // 获取手机号
 | ||
|                 $getUserRes = CmbHttpUtils::doPost('getUserInfo', ['cmbOpenId' => $res['cmbOpenId'], 'accessToken' => $res['accessToken']]);
 | ||
|                 if ($getUserRes['respCode'] == 1000) {
 | ||
|                     $decryptBody = $getUserRes['decryptBody'];
 | ||
|                     $mobile = $decryptBody['mobile'] ?? '';
 | ||
|                 }
 | ||
|                 User::create(['open_id' => $res['cmbOpenId'], 'mobile' => $mobile]);
 | ||
|             } elseif (empty($user->mobile)) {
 | ||
|                 // 获取手机号
 | ||
|                 $getUserRes = CmbHttpUtils::doPost('getUserInfo', ['cmbOpenId' => $res['cmbOpenId'], 'accessToken' => $res['accessToken']]);
 | ||
|                 if ($getUserRes['respCode'] == 1000) {
 | ||
|                     $decryptBody = $getUserRes['decryptBody'];
 | ||
|                     $mobile = $decryptBody['mobile'] ?? '';
 | ||
|                 }
 | ||
|                 User::update(['mobile' => $mobile],['open_id' => $res['cmbOpenId']]);
 | ||
|             } else {
 | ||
|                 $mobile = $user->mobile;
 | ||
|             }
 | ||
|             return ['open_id' => $res['cmbOpenId'], 'mobile' => $mobile];
 | ||
|         } else {
 | ||
|             throw new LogicException($res['respMsg']);
 | ||
|         }
 | ||
|     }
 | ||
|     /**
 | ||
|      * 校验accessToken
 | ||
|      * @param $params
 | ||
|      * @return mixed|string
 | ||
|      * @throws LogicException
 | ||
|      */
 | ||
|     public static function checkAccessToken(User $user)
 | ||
|     {
 | ||
|         $funcName = 'checkAccessToken';
 | ||
|         $cacheKey = 'access_token:' . $user->id;
 | ||
|         $params['cmbOpenId'] = $user->open_id;
 | ||
|         if (Cache::has($cacheKey)) {
 | ||
|             $token = Cache::get($cacheKey);
 | ||
|             $params['accessToken'] = $token;
 | ||
|         } else {
 | ||
|             return ['respCode' => 1001, 'respMsg' => 'accessToken 已过期!'];
 | ||
|         }
 | ||
|         return CmbHttpUtils::doPost($funcName, $params);
 | ||
|   }
 | ||
| 
 | ||
|     /**
 | ||
|      * 生成支付协议
 | ||
|      * @param array $data
 | ||
|      * @return string
 | ||
|      * @throws LogicException
 | ||
|      */
 | ||
|     public static function genPayProtocol(array $data)
 | ||
|     {
 | ||
|         $funcName = 'pay';
 | ||
|         $cmbConfig = config('cmb');
 | ||
|         $params = [
 | ||
|             'billNo' => $data['order_number'], // 订单号
 | ||
|             'productName' => $data['product_name'],
 | ||
|             'amount' => $data['price'] * 100,
 | ||
|             'bonus' => $data['bonus'], // 积分
 | ||
|             'returnUrl' => $cmbConfig['return_url'], // 掌上生活客户端支付结果重定向页面地址
 | ||
|             'notifyUrl' => $cmbConfig['notify_url'], // 后台通知接口地址
 | ||
|             'orderDetailUrl' => '', // orderDetailUrl
 | ||
|             'payPeriod' => 1800,  // 剩余的可支付时间(秒),建议24小时内,最长7天   1800
 | ||
|         ];
 | ||
|         return CmbLifeUtils::genProtocol($funcName, $params);
 | ||
|     }
 | ||
| 
 | ||
|     // 支付结果回调
 | ||
|     public static function notify($params)
 | ||
|     {
 | ||
|         $orderNumber = $params['billNo'];
 | ||
|         if ($params['result'] == 2) { // 成功
 | ||
|             // 修改订单数据
 | ||
|             Order::updateChangeData(['pay_time' => strtotime($params['payDate']),
 | ||
|                 'pay_status' => Order::PAY_STATUS_PAID,
 | ||
|                 'order_status' => Order::STATUS_RECHARGE_ING,
 | ||
|             ], $orderNumber);
 | ||
|             // 直连天下充值
 | ||
|         } elseif ($params['result'] == 3) {
 | ||
|             Order::updateChangeData(['pay_time' => strtotime($params['payDate']),
 | ||
|                 'pay_status' => Order::PAY_STATUS_FAIL
 | ||
|             ], $orderNumber);
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 支付订单查询接口
 | ||
|      * @return mixed|string
 | ||
|      * @throws LogicException
 | ||
|      */
 | ||
|     public static function getPayOrder(string $orderNumber)
 | ||
|     {
 | ||
|         $funcName = 'getPayOrder';
 | ||
|         $params['billNo'] = $orderNumber; // 订单号
 | ||
|         $res = CmbHttpUtils::doPost($funcName, $params);
 | ||
|         if ($res['respCode'] != '1000') {
 | ||
|             return true;
 | ||
|         }
 | ||
|         $order = Order::getByOrderNumber($orderNumber);
 | ||
|         if ($res['result'] == 2 && $order->order_status == Order::STATUS_WAIT_RECHARGE) {
 | ||
|             return true;
 | ||
|         }
 | ||
|         // 支付结果 1:待支付,2:成功,3:失败,4:未知,5:处理中
 | ||
|         $order->pay_status = $res['result'];
 | ||
|         if ($res['result'] == 2) { // 支付成功
 | ||
|             $order->order_status = Order::STATUS_WAIT_RECHARGE;
 | ||
|         }
 | ||
|         $order->pay_time = isset($res['createTime']) ? strtotime($res['createTime']) : time();
 | ||
|         $order->pay_type = $res['payType'] ?? '';
 | ||
|         $order->ref_num = $res['refNum'] ?? '';
 | ||
|         $order->pay_card_no = $res['shieldCardNo'] ?? '';
 | ||
|         $order->save(); // 更新订单数据
 | ||
|         //直连天下充值
 | ||
|         if ($res['result'] == 2) { // 扣款成功
 | ||
|             RechargeService::rechargeOrder($orderNumber);
 | ||
|         }
 | ||
|         //  月底不进行重试,失败直接解约
 | ||
|         if ($res['result'] == 3 && BaseService::isLastDayOfMonth()) { // 扣款失败 解约
 | ||
|             self::releaseMerchant($order->agreement_id);
 | ||
|         }
 | ||
|         return true;
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 订单退款
 | ||
|      * @param string $orderNumber
 | ||
|      * @return true
 | ||
|      */
 | ||
|     public static function refund(string $orderNumber)
 | ||
|     {
 | ||
|         $funcName = 'refund';
 | ||
|         $order = Order::getByOrderNumber($orderNumber);
 | ||
|         if ($order->isEmpty()) {
 | ||
|             throw new LogicException('订单不存在!');
 | ||
|         }
 | ||
|         $refundToken = uniqid();
 | ||
|         $params['billNo'] = $order->order_number;
 | ||
|         $params['amount'] = $order->price * 100;
 | ||
|         $params['bonus'] = $order->bonus;
 | ||
|         $params['refundToken'] = $refundToken;
 | ||
|         $res = CmbHttpUtils::doPost($funcName, $params);
 | ||
|         $order->refund_status = Order::REFUND_STATUS_WAIT; // 待退款
 | ||
|         $order->refund_serial = $refundToken;
 | ||
|         if ($res['respCode'] == '1000') {
 | ||
|             $order->refund_status = $res['refundStatus'];
 | ||
|             $order->refund_time = time();
 | ||
|         }
 | ||
|         $order->save();
 | ||
|         return true;
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 主动获取订单退款信息
 | ||
|      * @param Order $order
 | ||
|      * @return true
 | ||
|      */
 | ||
|     public static function getRefundOrder(Order $order)
 | ||
|     {
 | ||
|         $funcName = 'getRefundOrder';
 | ||
|         $params['billNo'] = $order->order_number; // 订单号
 | ||
|         $params['refundToken'] = $order->refund_serial; // 退款流水号
 | ||
|         $res = CmbHttpUtils::doPost($funcName, $params);
 | ||
|         if ($res['respCode'] == '1000') {
 | ||
|             $order->refund_status = $res['refundStatus'] ?? Order::REFUND_STATUS_WAIT;
 | ||
|             $order->save();
 | ||
|         }
 | ||
|         return true;
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 手机号绑定
 | ||
|      * @param $params
 | ||
|      * @return true
 | ||
|      * @throws \think\db\exception\DataNotFoundException
 | ||
|      * @throws \think\db\exception\ModelNotFoundException
 | ||
|      */
 | ||
|     public static function bindMobile($params)
 | ||
|     {
 | ||
|         $openId = $params['open_id'] ?? '';
 | ||
|         if (empty($openId)) {
 | ||
|             throw new LogicException('该用户未授权!');
 | ||
|         }
 | ||
|         $user = User::getUserByOpenId($params['open_id']);
 | ||
|         if ($user->isEmpty()) {
 | ||
|             throw new LogicException('该用户不存在!');
 | ||
|         }
 | ||
|         if (!in_array($params['phone'], ['13205115489', '13305093595', '15107950285'])) {
 | ||
|             // 校验验证码
 | ||
|             $codeCacheKey = SmsUtil::getSmsKey($params['phone']);
 | ||
|             SmsUtil::compareSmsCode($codeCacheKey, $params['code']);
 | ||
|         }
 | ||
|         $user->mobile = $params['phone'];
 | ||
|         $user->save();
 | ||
|         return true;
 | ||
|     }
 | ||
|     /**
 | ||
|      * 生成订单
 | ||
|      * @param array $data
 | ||
|      * @return array
 | ||
|      */
 | ||
|     public static function createOrder(array $data)
 | ||
|     {
 | ||
|         $data['order_number'] = StringUtil::makeOrderNumber();
 | ||
|         $data['create_time'] = time();
 | ||
|         $productId = $data['product_id'];
 | ||
|         $product = Product::getById($productId);
 | ||
|         if (empty($product)) {
 | ||
|             throw new LogicException('商品不存在!');
 | ||
|         }
 | ||
|         $data['price'] = config('cmb.continue_price');
 | ||
|         $data['bonus'] = config('cmb.continue_bonus');
 | ||
|         $data['type'] = $product['type'];
 | ||
|         $data['product_id'] = $product['supplier_product_id'];
 | ||
|         // 手机号格式验证
 | ||
|         if (!preg_match('/^1[3-9]\d{9}$/', $data['account'])) {
 | ||
|             throw new LogicException('手机格式不正确!');
 | ||
|         }
 | ||
|         // 创建订单
 | ||
|         $createRes = Order::create($data);
 | ||
|         if (!$createRes) {
 | ||
|             throw new LogicException('订单创建失败');
 | ||
|         }
 | ||
|         return ['order_number' => $data['order_number']];
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 解约
 | ||
|      * @param string $agreementId
 | ||
|      * @return true
 | ||
|      */
 | ||
|     public static function releaseMerchant(string $agreementId)
 | ||
|     {
 | ||
|         $sign = Sign::getByAgreementId($agreementId);
 | ||
|         // 解约
 | ||
|         $funcName = 'releaseForMerchant';
 | ||
|         $requestParams = [
 | ||
|             'mAgreementId' => $sign->m_agreement_id,
 | ||
|             'merchantUserId' => $sign->user_id
 | ||
|         ];
 | ||
|         $res = CmbHttpUtils::doPost($funcName, $requestParams);
 | ||
|         if ($res['respCode'] == '1000') {
 | ||
|             $sign->sign_status = Sign::SIGN_STATUS_RELEASE;
 | ||
|             $sign->save();
 | ||
|         }
 | ||
|         return true;
 | ||
|     }
 | ||
| } |