|
|
<?php /** * Created by PhpStorm. * User: travis * Date: 2019/12/12 * Time: 6:20 */
namespace api\logic;
use backend\modules\shop\models\ars\PaymentLog; use backend\modules\shop\models\ars\WxPayConfig; use common\models\User; use Yii; use backend\modules\shop\models\ars\Config; use EasyWeChat\Factory; use backend\modules\shop\models\ars\Order; use yii\db\Exception; use yii\web\BadRequestHttpException; use yii\web\NotFoundHttpException; use yii\base\BaseObject;
class WxPaymentLogic extends BaseObject { /*支付类型*/ const PAY_TYPE_WEB = 1; const PAY_TYPE_MINI_PROGRAM = 2; /*发起支付方式*/ const TRADE_TYPE_JS_API = 'JSAPI';
public $appId; public $mchId; public $key; public $certPath; public $keyPath; public $notifyUrl = 'http://baidu.com'; public $tradeType; public $payType; public $app; public $order;
/** * @param $payType * @throws BadRequestHttpException * @throws Exception * 微信统一下单 */ public function wxPayment($payType) { $this->payType = $payType; $unifyParams = $this->applyPaymentData(); $this->unify($unifyParams); }
/** * @return array * @throws BadRequestHttpException * @throws Exception * 生成支付参数 */ private function applyPaymentData() { $orderId = Yii::$app->request->getBodyParam('order_id');/*int 商品id*/ $paymentAmount = Yii::$app->request->getBodyParam('payment_amount');/*int 商品id*/ $notifyUrl = Yii::$app->request->getBodyParam('notify_url');/*int 商品id*/ if (empty($orderId) || empty($paymentAmount) || empty($notifyUrl)) { throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS); }
$this->tradeType = self::TRADE_TYPE_JS_API; $this->savePaymentLog($orderId, $paymentAmount, $notifyUrl);
$params = [ 'body' => '订单支付', 'out_trade_no' => $orderId, 'total_fee' => round($paymentAmount * 100), 'openid' => Yii::$app->user->identity->wx_openid, ]; return $params; }
/** * @param string $orderId * @param float $paymentAmount * @param string $notifyUrl * @throws Exception * 保存支付信息 */ private function savePaymentLog($orderId, $paymentAmount, $notifyUrl) { $paymentLog = PaymentLog::findOne(['order_id' => $this->order->order_sn]); if (!$paymentLog) { $paymentLog = new PaymentLog(); } $paymentLog->order_id = $orderId; $paymentLog->payment_amount = $paymentAmount; $paymentLog->notify_url = $notifyUrl; $paymentLog->type = $this->payType; if (!$paymentLog->save()) { throw new Exception(Helper::errorMessageStr($paymentLog->errors)); } }
private function getPaymentApp() { $this->initObject(); $config = [ 'app_id' => $this->appId, 'mch_id' => $this->mchId, 'key' => $this->key, 'cert_path' => $this->certPath, 'key_path' => $this->keyPath, 'notify_url' => $this->notifyUrl, 'trade_type' => $this->tradeType, 'sandbox' => true, // 设置为 false 或注释则关闭沙箱模式
]; $this->app = Factory::payment($config); // 判断当前是否为沙箱模式:
$this->app->inSandbox(); }
/** * @var WxPayConfig $wxPayConfig */ private function initObject() { $path = Yii::getAlias('@backend');
// switch ($this->payType) {
// case self::PAY_TYPE_WEB:
// $this->appId = trim($config->wx_appId);
// $this->mchId = trim($config->wx_mchId);
// $this->key = trim($config->wx_key);
// $this->keyPath = trim($path . $config->wx_keyPath);
// break;
// case self::PAY_TYPE_MINI_PROGRAM:
// $this->appId = trim($config->mini_program_appId);
// $this->mchId = trim($config->mini_program_mchId);
// $this->key = trim($config->mini_program_key);
// break;
// }
$wxPayConfig = WxPayConfig::find()->one(); $this->mchId = $wxPayConfig->mch_id; $this->certPath = trim($path . $wxPayConfig->cert_path); $this->keyPath = trim($path . $wxPayConfig->key_path); }
/** * @param $unifyParams * @return mixed * @throws Exception * 统一下单 */ private function unify($unifyParams) { $this->getPaymentApp(); return $this->app->order->unify($unifyParams); }
/** * @return array|bool * @throws BadRequestHttpException * 支付回调 */ public function notify() { $result = [ 'appid' => 'wxdccdddaa336353e1', 'bank_type' => 'OTHERS', 'cash_fee' => '926', 'fee_type' => 'CNY', 'is_subscribe' => 'N', 'mch_id' => '1395812402', 'nonce_str' => '5df366a248edb', 'openid' => 'ovT0C0UB8xQbfYHVVS2VGWMjDMhI', 'out_trade_no' => '201912131823156640Q', 'result_code' => 'SUCCESS', 'return_code' => 'SUCCESS', 'sign' => 'EA6FFD717A206D203856EAFB554F666F', 'time_end' => '20191213182333', 'total_fee' => '926', 'trade_type' => 'JSAPI', 'transaction_id' => '4200000423201912134049863433', ]; $xmlString = $this->arrayToXml($result); $notifyData = json_decode(json_encode(simplexml_load_string($xmlString, 'SimpleXMLElement', LIBXML_NOCDATA)));
// $notifyData = json_decode(json_encode(simplexml_load_string(Yii::$app->request->getRawBody(), 'SimpleXMLElement', LIBXML_NOCDATA)));
// Yii::info($notifyData, "notify");
// if (!$this->checkSign($notifyData)) {
// throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS);
// }
$tra = Yii::$app->db->beginTransaction('SERIALIZABLE'); try { if ($notifyData->result_code != 'SUCCESS' || $notifyData->return_code != 'SUCCESS') { throw new Exception('result_code or return_code is false'); }
$user = User::findOne(['wx_openid' => $notifyData->openid, 'status' => User::STATUS_ACTIVE]) ?? User::findOne(['mini_openid' => $notifyData->openid, 'status' => User::STATUS_ACTIVE]);/*根据openid获取用户*/ if (empty($user)) { throw new Exception('用户不存在或已被禁用'); }
$paymentLog = PaymentLog::findOne(['order_id' => $notifyData->out_trade_no]); $paymentLog->mch_id = $this->mch_id; $paymentLog->wx_refund_id = $notifyData->transaction_id; //交易号
$paymentLog->status = 1; if (!$paymentLog->save()) { throw new Exception(Helper::errorMessageStr($paymentLog->errors)); }
if (!$tra->commit()) { throw new Exception('保存数据失败'); }
$this->forwardNotify($notifyData, true);
return ['return_code' => 'SUCCESS', 'return_msg' => 'OK'];//回传成功信息到微信服务器
} catch (Exception $e) { $tra->rollBack(); $this->forwardNotify($notifyData, false); Yii::info($e->getMessage(), 'notify'); return false; } }
private function forwardNotify($notifyData, $status) { return true; return false; }
/** * @param $data * @return bool * 支付成功回调验证签名和支付金额 */ public function checkSign($data) { $this->initObject(); $notifySign = $data['sign']; unset($data['sign']); $sign = $this->_sign($data); if ($notifySign == $sign) { return true; } else { return false; } }
/** * @param $arr * @return string * 微信签名方法 */ private function _sign($arr) { $arr = array_filter($arr); ksort($arr); $arr['key'] = $this->key; $queryString = http_build_query($arr); $queryString = urldecode($queryString); return strtoupper(md5($queryString)); }
/** * @param $arr * @param null $dom * @param null $node * @param string $root * @param bool $cdata * @return string * 数组转xml字符串 */ function arrayToXml($arr, $dom = null, $node = null, $root = 'xml', $cdata = false) { if (!$dom) { $dom = new \DOMDocument('1.0','utf-8'); } if (!$node) { $node = $dom->createElement($root); $dom->appendChild($node); } foreach ($arr as $key=>$value) { $child_node = $dom->createElement(is_string($key) ? $key : 'node'); $node->appendChild($child_node); if (!is_array($value)) { if (!$cdata) { $data = $dom->createTextNode($value); } else { $data = $dom->createCDATASection($value); } $child_node->appendChild($data); } else { $this->arrayToXml($value,$dom,$child_node,$root,$cdata); } } return $dom->saveXML(); }
}
|