* @since 1.0 */ class Paypal extends Service { // paypal支付状态 public $payment_status_none = 'none'; public $payment_status_completed = 'completed'; public $payment_status_denied = 'denied'; public $payment_status_expired = 'expired'; public $payment_status_failed = 'failed'; public $payment_status_in_progress = 'in_progress'; public $payment_status_pending = 'pending'; public $payment_status_refunded = 'refunded'; public $payment_status_refunded_part= 'partially_refunded'; public $payment_status_reversed = 'reversed'; public $payment_status_unreversed = 'canceled_reversal'; public $payment_status_processed = 'processed'; public $payment_status_voided = 'voided'; // 是否使用证书的方式(https) public $use_local_certs = false; // 在payment中 express paypal 的配置值 public $express_payment_method; public $standard_payment_method; public $version = '109.0'; public $crt_file; protected $_postData; protected $_order; const EXPRESS_TOKEN = 'paypal_express_token'; const EXPRESS_PAYER_ID = 'paypal_express_payer_id'; protected $expressPayerID; protected $expressToken; protected $_ipnMessageModelName = '\fecshop\models\mysqldb\IpnMessage'; protected $_ipnMessageModel; public function __construct(){ list($this->_ipnMessageModelName,$this->_ipnMessageModel) = \Yii::mapGet($this->_ipnMessageModelName); } /** * @property $domain | string * @return 得到证书crt文件的绝对路径 */ public function getCrtFile($domain) { if (isset($this->crt_file[$domain]) && !empty($this->crt_file[$domain])) { return Yii::getAlias($this->crt_file[$domain]); } } /** * 在paypal 标准支付中,paypal会向网站发送IPN消息,告知fecshop订单支付状态, * 进而fecshop更改订单状态。 * fecshop一方面验证消息是否由paypal发出,另一方面要验证订单是否和后台的一致。 */ public function receiveIpn($post) { if ($this->verifySecurity($post)) { // 验证数据是否已经发送 if ($this->isNotDuplicate()) { // 验证数据是否被篡改。 if ($this->isNotDistort()) { $this->updateStandardOrderPayment(); } else { // 如果数据和订单数据不一致,而且,支付状态为成功,则此订单 // 标记为可疑的。 $suspected_fraud = Yii::$service->order->payment_status_suspected_fraud; $this->updateStandardOrderPayment($suspected_fraud); } } } } /** * 该函数是为了验证IPN是否是由paypal发出, * 当paypal发送IPN消息给fecshop,fecshop不知道是否是伪造的支付消息, * 因此,fecshop将接收到的参数传递给paypal,询问paypal是否是paypal * 发送的IPN消息,如果是,则返回VERIFIED。 */ protected function verifySecurity($post) { $this->_postData = $post; Yii::$service->payment->setPaymentMethod('paypal_standard'); $verifyUrl = $this->getVerifyUrl(); $verifyReturn = $this->curlGet($verifyUrl); if ($verifyReturn == 'VERIFIED') { return true; } } /** * paypal发送的IPN,需要进行验证是否IPN是由paypal发出 * 因此需要请求paypal确认,此函数返回请求paypal的url。 */ protected function getVerifyUrl() { $urlParamStr = ''; if ($this->_postData) { foreach ($this->_postData as $k => $v) { $urlParamStr .= '&'.$k.'='.urlencode($v); } } $urlParamStr .= '&cmd=_notify-validate'; $urlParamStr = substr($urlParamStr, 1); $verifyUrl = Yii::$service->payment->getStandardPaymentUrl(); $verifyUrl = $verifyUrl.'?'.$urlParamStr; return $verifyUrl; } /** * @property $url | string, 请求的url * @property $i | 请求的次数,因为curl可能存在失败的可能,当 * 失败后,就会通过递归的方式进行多次请求,这里设置的最大请求5次。 * @return 返回请求url的return信息。 */ protected function curlGet($url, $i = 0) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_VERBOSE, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_SSLVERSION, 6); if ($this->use_local_certs) { $crtFile = $this->getCrtFile('www.paypal.com'); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_CAINFO, $crtFile); } else { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); } curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Connection: Close']); $httpResponse = curl_exec($ch); if (!$httpResponse) { $i++; if ($i <= 5) { return $this->curlGet($url, $i); } else { return $httpResponse; } } return $httpResponse; } /** * paypal 可能发送多次IPN消息 * 判断是否重复,如果不重复,把当前的插入。 */ protected function isNotDuplicate() { $ipn = $this->_ipnMessageModel->find() ->asArray() ->where([ 'txn_id'=>$this->_postData['txn_id'], 'payment_status'=>$this->_postData['payment_status'], ]) ->one(); if (is_array($ipn) && !empty($ipn)) { return false; } else { $IpnMessage = new $this->_ipnMessageModelName(); $IpnMessage->txn_id = $this->_postData['txn_id']; $IpnMessage->payment_status = $this->_postData['payment_status']; $IpnMessage->updated_at = time(); $IpnMessage->save(); return true; } } /** * 验证订单数据是否被篡改。 * 通过订单号找到订单,查看是否存在 * 验证邮件地址,订单金额是否准确。 */ protected function isNotDistort() { //Yii::$app->mylog->log("begin isNotDistort.."); $increment_id = $this->_postData['invoice']; $mc_gross = $this->_postData['mc_gross']; $mc_currency = $this->_postData['mc_currency']; if ($increment_id && $mc_gross && $mc_currency) { $this->_order = Yii::$service->order->getByIncrementId($increment_id); if ($this->_order) { $order_currency_code = $this->_order['order_currency_code']; if ($order_currency_code == $mc_currency) { // 核对订单总额 $currentCurrencyGrandTotal = $this->_order['grand_total']; if ((float) $currentCurrencyGrandTotal == (float) $mc_gross) { return true; } else { } } else { } } } return false; } /** * @property $orderstatus | String 退款状态 * 更新订单状态。这是express 支付方式使用的。 */ protected function updateStandardOrderPayment($orderstatus = '') { $order_cancel_status = Yii::$service->order->payment_status_canceled; // 如果订单状态被取消,那么不能进行支付。 if ($this->_order->order_status == $order_cancel_status) { Yii::$service->helper->error->add('The order status has been canceled and you can not pay for item ,you can create a new order to pay'); return; } if ($this->_postData['txn_type']) { $this->_order->txn_type = $this->_postData['txn_type']; } if ($this->_postData['txn_id']) { $this->_order->txn_id = $this->_postData['txn_id']; } if ($this->_postData['payer_id']) { $this->_order->payer_id = $this->_postData['payer_id']; } if ($this->_postData['ipn_track_id']) { $this->_order->ipn_track_id = $this->_postData['ipn_track_id']; } if ($this->_postData['receiver_id']) { $this->_order->receiver_id = $this->_postData['receiver_id']; } if ($this->_postData['verify_sign']) { $this->_order->verify_sign = $this->_postData['verify_sign']; } if ($this->_postData['charset']) { $this->_order->charset = $this->_postData['charset']; } if ($this->_postData['mc_fee']) { $this->_order->payment_fee = $this->_postData['mc_fee']; $currency = $this->_postData['mc_currency']; $this->_order->base_payment_fee = Yii::$service->page->currency->getBaseCurrencyPrice($this->_postData['mc_fee'], $currency); } if ($this->_postData['payment_type']) { $this->_order->payment_type = $this->_postData['payment_type']; } if ($this->_postData['payment_date']) { $this->_order->paypal_order_datetime = date('Y-m-d H:i:s', $this->_postData['payment_date']); } if ($this->_postData['protection_eligibility']) { $this->_order->protection_eligibility = $this->_postData['protection_eligibility']; } $this->_order->updated_at = time(); // 在service中不要出现事务代码,如果添加事务,请在调用层使用。 //$innerTransaction = Yii::$app->db->beginTransaction(); //try { if ($orderstatus) { // 指定了订单状态 $this->_order->order_status = $orderstatus; $this->_order->save(); $payment_status = strtolower($this->_postData['payment_status']); //Yii::$app->mylog->log('save_'.$orderstatus); } else { $payment_status = strtolower($this->_postData['payment_status']); if ($payment_status == $this->payment_status_completed) { $this->_order->order_status = Yii::$service->order->payment_status_processing; // 更新订单信息 $this->_order->save(); // 得到当前的订单信息 $orderInfo = Yii::$service->order->getOrderInfoByIncrementId($this->_order['increment_id']); // 发送新订单邮件 Yii::$service->email->order->sendCreateEmail($orderInfo); } elseif ($payment_status == $this->payment_status_failed) { # 因为涉及到扣库存,因此,先不更改订单状态。 //$this->_order->order_status = Yii::$service->order->payment_status_canceled; //$this->_order->save(); } elseif ($payment_status == $this->payment_status_refunded) { # 因为涉及到扣库存,因此,先不更改订单状态。 //$this->_order->order_status = Yii::$service->order->payment_status_canceled; //$this->_order->save(); } else { } } //$innerTransaction->commit(); return true; //} catch (Exception $e) { // $innerTransaction->rollBack(); //} //return false; } // express 部分 /** * @property $token | String , 通过 下面的 PPHttpPost5 方法返回的paypal express的token * @return String,通过token得到跳转的 paypal url, * 得到上面的url后,进行跳转到paypal,然后确认,然后返回到fecshop,paypal会传递货运地址等信息 * 到fecshop,这样用户不需要手动填写货运地址等信息。因此,这种方式为快捷支付。 */ public function getSetExpressCheckoutUrl($token) { if ($token) { $ApiUrl = Yii::$service->payment->getExpressApiUrl($this->express_payment_method); return $ApiUrl.'?cmd=_express-checkout&token='.urlencode($token); } } /** * @property $token | String , 通过 下面的 PPHttpPost5 方法返回的paypal express的token * @return String,通过token得到跳转的 paypal url, * 得到上面的url后,进行跳转到paypal,然后确认,然后返回到fecshop,paypal会传递货运地址等信息 * 到fecshop,这样用户不需要手动填写货运地址等信息。因此,这种方式为快捷支付。 */ public function getSetStandardCheckoutUrl($token) { if ($token) { $ApiUrl = Yii::$service->payment->getStandardApiUrl($this->standard_payment_method); return $ApiUrl.'?useraction=commit&cmd=_express-checkout&token='.urlencode($token); } } /** * @property $methodName_ | String,请求的方法,譬如: $methodName_ = "SetExpressCheckout"; * @property $nvpStr_ | String ,请求传递的购物车中的产品和总额部分的数据,组合成字符串的格式。 * @property $i | Int , 限制递归次数的变量,当api获取失败的时候,可以通过递归的方式多次尝试,直至超过最大失败次数,才会返回失败 * 此方法为获取token。返回的数据为数组,里面含有 ACK TOKEN 等值。 * 也就是和paypal进行初次的api账号密码验证,成功后返回token等信息。 */ public function PPHttpPost5($methodName_, $nvpStr_, $i = 1) { $API_NvpUrl = Yii::$service->payment->getExpressNvpUrl($this->express_payment_method); $API_Signature = Yii::$service->payment->getExpressSignature($this->express_payment_method); $API_UserName = Yii::$service->payment->getExpressAccount($this->express_payment_method); $API_Password = Yii::$service->payment->getExpressPassword($this->express_payment_method); $ipn_url = Yii::$service->payment->getExpressIpnUrl($this->express_payment_method); // Set the API operation, version, and API signature in the request. $nvpreq = "METHOD=$methodName_&PWD=$API_Password&USER=$API_UserName&SIGNATURE=$API_Signature$nvpStr_"; $nvpreq .= "&PAYMENTREQUEST_0_NOTIFYURL=".urlencode($ipn_url); //echo $nvpreq; //\Yii::info($nvpreq, 'fecshop_debug'); //exit; $ch = curl_init(); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_URL, $API_NvpUrl); curl_setopt($ch, CURLOPT_VERBOSE, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_SSLVERSION, 6); if ($this->use_local_certs) { $crtFile = $this->getCrtFile('api-3t.paypal.com'); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_CAINFO, $crtFile); } else { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); } // Set the request as a POST FIELD for curl. curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq); curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Connection: Close']); // Get response from the server. $httpResponse = curl_exec($ch); //echo "

%%%%%".$httpResponse."%%%%%

"; if (!$httpResponse) { $i++; if ($i > 5) { //获取三次失败后,则推出。 exit("$methodName_ failed: ".curl_error($ch).'('.curl_errno($ch).')'); } else { $httpResponse = $this->PPHttpPost5($methodName_, $nvpStr_, $i); } } else { //第一次获取数据失败,则再次获取。并返回、 if ($i > 0) { //return $httpResponse; } } //paypal返回的是一系列的字符串,譬如:L_TIMESTAMP0=2014-11-08T01:51:13Z&L_TIMESTAMP1=2014-11-08T01:40:41Z&L_TIMESTAMP2=2014-11-08T01:40:40Z& //下面要做的是先把字符串通过&字符打碎成数组 // //echo "***************
"; //echo urldecode($httpResponse); //echo "
***************
"; $httpResponseAr = explode('&', urldecode($httpResponse)); $httpParsedResponseAr = []; foreach ($httpResponseAr as $i => $value) { $tmpAr = explode('=', $value); if (sizeof($tmpAr) > 1) { $httpParsedResponseAr[$tmpAr[0]] = $tmpAr[1]; } } if ((0 == sizeof($httpParsedResponseAr)) || !array_key_exists('ACK', $httpParsedResponseAr)) { exit("Invalid HTTP Response for POST request($nvpreq) to $API_NvpUrl."); } return $httpParsedResponseAr; } /** * @property $nvp_array | Array, 各个配置参数 * 将数组里面的key和value,组合成url的字符串,生成nvp url */ public function getRequestUrlStrByArray($nvp_array) { $str = ''; if (is_array($nvp_array) && !empty($nvp_array)) { foreach ($nvp_array as $k=>$v) { $str .= '&'.urlencode($k).'='.urlencode($v); } } //echo $str;exit; return $str; } /** * 【paypal快捷支付部分】api发送付款 * 通过该函数,将参数组合成字符串,通过api发送给paypal进行付款。 */ public function getExpressCheckoutPaymentNvpStr($token) { $nvp_array = []; $nvp_array['PAYERID'] = $this->getExpressPayerID(); $nvp_array['TOKEN'] = $this->getExpressToken(); $nvp_array['PAYMENTREQUEST_0_PAYMENTACTION'] = 'Sale'; $nvp_array['VERSION'] = $this->version; // https://developer.paypal.com/docs/classic/api/merchant/SetExpressCheckout_API_Operation_NVP/ // 检查地址 $nvp_array['ADDROVERRIDE'] = 0; //ADDROVERRIDE // 得到购物车的信息,通过购物车信息填写。 $orderInfo = Yii::$service->order->getInfoByPaymentToken($token); //$cartInfo = Yii::$service->cart->getCartInfo(); $currency = Yii::$service->page->currency->getCurrentCurrency(); $grand_total = Yii::$service->helper->format->number_format($orderInfo['grand_total']); $subtotal = Yii::$service->helper->format->number_format($orderInfo['subtotal']); $shipping_total = Yii::$service->helper->format->number_format($orderInfo['shipping_total']); $discount_amount= Yii::$service->helper->format->number_format($orderInfo['subtotal_with_discount']); $subtotal = $subtotal - $discount_amount; $nvp_array['PAYMENTREQUEST_0_SHIPTOSTREET'] = $orderInfo['customer_address_street1'].' '.$orderInfo['customer_address_street2']; $nvp_array['PAYMENTREQUEST_0_SHIPTOCITY'] = $orderInfo['customer_address_city']; $nvp_array['PAYMENTREQUEST_0_SHIPTOSTATE'] = $orderInfo['customer_address_state_name']; $nvp_array['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE'] = $orderInfo['customer_address_country']; $nvp_array['PAYMENTREQUEST_0_SHIPTOZIP'] = $orderInfo['customer_address_zip']; $nvp_array['PAYMENTREQUEST_0_SHIPTONAME'] = $orderInfo['customer_firstname'].' '.$orderInfo['customer_lastname']; $nvp_array['PAYMENTREQUEST_0_INVNUM'] = $orderInfo['increment_id']; $nvp_array['PAYMENTREQUEST_0_CURRENCYCODE'] = $currency; $nvp_array['PAYMENTREQUEST_0_AMT'] = $grand_total; $nvp_array['PAYMENTREQUEST_0_ITEMAMT'] = $subtotal; $nvp_array['PAYMENTREQUEST_0_SHIPPINGAMT'] = $shipping_total; $i = 0; foreach ($orderInfo['products'] as $item) { $nvp_array['L_PAYMENTREQUEST_0_QTY'.$i] = $item['qty']; $nvp_array['L_PAYMENTREQUEST_0_NUMBER'.$i] = $item['sku']; $nvp_array['L_PAYMENTREQUEST_0_AMT'.$i] = Yii::$service->helper->format->number_format($item['price']); $nvp_array['L_PAYMENTREQUEST_0_NAME'.$i] = $item['name']; $nvp_array['L_PAYMENTREQUEST_0_CURRENCYCODE'.$i] = $currency; $i++; } $nvp_array['L_PAYMENTREQUEST_0_NAME'.$i] = 'Discount'; $nvp_array['L_PAYMENTREQUEST_0_AMT'.$i] = '-'.$discount_amount; //var_dump($nvp_array); $nvpStr = $this->getRequestUrlStrByArray($nvp_array); //var_dump($nvpStr); return $nvpStr; } /** * 【paypal快捷支付部分】将参数组合成字符串。 * 通过api token,从paypal获取用户在paypal保存的货运地址。 */ public function getExpressAddressNvpStr() { $nvp_array = []; $nvp_array['VERSION'] = Yii::$service->payment->paypal->version; $nvp_array['token'] = Yii::$service->payment->paypal->getExpressToken(); return $this->getRequestUrlStrByArray($nvp_array); } /** * @property $landingPage | String ,访问api的类型,譬如login * 【paypal快捷支付部分】通过购物车中的数据,组合成访问paypal express api的url * 这里返回的的字符串,是快捷支付部分获取token和payerId的参数。 * 通过这些参数最终得到paypal express的token和payerId */ public function getExpressTokenNvpStr($landingPage = 'Login') { $nvp_array = []; $nvp_array['LANDINGPAGE'] = $landingPage; $nvp_array['RETURNURL'] = Yii::$service->payment->getExpressReturnUrl($this->express_payment_method); $nvp_array['CANCELURL'] = Yii::$service->payment->getExpressCancelUrl($this->express_payment_method); $nvp_array['PAYMENTREQUEST_0_PAYMENTACTION'] = 'Sale'; $nvp_array['VERSION'] = $this->version; // 得到购物车的信息,通过购物车信息填写。 $cartInfo = Yii::$service->cart->getCartInfo(); $currency = Yii::$service->page->currency->getCurrentCurrency(); $grand_total = $cartInfo['grand_total']; $subtotal = $cartInfo['product_total']; $shipping_total = $cartInfo['shipping_cost']; $discount_amount = $cartInfo['coupon_cost']; $subtotal = $subtotal - $discount_amount; $nvp_array['PAYMENTREQUEST_0_CURRENCYCODE'] = $currency; $nvp_array['PAYMENTREQUEST_0_AMT'] = $grand_total; $nvp_array['PAYMENTREQUEST_0_ITEMAMT'] = $subtotal; $nvp_array['PAYMENTREQUEST_0_SHIPPINGAMT'] = $shipping_total; $i = 0; foreach ($cartInfo['products'] as $item) { $nvp_array['L_PAYMENTREQUEST_0_QTY'.$i] = $item['qty']; $nvp_array['L_PAYMENTREQUEST_0_NUMBER'.$i] = $item['sku']; $nvp_array['L_PAYMENTREQUEST_0_AMT'.$i] = $item['product_price']; $nvp_array['L_PAYMENTREQUEST_0_NAME'.$i] = Yii::$service->store->getStoreAttrVal($item['name'], 'name'); $nvp_array['L_PAYMENTREQUEST_0_CURRENCYCODE'.$i] = $currency; $i++; } $nvp_array['L_PAYMENTREQUEST_0_NAME'.$i] = 'Discount'; $nvp_array['L_PAYMENTREQUEST_0_AMT'.$i] = '-'.$discount_amount; return $this->getRequestUrlStrByArray($nvp_array); } /** * @property $landingPage | String ,访问api的类型,譬如login * 【paypal快捷支付部分】通过购物车中的数据,组合成访问paypal express api的url * 这里返回的的字符串,是快捷支付部分获取token和payerId的参数。 * 通过这些参数最终得到paypal express的token和payerId */ public function getStandardTokenNvpStr($landingPage = 'Login') { $nvp_array = []; $nvp_array['LANDINGPAGE'] = $landingPage; $nvp_array['RETURNURL'] = Yii::$service->payment->getStandardReturnUrl('paypal_standard'); $nvp_array['CANCELURL'] = Yii::$service->payment->getStandardCancelUrl('paypal_standard'); $nvp_array['PAYMENTREQUEST_0_PAYMENTACTION'] = 'Sale'; $nvp_array['VERSION'] = $this->version; // 得到购物车的信息,通过购物车信息填写。 $orderInfo = Yii::$service->order->getCurrentOrderInfo(); //var_dump($orderInfo); $currency = $orderInfo['order_currency_code']; $grand_total = Yii::$service->helper->format->number_format($orderInfo['grand_total']); $subtotal = Yii::$service->helper->format->number_format($orderInfo['subtotal']); $shipping_total = Yii::$service->helper->format->number_format($orderInfo['shipping_total']); $discount_amount= $orderInfo['subtotal_with_discount'] ? $orderInfo['subtotal_with_discount'] : 0; $subtotal = $subtotal - $discount_amount; $nvp_array['PAYMENTREQUEST_0_CURRENCYCODE'] = $currency; $nvp_array['PAYMENTREQUEST_0_AMT'] = $grand_total; $nvp_array['PAYMENTREQUEST_0_ITEMAMT'] = $subtotal; $nvp_array['PAYMENTREQUEST_0_SHIPPINGAMT'] = $shipping_total; $i = 0; foreach ($orderInfo['products'] as $item) { $nvp_array['L_PAYMENTREQUEST_0_QTY'.$i] = $item['qty']; $nvp_array['L_PAYMENTREQUEST_0_NUMBER'.$i] = $item['sku']; $nvp_array['L_PAYMENTREQUEST_0_AMT'.$i] = Yii::$service->helper->format->number_format($item['price']); $nvp_array['L_PAYMENTREQUEST_0_NAME'.$i] = $item['name'];; $nvp_array['L_PAYMENTREQUEST_0_CURRENCYCODE'.$i] = $currency; $i++; } $nvp_array['L_PAYMENTREQUEST_0_NAME'.$i] = 'Discount'; $nvp_array['L_PAYMENTREQUEST_0_AMT'.$i] = '-'.$discount_amount; //var_dump($nvp_array); //exit; return $this->getRequestUrlStrByArray($nvp_array); } /** * 从get参数里得到express支付的token */ public function getExpressToken() { if(!$this->expressToken){ $token = Yii::$app->request->get('token'); $token = \Yii::$service->helper->htmlEncode($token); if ($token) { $this->expressToken = $token; } } return $this->expressToken; } /** * 从get参数里得到express支付的PayerID */ public function getExpressPayerID() { if(!$this->expressPayerID){ $PayerID = Yii::$app->request->get('PayerID'); $PayerID = \Yii::$service->helper->htmlEncode($PayerID); if ($PayerID) { $this->expressPayerID = $PayerID; } } return $this->expressPayerID; } /** * @property $doExpressCheckoutReturn | Array , 上面的 函数 doExpressCheckoutPayment 返回的数据 * 快捷支付付款状态提交后,更新订单的支付部分的信息。 */ public function updateExpressOrderPayment($DoExpressCheckoutReturn,$token) { if ($DoExpressCheckoutReturn) { //echo 'aaa'; //$increment_id = Yii::$service->order->getSessionIncrementId(); //echo "\n $increment_id \n\n"; //$order = Yii::$service->order->getByIncrementId($increment_id); echo '########'.$token.'#####'; $order = Yii::$service->order->getByPaymentToken($token); $order_cancel_status = Yii::$service->order->payment_status_canceled; // 如果订单状态被取消,那么不能进行支付。 if ($order['order_status'] == $order_cancel_status) { Yii::$service->helper->errors->add('The order status has been canceled and you can not pay for item ,you can create a new order to pay'); return false; } if ($order['increment_id']) { //echo 'bbb'; $order['txn_id'] = $DoExpressCheckoutReturn['PAYMENTINFO_0_TRANSACTIONID']; $order['txn_type'] = $DoExpressCheckoutReturn['PAYMENTINFO_0_TRANSACTIONTYPE']; $PAYMENTINFO_0_AMT = $DoExpressCheckoutReturn['PAYMENTINFO_0_AMT']; $order['payment_fee'] = $DoExpressCheckoutReturn['PAYMENTINFO_0_FEEAMT']; $currency = $DoExpressCheckoutReturn['PAYMENTINFO_0_CURRENCYCODE']; $order['base_payment_fee'] = Yii::$service->page->currency->getBaseCurrencyPrice($order['payment_fee'], $currency); $order['payer_id'] = $this->getExpressPayerID(); $order['correlation_id'] = $DoExpressCheckoutReturn['CORRELATIONID']; $order['protection_eligibility'] = $DoExpressCheckoutReturn['PAYMENTINFO_0_PROTECTIONELIGIBILITY']; $order['protection_eligibility_type'] = $DoExpressCheckoutReturn['PAYMENTINFO_0_PROTECTIONELIGIBILITYTYPE']; $order['secure_merchant_account_id'] = $DoExpressCheckoutReturn['PAYMENTINFO_0_SECUREMERCHANTACCOUNTID']; $order['build'] = $DoExpressCheckoutReturn['BUILD']; $order['payment_type'] = $DoExpressCheckoutReturn['PAYMENTINFO_0_PAYMENTTYPE']; $order['paypal_order_datetime'] = date('Y-m-d H:i:s', $DoExpressCheckoutReturn['PAYMENTINFO_0_ORDERTIME']); $PAYMENTINFO_0_PAYMENTSTATUS = $DoExpressCheckoutReturn['PAYMENTINFO_0_PAYMENTSTATUS']; echo $this->payment_status_completed.'##'.$PAYMENTINFO_0_PAYMENTSTATUS."
"; if (strtolower($PAYMENTINFO_0_PAYMENTSTATUS) == $this->payment_status_completed) { //echo 222; // 判断金额是否相符 echo $currency."
"; echo $order['order_currency_code']."
"; echo $PAYMENTINFO_0_AMT."
"; echo $order['grand_total']."
"; if ($currency == $order['order_currency_code'] && $PAYMENTINFO_0_AMT == $order['grand_total']) { //echo 222; $order->order_status = Yii::$service->order->payment_status_processing; $order->save(); // 支付成功,发送新订单邮件 $orderInfo = Yii::$service->order->getCurrentOrderInfo(); Yii::$service->email->order->sendCreateEmail($orderInfo); return true; } else { Yii::$service->helper->errors->add('The amount of payment is inconsistent with the amount of the order'); $order->order_status = Yii::$service->order->payment_status_suspected_fraud; $order->save(); } } else { Yii::$service->helper->errors->add('paypal express payment is not complete , current payment status is '.$PAYMENTINFO_0_PAYMENTSTATUS); } } else { Yii::$service->helper->errors->add('current order is not exist'); } } else { Yii::$service->helper->errors->add('ExpressCheckoutReturn is empty'); } return false; } }