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;
|
||
}
|
||
} |