|
|
@ -8,7 +8,9 @@ |
|
|
|
|
|
|
|
namespace api\logic; |
|
|
|
|
|
|
|
use backend\modules\shop\models\ars\Order; |
|
|
|
use backend\modules\shop\models\ars\PaymentLog; |
|
|
|
use backend\modules\shop\models\ars\RefundLog; |
|
|
|
use backend\modules\shop\models\ars\WxPayConfig; |
|
|
|
use Yii; |
|
|
|
use EasyWeChat\Factory; |
|
|
@ -17,12 +19,21 @@ use yii\helpers\Json; |
|
|
|
use yii\httpclient\Client; |
|
|
|
use yii\web\BadRequestHttpException; |
|
|
|
use yii\base\BaseObject; |
|
|
|
use yii\web\NotFoundHttpException; |
|
|
|
|
|
|
|
class WxPaymentLogic extends BaseObject |
|
|
|
{ |
|
|
|
/*支付类型*/ |
|
|
|
const PAY_TYPE_WEB = 1; |
|
|
|
const PAY_TYPE_MINI_PROGRAM = 2; |
|
|
|
/*支付状态*/ |
|
|
|
const STATUS_PAYMENT_WAITING = 0; |
|
|
|
const STATUS_PAYMENT_SUCCESS = 1; |
|
|
|
/*退款状态*/ |
|
|
|
const STATUS_REFUND_WAIT = 0; //退款待审核
|
|
|
|
const STATUS_REFUND_CONFIRM = 1; //退款待确认
|
|
|
|
const STATUS_REFUND_SUCCESS = 2; //退款成功
|
|
|
|
const STATUS_REFUND_PORTION = 3; //部分退款
|
|
|
|
/*发起支付方式*/ |
|
|
|
const TRADE_TYPE_JS_API = 'JSAPI'; |
|
|
|
|
|
|
@ -36,10 +47,12 @@ class WxPaymentLogic extends BaseObject |
|
|
|
public $payType; |
|
|
|
public $app; |
|
|
|
public $order; |
|
|
|
public $viewAction = 'view'; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* @param $payType |
|
|
|
* @return mixed |
|
|
|
* @throws BadRequestHttpException |
|
|
|
* @throws Exception |
|
|
|
* 微信统一下单 |
|
|
@ -48,10 +61,9 @@ class WxPaymentLogic extends BaseObject |
|
|
|
{ |
|
|
|
$this->payType = $payType; |
|
|
|
$unifyParams = $this->applyPaymentData(); |
|
|
|
$this->unify($unifyParams); |
|
|
|
return $this->unify($unifyParams); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* @return array |
|
|
|
* @throws BadRequestHttpException |
|
|
@ -96,13 +108,13 @@ class WxPaymentLogic extends BaseObject |
|
|
|
$paymentLog->payment_amount = $paymentAmount; |
|
|
|
$paymentLog->notify_url = $notifyUrl; |
|
|
|
$paymentLog->type = $this->payType; |
|
|
|
$paymentLog->status = PaymentLog::PAYMENT_STATUS_WAITING; |
|
|
|
$paymentLog->status = self::STATUS_PAYMENT_WAITING; |
|
|
|
if (!$paymentLog->save()) { |
|
|
|
throw new Exception(Helper::errorMessageStr($paymentLog->errors)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private function getPaymentApp() |
|
|
|
private function getApp() |
|
|
|
{ |
|
|
|
$this->initObject(); |
|
|
|
$config = [ |
|
|
@ -113,11 +125,11 @@ class WxPaymentLogic extends BaseObject |
|
|
|
'key_path' => $this->keyPath, |
|
|
|
'notify_url' => $this->notifyUrl, |
|
|
|
'trade_type' => $this->tradeType, |
|
|
|
'sandbox' => true, // 设置为 false 或注释则关闭沙箱模式
|
|
|
|
// 'sandbox' => true, // 设置为 false 或注释则关闭沙箱模式
|
|
|
|
]; |
|
|
|
$this->app = Factory::payment($config); |
|
|
|
// 判断当前是否为沙箱模式:
|
|
|
|
$this->app->inSandbox(); |
|
|
|
// $this->app->inSandbox();
|
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -127,16 +139,16 @@ class WxPaymentLogic extends BaseObject |
|
|
|
{ |
|
|
|
$path = Yii::getAlias('@backend'); |
|
|
|
$wxPayConfig = WxPayConfig::find()->one(); |
|
|
|
switch ($this->payType) { |
|
|
|
case self::PAY_TYPE_WEB: |
|
|
|
// $wxConfig = WxConfig::find()->one();
|
|
|
|
// switch ($this->payType) {
|
|
|
|
// case self::PAY_TYPE_WEB:
|
|
|
|
// $this->appId = trim($wxConfig->wx_appId);
|
|
|
|
// break;
|
|
|
|
// case self::PAY_TYPE_MINI_PROGRAM:
|
|
|
|
// $this->appId = trim($wxConfig->mini_program_appId);
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// $this->appId = trim($wxConfig->appid);
|
|
|
|
break; |
|
|
|
case self::PAY_TYPE_MINI_PROGRAM: |
|
|
|
// $miniProgramConfig = MiniProgramConfig::find()->one();
|
|
|
|
// $this->appId = trim($miniProgramConfig->appid);
|
|
|
|
break; |
|
|
|
} |
|
|
|
$this->mchId = $wxPayConfig->mch_id; |
|
|
|
$this->certPath = trim($path . $wxPayConfig->cert_path); |
|
|
|
$this->keyPath = trim($path . $wxPayConfig->key_path); |
|
|
@ -150,7 +162,7 @@ class WxPaymentLogic extends BaseObject |
|
|
|
*/ |
|
|
|
private function unify($unifyParams) |
|
|
|
{ |
|
|
|
$this->getPaymentApp(); |
|
|
|
$this->getApp(); |
|
|
|
return $this->app->order->unify($unifyParams); |
|
|
|
} |
|
|
|
|
|
|
@ -174,14 +186,17 @@ class WxPaymentLogic extends BaseObject |
|
|
|
if ($notifyData->result_code != 'SUCCESS' || $notifyData->return_code != 'SUCCESS') { |
|
|
|
throw new BadRequestHttpException('result_code or return_code is false'); |
|
|
|
} |
|
|
|
|
|
|
|
$paymentLog = PaymentLog::findOne(['order_id' => $notifyData->out_trade_no]); |
|
|
|
$this->notifyUrl = Yii::$app->request->hostInfo . $paymentLog->notify_url; |
|
|
|
$paymentLog->mch_id = $notifyData->mch_id; |
|
|
|
$paymentLog->wx_refund_id = $notifyData->transaction_id; //交易号
|
|
|
|
$paymentLog->status = PaymentLog::PAYMENT_STATUS_SUCCESS; |
|
|
|
$paymentLog->wx_payment_id = $notifyData->transaction_id; //交易号
|
|
|
|
$paymentLog->status = self::STATUS_PAYMENT_SUCCESS; |
|
|
|
$paymentLog->payment_at = time(); |
|
|
|
if (!$paymentLog->save()) { |
|
|
|
throw new Exception(Helper::errorMessageStr($paymentLog->errors)); |
|
|
|
} |
|
|
|
|
|
|
|
if (!$tra->commit()) { |
|
|
|
throw new Exception('保存数据失败'); |
|
|
|
} |
|
|
@ -195,13 +210,16 @@ class WxPaymentLogic extends BaseObject |
|
|
|
Yii::info($e->getMessage(), 'notify'); |
|
|
|
return false; |
|
|
|
} catch (BadRequestHttpException $e) { |
|
|
|
$tra->rollBack(); |
|
|
|
$this->forwardNotify($notifyData, false); |
|
|
|
Yii::info($e->getMessage(), 'notify'); |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param $notifyData |
|
|
|
* @param $notifyData $tra->rollBack(); |
|
|
|
|
|
|
|
* @param $status |
|
|
|
* @return bool |
|
|
|
* @throws \yii\base\InvalidConfigException |
|
|
@ -230,6 +248,104 @@ class WxPaymentLogic extends BaseObject |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @return bool |
|
|
|
* @throws BadRequestHttpException |
|
|
|
* @throws Exception |
|
|
|
* @throws NotFoundHttpException |
|
|
|
* 申请退款 |
|
|
|
*/ |
|
|
|
public function applyRefund() |
|
|
|
{ |
|
|
|
$orderId = Yii::$app->request->getBodyParam('order_id'); |
|
|
|
$refundId = Yii::$app->request->getBodyParam('wx_refund_id'); |
|
|
|
$refundAmount = Yii::$app->request->getBodyParam('refund_amount'); |
|
|
|
$refundAccount = Yii::$app->request->getBodyParam('refund_account'); |
|
|
|
$reason = Yii::$app->request->getBodyParam('reason'); |
|
|
|
if (empty($orderId) || empty($refundId) || empty($refundAmount) || empty($reason)) { |
|
|
|
throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS); |
|
|
|
} |
|
|
|
$paymentLog = PaymentLog::findOne(['order_id' => $orderId]); |
|
|
|
if (empty($paymentLog)) { |
|
|
|
throw new NotFoundHttpException('订单支付信息未找到'); |
|
|
|
} |
|
|
|
if (RefundLog::findOne(['order_id' => $orderId, 'status' => self::STATUS_REFUND_WAIT])) { |
|
|
|
throw new BadRequestHttpException('此订单存在等待审核的退款申请'); |
|
|
|
} |
|
|
|
|
|
|
|
$refundedAmount = RefundLog::find() |
|
|
|
->where(['order_id' => $orderId, 'status' => self::STATUS_PAYMENT_SUCCESS]) |
|
|
|
->sum('refund_amount') ?? 0; |
|
|
|
|
|
|
|
$refundLog = new RefundLog(); |
|
|
|
$refundLog->order_id = $orderId; |
|
|
|
$refundLog->wx_refund_id = Helper::timeRandomNum(3, 'P'); |
|
|
|
$refundLog->reason = $reason; |
|
|
|
$refundLog->order_amount = $paymentLog->payment_amount; |
|
|
|
$refundLog->refund_amount = $refundAmount; |
|
|
|
$refundLog->refunded_amount = $refundedAmount; |
|
|
|
$refundLog->type = $paymentLog->type; |
|
|
|
$refundLog->status = self::STATUS_REFUND_WAIT; |
|
|
|
$refundLog->refund_account = $refundAccount; |
|
|
|
$refundLog->applyed_at = time(); |
|
|
|
if (!$refundLog->save()) { |
|
|
|
throw new Exception(Helper::errorMessageStr($refundLog->errors)); |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @return mixed |
|
|
|
* @throws BadRequestHttpException |
|
|
|
* @throws Exception |
|
|
|
* @throws NotFoundHttpException |
|
|
|
* 退款 |
|
|
|
*/ |
|
|
|
public function refund() |
|
|
|
{ |
|
|
|
$orderId = Yii::$app->request->getbodyParam('order_id'); |
|
|
|
if (empty($orderId)) { |
|
|
|
throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS); |
|
|
|
} |
|
|
|
$paymentLog = PaymentLog::findOne(['order_id' => $orderId]); |
|
|
|
if (empty($paymentLog)) { |
|
|
|
throw new NotFoundHttpException('订单支付信息未找到'); |
|
|
|
} |
|
|
|
$refundLog = RefundLog::findOne(['order_id' => $orderId, 'status' => self::STATUS_REFUND_WAIT]); |
|
|
|
if (!$refundLog) { |
|
|
|
throw new NotFoundHttpException('订单退款信息未找到'); |
|
|
|
} |
|
|
|
|
|
|
|
/*参数分别为:微信订单号、商户退款单号、订单金额、退款金额、其他参数*/ |
|
|
|
$this->getApp(); |
|
|
|
$config = ['refund_desc' => '退款']; |
|
|
|
$result = $this->app->refund->byTransactionId( |
|
|
|
$paymentLog->wx_refund_id, |
|
|
|
$refundLog->wx_refund_id, |
|
|
|
round($paymentLog->payment_amount * 100), |
|
|
|
round($refundLog->refund_amount * 100), |
|
|
|
$config |
|
|
|
); |
|
|
|
Yii::info($result, 'refund_log'); |
|
|
|
|
|
|
|
if ($result['return_code'] == 'FAIL' || $result['return_msg'] != 'OK' || $result['result_code'] == 'FAIL') { |
|
|
|
throw new BadRequestHttpException($result['return_msg']); |
|
|
|
} |
|
|
|
if ($result['err_code_des']) { |
|
|
|
throw new BadRequestHttpException($result['err_code_des']); |
|
|
|
} |
|
|
|
$paymentLog->status = $refundLog->refund_amount < $paymentLog->payment_amount ? self::STATUS_REFUND_SUCCESS : self::STATUS_REFUND_PORTION; |
|
|
|
if (!$paymentLog->save()) { |
|
|
|
throw new Exception(Helper::errorMessageStr($paymentLog->errors)); |
|
|
|
} |
|
|
|
$refundLog->status = $refundLog->refund_amount < $paymentLog->payment_amount ? self::STATUS_REFUND_SUCCESS : self::STATUS_REFUND_PORTION; |
|
|
|
$refundLog->finished_at = time(); |
|
|
|
if (!$refundLog->save()) { |
|
|
|
throw new Exception(Helper::errorMessageStr($refundLog->errors)); |
|
|
|
} |
|
|
|
return $result; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* @param $data |
|
|
|