|
|
|
@ -2,13 +2,17 @@ |
|
|
|
|
|
|
|
namespace App\Service\v3; |
|
|
|
|
|
|
|
use App\Commons\Log; |
|
|
|
use App\Constants\v3\ErrorCode; |
|
|
|
use App\Constants\v3\LogLabel; |
|
|
|
use App\Constants\v3\OrderState; |
|
|
|
use App\Exception\BusinessException; |
|
|
|
use App\Exception\ErrorCodeException; |
|
|
|
use App\Model\v3\CcbPayment; |
|
|
|
use App\Model\v3\OrderMain; |
|
|
|
use App\Model\v3\Store; |
|
|
|
use App\Model\v3\User; |
|
|
|
use Hyperf\Di\Annotation\Inject; |
|
|
|
use Hyperf\Guzzle\ClientFactory; |
|
|
|
use Hyperf\Logger\LoggerFactory; |
|
|
|
|
|
|
|
@ -38,6 +42,18 @@ class CcbPaymentService |
|
|
|
*/ |
|
|
|
private $mktId; |
|
|
|
|
|
|
|
/** |
|
|
|
* 我方商家编号 |
|
|
|
* @var string |
|
|
|
*/ |
|
|
|
private $merchantId; |
|
|
|
|
|
|
|
/** |
|
|
|
* 支付方式 |
|
|
|
* @var string |
|
|
|
*/ |
|
|
|
private $pymdCd; |
|
|
|
|
|
|
|
/** |
|
|
|
* 我方私钥 |
|
|
|
* @var resource |
|
|
|
@ -72,6 +88,12 @@ class CcbPaymentService |
|
|
|
*/ |
|
|
|
private $logger; |
|
|
|
|
|
|
|
/** |
|
|
|
* @Inject |
|
|
|
* @var Log |
|
|
|
*/ |
|
|
|
protected $log; |
|
|
|
|
|
|
|
public function __construct(ClientFactory $clientFactory, LoggerFactory $loggerFactory) |
|
|
|
{ |
|
|
|
$this->clientFactory = $clientFactory; |
|
|
|
@ -79,6 +101,8 @@ class CcbPaymentService |
|
|
|
|
|
|
|
$this->isDebug = config('ccb.debug'); |
|
|
|
$this->mktId = config('ccb.mkt_id'); |
|
|
|
$this->merchantId = config('ccb.merchant_id'); |
|
|
|
$this->pymdCd = config('ccb.pymd_cd'); |
|
|
|
|
|
|
|
$selfPrivateKey = config('ccb.self_private_key'); |
|
|
|
$selfPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n".chunk_split($selfPrivateKey, 64, "\n")."-----END RSA PRIVATE KEY-----\n"; |
|
|
|
@ -269,18 +293,22 @@ class CcbPaymentService |
|
|
|
return date('YmdHis').mt_rand(10000, 99999).mt_rand(10000, 99999); |
|
|
|
} |
|
|
|
|
|
|
|
private function genMainOrderNo() |
|
|
|
{ |
|
|
|
return time().mt_rand(10000, 99999).mt_rand(10000, 99999); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 3.1 生成支付订单接口 |
|
|
|
* @param string $Main_Ordr_No 主订单编号 |
|
|
|
* @param string $Ordr_Tamt 订单总金额 |
|
|
|
* @param string $Txn_Tamt 交易总金额(实付) |
|
|
|
* @param string $Pymd_Cd 支付方式:03为H5,05为小程序 |
|
|
|
* @param string $Sub_Appid 当前调起支付的小程序appid |
|
|
|
* @param string $Sub_Openid 用户在小程序下的openid |
|
|
|
* @param string|null $Sub_Appid 当前调起支付的小程序appid |
|
|
|
* @param string|null $Sub_Openid 用户在小程序下的openid |
|
|
|
* @param array $Orderlist 子订单列表 |
|
|
|
* @return array |
|
|
|
*/ |
|
|
|
public function gatherPlaceorder(string $Main_Ordr_No, string $Ordr_Tamt, string $Txn_Tamt, string $Pymd_Cd, string $Sub_Appid, string $Sub_Openid, array $Orderlist) |
|
|
|
public function gatherPlaceorder(string $Main_Ordr_No, string $Ordr_Tamt, string $Txn_Tamt, ?string $Sub_Appid, ?string $Sub_Openid, array $Orderlist) |
|
|
|
{ |
|
|
|
$uri = '/online/direct/gatherPlaceorder'; |
|
|
|
|
|
|
|
@ -291,19 +319,22 @@ class CcbPaymentService |
|
|
|
'Ittparty_Jrnl_No' => $this->genSerialNumber(), |
|
|
|
'Mkt_Id' => $this->mktId, |
|
|
|
'Main_Ordr_No' => $Main_Ordr_No, |
|
|
|
'Pymd_Cd' => $Pymd_Cd, |
|
|
|
'Pymd_Cd' => $this->pymdCd, |
|
|
|
'Py_Ordr_Tpcd' => '04', |
|
|
|
'Py_Rslt_Ntc_Sn' => '1', |
|
|
|
'Ccy' => '156', |
|
|
|
'Ordr_Tamt' => $Ordr_Tamt, |
|
|
|
'Txn_Tamt' => $Txn_Tamt, |
|
|
|
'Sub_Appid' => $Sub_Appid, |
|
|
|
'Sub_Openid' => $Sub_Openid, |
|
|
|
'Order_Time_Out' => '1800', |
|
|
|
'Orderlist' => $Orderlist, |
|
|
|
'Vno' => '4', |
|
|
|
]; |
|
|
|
|
|
|
|
if ($this->pymdCd == '05') { |
|
|
|
$params['Sub_Appid'] = $Sub_Appid; |
|
|
|
$params['Sub_Openid'] = $Sub_Openid; |
|
|
|
} |
|
|
|
|
|
|
|
return $this->apiRequest($uri, $params); |
|
|
|
} |
|
|
|
|
|
|
|
@ -313,11 +344,12 @@ class CcbPaymentService |
|
|
|
* @param string $Cmdty_Ordr_No 子订单编号 |
|
|
|
* @param string $Ordr_Amt 订单金额 |
|
|
|
* @param string $Txnamt 实付金额 |
|
|
|
* @param string $Cmdty_Dsc 商品描述 |
|
|
|
* @return string[] |
|
|
|
*/ |
|
|
|
public function subOrderListItem(string $Mkt_Mrch_Id, string $Cmdty_Ordr_No, string $Ordr_Amt, string $Txnamt) |
|
|
|
public function subOrderListItem(string $Mkt_Mrch_Id, string $Cmdty_Ordr_No, string $Ordr_Amt, string $Txnamt, string $Cmdty_Dsc) |
|
|
|
{ |
|
|
|
return compact('Mkt_Mrch_Id', 'Cmdty_Ordr_No', 'Ordr_Amt', 'Txnamt'); |
|
|
|
return compact('Mkt_Mrch_Id', 'Cmdty_Ordr_No', 'Ordr_Amt', 'Txnamt', 'Cmdty_Dsc'); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
@ -457,4 +489,140 @@ class CcbPaymentService |
|
|
|
return $this->apiRequest($uri, $params); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 创建支付订单 |
|
|
|
* @param $globalOrderId |
|
|
|
* @param $userId |
|
|
|
* @return array |
|
|
|
* @throws \GuzzleHttp\Exception\GuzzleException |
|
|
|
*/ |
|
|
|
public function createCcbPayment($globalOrderId, $userId) |
|
|
|
{ |
|
|
|
try { |
|
|
|
// 待支付的,未超时(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); |
|
|
|
} |
|
|
|
|
|
|
|
$user = User::select('openid')->find($userId); |
|
|
|
|
|
|
|
$model = new CcbPayment(); |
|
|
|
$model->order_main_id = $orderMain->global_order_id; |
|
|
|
$model->main_ordr_no = $this->genMainOrderNo(); |
|
|
|
$model->pymd_cd = $this->pymdCd; |
|
|
|
if ($this->pymdCd == '05') { |
|
|
|
$model->sub_appid = config('wechat.applet.app_id'); |
|
|
|
$model->sub_openid = $user->openid; |
|
|
|
} |
|
|
|
$model->py_ordr_tpcd = '04'; |
|
|
|
$model->ordr_tamt = $orderMain->money; |
|
|
|
$model->txn_tamt = $orderMain->money; |
|
|
|
$subOrderList = []; |
|
|
|
|
|
|
|
// 运费判断
|
|
|
|
if (bccomp($orderMain->delivery_money, '0', 2) == 1) { |
|
|
|
$subOrderList[] = $this->subOrderListItem( |
|
|
|
$this->merchantId, |
|
|
|
$model->main_ordr_no.'D', |
|
|
|
$orderMain->delivery_money, |
|
|
|
$orderMain->delivery_money, |
|
|
|
'配送费' |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
// 我方分润比例%
|
|
|
|
$selfProfitRatio = config('ccb.self_profit_ratio'); |
|
|
|
|
|
|
|
if (bccomp($selfProfitRatio, '0', 3) == 0) { |
|
|
|
throw new BusinessException(500, '未配置分润比例,请联系管理员'); |
|
|
|
} |
|
|
|
|
|
|
|
foreach ($orderMain->orders as $order) { |
|
|
|
if (empty($order->store->ccb_merchant_id)) { |
|
|
|
throw new BusinessException(500, '店铺'.$order->store_id.'未配置商户编号,请联系管理员'); |
|
|
|
} |
|
|
|
foreach ($order->orderGoods as $orderGoods) { |
|
|
|
$goodsMoney = bcmul($orderGoods->price, (string)$orderGoods->number, 2); |
|
|
|
$selfProfitMoney = bcmul($goodsMoney, $selfProfitRatio, 2); |
|
|
|
$merchantProfitMoney = bcsub($goodsMoney, $selfProfitMoney, 2); |
|
|
|
// 平台抽佣后最小金额不能为0
|
|
|
|
if (bccomp($merchantProfitMoney, '0', 2) == 0) { |
|
|
|
$selfProfitMoney = '0.00'; |
|
|
|
$merchantProfitMoney = $goodsMoney; |
|
|
|
} |
|
|
|
$subOrderList[] = $this->subOrderListItem( |
|
|
|
$order->store->ccb_merchant_id, |
|
|
|
$model->main_ordr_no.'G'.$orderGoods->id.'N01', |
|
|
|
$merchantProfitMoney, |
|
|
|
$merchantProfitMoney, |
|
|
|
$orderGoods->name.'(分佣到账)' |
|
|
|
); |
|
|
|
if (bccomp($selfProfitMoney, '0', 2) == 1) { |
|
|
|
$subOrderList[] = $this->subOrderListItem( |
|
|
|
$this->merchantId, |
|
|
|
$model->main_ordr_no.'G'.$orderGoods->id.'N02', |
|
|
|
$selfProfitMoney, |
|
|
|
$selfProfitMoney, |
|
|
|
$orderGoods->name.'(平台抽佣)' |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
$model->orderlist = json_encode($subOrderList); |
|
|
|
$model->save(); |
|
|
|
|
|
|
|
$result = $this->gatherPlaceorder( |
|
|
|
$model->main_ordr_no, |
|
|
|
$model->ordr_tamt, |
|
|
|
$model->txn_tamt, |
|
|
|
$model->sub_appid, |
|
|
|
$model->sub_openid, |
|
|
|
$subOrderList |
|
|
|
); |
|
|
|
|
|
|
|
$model->py_trn_no = $result['Py_Trn_No']; |
|
|
|
$model->prim_ordr_no = $result['Prim_Ordr_No']; |
|
|
|
$model->ordr_gen_tm = $result['Ittparty_Tms']; |
|
|
|
if (isset($result['Cshdk_Url'])) { |
|
|
|
$model->cshdk_url = $result['Cshdk_Url']; |
|
|
|
} |
|
|
|
if ($this->pymdCd == '05') { |
|
|
|
$model->rtn_par_data = json_encode($result['Rtn_Par_Data']); |
|
|
|
} |
|
|
|
$model->ordr_stcd = $result['Ordr_Stcd']; |
|
|
|
$model->rtn_orderlist = json_encode($result['Orderlist']); |
|
|
|
$model->save(); |
|
|
|
|
|
|
|
if ($this->pymdCd == '05') { |
|
|
|
// 返回支付参数给前端
|
|
|
|
$parameters = [ |
|
|
|
'appId' => $result['Rtn_Par_Data']['appId'], |
|
|
|
'timeStamp' => $result['Rtn_Par_Data']['timeStamp'], |
|
|
|
'nonceStr' => $result['Rtn_Par_Data']['nonceStr'], |
|
|
|
'package' => $result['Rtn_Par_Data']['package'], |
|
|
|
'signType' => $result['Rtn_Par_Data']['signType'], |
|
|
|
'paySign' => $result['Rtn_Par_Data']['paySign'], |
|
|
|
]; |
|
|
|
} else { |
|
|
|
$parameters = [ |
|
|
|
'Cshdk_Url' => $model->cshdk_url, |
|
|
|
]; |
|
|
|
} |
|
|
|
|
|
|
|
$parameters['order_main_id'] = $orderMain->global_order_id; |
|
|
|
|
|
|
|
return $parameters; |
|
|
|
|
|
|
|
} catch (\Exception $e) { |
|
|
|
$this->log->event(LogLabel::ORDER_PAYMENT_LOG, ['payment_do_exception_msg' => $e->getMessage()]); |
|
|
|
throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, '[稍后重试]'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |