You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

187 lines
5.8 KiB

<?php
namespace App\Service\v3\Implementations;
use App\Commons\Log;
use App\Constants\v3\ErrorCode;
use App\Constants\v3\LogLabel;
use App\Constants\v3\OrderState;
use App\Constants\v3\OrderType;
use App\Exception\ErrorCodeException;
use App\Model\v3\OrderMain;
use App\Model\v3\User;
use App\Service\v3\Interfaces\GoodsActivityServiceInterface;
use App\Service\v3\Interfaces\PaymentServiceInterface;
use EasyWeChat\Factory;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Guzzle\CoroutineHandler;
use Hyperf\Di\Annotation\Inject;
class PaymentService implements PaymentServiceInterface
{
/**
* @Inject
* @var Log
*/
protected $log;
/**
* @Inject
* @var GoodsActivityServiceInterface
*/
protected $goodsActivityService;
public function do($globalOrderId, $money, $userId, $notifyUrl)
{
try {
$config = config('wxpay');
$app = Factory::payment($config);
$app['guzzle_handler'] = CoroutineHandler::class;
// 待支付的,未超时(15min,900sec)的订单
$orderMain = OrderMain::query()
->where(['state' => OrderState::UNPAID, 'global_order_id' => $globalOrderId, 'user_id' => $userId])
->where('created_at', '>=', (time()-900))
->first();
if (empty($orderMain)) {
throw new ErrorCodeException(ErrorCode::ORDER_NOT_AVAILABLE, '[支付订单号]'.$globalOrderId);
}
$payMoney = bcmul((string)$orderMain->money, 100, 0);
if (env('APP_ENV') != 'prod' && $orderMain->type == OrderType::ONLINE) {
$payMoney = 1;
}
$user = User::select('openid')->find($userId);
$result = $app->order->unify([
'body' => '懒族生活',
'out_trade_no' => $orderMain->global_order_id,
'total_fee' => $payMoney,
'notify_url' => $notifyUrl,
'trade_type' => 'JSAPI',
'openid' => $user['openid'],
]);
if ($result['return_code'] == 'FAIL') {
throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, '[支付失败]'.$result['return_msg']);
}
// 返回支付参数给前端
$parameters = [
'appId' => $result['appid'],
'timeStamp' => '' . time() . '',
'nonceStr' => uniqid(),
'package' => 'prepay_id=' . $result['prepay_id'],
'signType' => 'MD5'
];
$parameters['paySign'] = $this->signture($parameters, $config['key']);
$parameters['order_main_id'] = $orderMain->id;
return $parameters;
} catch (\Exception $e) {
$this->log->event(LogLabel::ORDER_PAYMENT_LOG, ['payment_exception_msg' => $e->getMessage()]);
throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, '[支付失败]'.$e->getMessage());
}
}
public function check()
{
// TODO: Implement check() method.
}
public function undo()
{
// TODO: Implement undo() method.
}
/**
* 企业付款到微信钱包
* @param $money
* @param $tradeNo
* @param $openId
* @param $userName
* @param string $desc
* @param string $checkName
* @throws GuzzleException
*/
public function payToWx($money, $tradeNo, $openId, $userName, $desc = '', $checkName = 'NO_CHECK')
{
$config = config('wxpay');
$app = Factory::payment($config);
$app['guzzle_handler'] = CoroutineHandler::class;
$result = $app->transfer->toBalance([
'partner_trade_no' => $tradeNo, // 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有符号)
'openid' => $openId,
'check_name' => $checkName, // NO_CHECK:不校验真实姓名, FORCE_CHECK:强校验真实姓名
're_user_name' => $userName, // 如果 check_name 设置为FORCE_CHECK,则必填用户真实姓名
'amount' => $money, // 企业付款金额,单位为分
'desc' => $desc, // 企业付款操作说明信息
]);
if ($result['return_code'] != 'SUCCESS') {
$this->log->event(LogLabel::PAY_TO_WX_FAIL_LOG, [
'exception_payToWx' => $result['return_msg'],
'result' => json_encode($result),
'desc' => $desc
]);
throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, $result['return_msg']);
}
if ($result['result_code'] != 'SUCCESS') {
$this->log->event(LogLabel::PAY_TO_WX_FAIL_LOG, [
'exception_payToWx' => $result['err_code_des'],
'result' => json_encode($result),
'desc' => $desc
]);
throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, $result['err_code_des']);
}
return true;
}
/**
* 支付参数加签
* @param $parameters
* @param $key
* @return string
*/
private function signture($parameters, $key)
{
// 按字典序排序参数
ksort($parameters);
// http_query
$queryParams = $this->http_query($parameters);
// 加入KEY
$queryParams = $queryParams . "&key=" . $key;
// MD5加密
$queryParams = md5($queryParams);
// 字符转为大写
return strtoupper($queryParams);
}
/**
* 参数转为http query字串
* @param $parameters
* @return string
*/
private function http_query($parameters) {
$http_query = [];
foreach ($parameters as $key => $value) {
$http_query[] = $key.'='.$value;
}
return implode('&', $http_query);
}
}