From 772fb073dd0c1c465c5f8d58a1275efd2b076b90 Mon Sep 17 00:00:00 2001 From: Terry <2358269014@qq.com> Date: Thu, 7 Dec 2017 14:51:23 +0800 Subject: [PATCH] =?UTF-8?q?paypal=E6=94=AF=E4=BB=98=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8paypal=E7=BB=91=E5=AE=9A=E7=9A=84=E4=BF=A1=E7=94=A8?= =?UTF-8?q?=E5=8D=A1=EF=BC=8C=E8=80=8C=E9=9D=9Epaypal=E4=BD=99=E9=A2=9D?= =?UTF-8?q?=E6=94=AF=E4=BB=98=EF=BC=8C=E8=BF=99=E7=A7=8D=E6=83=85=E5=86=B5?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86=EF=BC=8C=E4=BB=A5=E5=8F=8A=E6=9B=B4?= =?UTF-8?q?=E6=94=B9=E8=AE=A2=E5=8D=95=E7=8A=B6=E6=80=81=E5=90=AB=E4=B9=89?= =?UTF-8?q?=EF=BC=8Cprprocessing=E4=BB=A3=E8=A1=A8=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E6=94=B6=E6=AC=BE=E5=A4=84=E7=90=86=E4=B8=AD=EF=BC=8Cconfirmed?= =?UTF-8?q?=E4=BB=A3=E8=A1=A8=E8=AE=A2=E5=8D=95=E5=B7=B2=E6=94=B6=E6=AC=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/sales/orderinfo/manageredit.php | 2 +- .../controllers/paypal/ExpressController.php | 4 +- .../controllers/paypal/StandardController.php | 4 +- .../controllers/paypal/ExpressController.php | 4 +- .../controllers/paypal/StandardController.php | 4 +- .../controllers/paypal/ExpressController.php | 2 +- .../controllers/paypal/StandardController.php | 2 +- services/Order.php | 8 + services/Payment.php | 4 +- services/payment/Paypal.php | 207 +++++++++++++----- 10 files changed, 179 insertions(+), 62 deletions(-) diff --git a/app/appadmin/theme/base/default/sales/orderinfo/manageredit.php b/app/appadmin/theme/base/default/sales/orderinfo/manageredit.php index d6781a9b..9b81a3b8 100644 --- a/app/appadmin/theme/base/default/sales/orderinfo/manageredit.php +++ b/app/appadmin/theme/base/default/sales/orderinfo/manageredit.php @@ -285,7 +285,7 @@ use fecshop\app\appfront\helper\Format;
- 订单买家备注信息 + 订单买家留言信息
diff --git a/app/appfront/modules/Payment/controllers/paypal/ExpressController.php b/app/appfront/modules/Payment/controllers/paypal/ExpressController.php index e9e4ab5d..ff3761d6 100644 --- a/app/appfront/modules/Payment/controllers/paypal/ExpressController.php +++ b/app/appfront/modules/Payment/controllers/paypal/ExpressController.php @@ -18,7 +18,7 @@ use Yii; */ class ExpressController extends AppfrontController { - public $enableCsrfValidation = true; + public $enableCsrfValidation = false; public function actionStart() { @@ -56,7 +56,7 @@ class ExpressController extends AppfrontController var_dump($post); $post_log = ob_get_clean(); \Yii::info($post_log, 'fecshop_debug'); - //Yii::$service->payment->paypal->receiveIpn($post); + Yii::$service->payment->paypal->receiveIpn($post); } } diff --git a/app/appfront/modules/Payment/controllers/paypal/StandardController.php b/app/appfront/modules/Payment/controllers/paypal/StandardController.php index f517a5ef..1c20cde5 100644 --- a/app/appfront/modules/Payment/controllers/paypal/StandardController.php +++ b/app/appfront/modules/Payment/controllers/paypal/StandardController.php @@ -19,7 +19,7 @@ use Yii; class StandardController extends AppfrontController { - public $enableCsrfValidation = true; + public $enableCsrfValidation = false; public function actionStart() { @@ -45,7 +45,7 @@ class StandardController extends AppfrontController var_dump($post); $post_log = ob_get_clean(); \Yii::info($post_log, 'fecshop_debug'); - //Yii::$service->payment->paypal->receiveIpn($post); + Yii::$service->payment->paypal->receiveIpn($post); } } diff --git a/app/apphtml5/modules/Payment/controllers/paypal/ExpressController.php b/app/apphtml5/modules/Payment/controllers/paypal/ExpressController.php index 9e1e2485..2ad9ef7e 100644 --- a/app/apphtml5/modules/Payment/controllers/paypal/ExpressController.php +++ b/app/apphtml5/modules/Payment/controllers/paypal/ExpressController.php @@ -18,7 +18,7 @@ use Yii; */ class ExpressController extends AppfrontController { - public $enableCsrfValidation = true; + public $enableCsrfValidation = false; public function actionStart() { @@ -55,7 +55,7 @@ class ExpressController extends AppfrontController var_dump($post); $post_log = ob_get_clean(); \Yii::info($post_log, 'fecshop_debug'); - //Yii::$service->payment->paypal->receiveIpn($post); + Yii::$service->payment->paypal->receiveIpn($post); } } } diff --git a/app/apphtml5/modules/Payment/controllers/paypal/StandardController.php b/app/apphtml5/modules/Payment/controllers/paypal/StandardController.php index b47c6c58..eb04f6f1 100644 --- a/app/apphtml5/modules/Payment/controllers/paypal/StandardController.php +++ b/app/apphtml5/modules/Payment/controllers/paypal/StandardController.php @@ -18,7 +18,7 @@ use Yii; */ class StandardController extends AppfrontController { - public $enableCsrfValidation = true; + public $enableCsrfValidation = false; /** * 1.start部分,跳转到paypal前的部分 @@ -49,7 +49,7 @@ class StandardController extends AppfrontController var_dump($post); $post_log = ob_get_clean(); \Yii::info($post_log, 'fecshop_debug'); - //Yii::$service->payment->paypal->receiveIpn($post); + Yii::$service->payment->paypal->receiveIpn($post); } } /** diff --git a/app/appserver/modules/Payment/controllers/paypal/ExpressController.php b/app/appserver/modules/Payment/controllers/paypal/ExpressController.php index 1e51f61d..e298f688 100644 --- a/app/appserver/modules/Payment/controllers/paypal/ExpressController.php +++ b/app/appserver/modules/Payment/controllers/paypal/ExpressController.php @@ -61,7 +61,7 @@ class ExpressController extends AppserverController var_dump($post); $post_log = ob_get_clean(); \Yii::info($post_log, 'fecshop_debug'); - //Yii::$service->payment->paypal->receiveIpn($post); + Yii::$service->payment->paypal->receiveIpn($post); } } } diff --git a/app/appserver/modules/Payment/controllers/paypal/StandardController.php b/app/appserver/modules/Payment/controllers/paypal/StandardController.php index 5849c113..3743c989 100644 --- a/app/appserver/modules/Payment/controllers/paypal/StandardController.php +++ b/app/appserver/modules/Payment/controllers/paypal/StandardController.php @@ -58,7 +58,7 @@ class StandardController extends AppserverController var_dump($post); $post_log = ob_get_clean(); \Yii::info($post_log, 'fecshop_debug'); - //Yii::$service->payment->paypal->receiveIpn($post); + Yii::$service->payment->paypal->receiveIpn($post); } } /** diff --git a/services/Order.php b/services/Order.php index 3d7051bb..fbd6eb3b 100644 --- a/services/Order.php +++ b/services/Order.php @@ -21,11 +21,19 @@ class Order extends Service { public $requiredAddressAttr; // 必填的订单字段。 // 下面是订单支付状态 + // 等待支付状态 public $payment_status_pending = 'pending'; + // 支付处理中,因为信用卡有预售,因此需要等IPN消息来确认是否支付成功 public $payment_status_processing = 'processing'; + // 支付状态已确认,代表已经收到钱了 + public $payment_status_confirmed = 'confirmed'; + // 订单已取消 public $payment_status_canceled = 'canceled'; + // 订单已完成,暂时没有用这个 public $payment_status_complete = 'complete'; + // 订单被挂起 public $payment_status_holded = 'holded'; + // 欺诈 public $payment_status_suspected_fraud = 'suspected_fraud'; // 订单号格式。 public $increment_id = 1000000000; diff --git a/services/Payment.php b/services/Payment.php index f35a4763..fe4335bc 100644 --- a/services/Payment.php +++ b/services/Payment.php @@ -149,11 +149,12 @@ class Payment extends Service } } - /** + /** 废弃 * @property $payment_method | String 支付方式。 * @return string 得到跳转到第三方支付的url。 * #从配置信息中获取 */ + /* public function getStandardPaymentUrl($payment_method = '') { if (!$payment_method) { @@ -168,6 +169,7 @@ class Payment extends Service } } } + */ /** * @property $payment_method | String 支付方式。 diff --git a/services/payment/Paypal.php b/services/payment/Paypal.php index c6521e44..eb542c6b 100644 --- a/services/payment/Paypal.php +++ b/services/payment/Paypal.php @@ -20,7 +20,10 @@ use Yii; */ class Paypal extends Service { - // paypal支付状态 + /** + * paypal支付状态 详细参看:https://developer.paypal.com/docs/classic/api/merchant/DoExpressCheckoutPayment_API_Operation_NVP/ + * 打开url后,浏览器查找:PAYMENTINFO_n_PAYMENTSTATUS , 即可找到下面各个状态对应的含义 + */ public $payment_status_none = 'none'; public $payment_status_completed = 'completed'; public $payment_status_denied = 'denied'; @@ -52,12 +55,18 @@ class Paypal extends Service protected $expressPayerID; protected $expressToken; + // 允许更改的订单状态,不存在这里面的订单状态不允许修改 + protected $_allowChangOrderStatus; protected $_ipnMessageModelName = '\fecshop\models\mysqldb\IpnMessage'; protected $_ipnMessageModel; public function __construct(){ list($this->_ipnMessageModelName,$this->_ipnMessageModel) = \Yii::mapGet($this->_ipnMessageModelName); + $this->_allowChangOrderStatus = [ + Yii::$service->order->payment_status_pending, + Yii::$service->order->payment_status_processing, + ]; } /** * @property $domain | string @@ -77,19 +86,22 @@ class Paypal extends Service */ public function receiveIpn($post) { + \Yii::info('receiveIpn', 'fecshop_debug'); if ($this->verifySecurity($post)) { + \Yii::info('verifySecurity', 'fecshop_debug'); // 验证数据是否已经发送 - if ($this->isNotDuplicate()) { + //if ($this->isNotDuplicate()) { // 验证数据是否被篡改。 if ($this->isNotDistort()) { - $this->updateStandardOrderPayment(); + \Yii::info('updateOrderStatusByIpn', 'fecshop_debug'); + $this->updateOrderStatusByIpn(); } else { // 如果数据和订单数据不一致,而且,支付状态为成功,则此订单 // 标记为可疑的。 $suspected_fraud = Yii::$service->order->payment_status_suspected_fraud; - $this->updateStandardOrderPayment($suspected_fraud); + $this->updateOrderStatusByIpn($suspected_fraud); } - } + // } } } @@ -102,9 +114,11 @@ class Paypal extends Service protected function verifySecurity($post) { $this->_postData = $post; - Yii::$service->payment->setPaymentMethod('paypal_standard'); + //Yii::$service->payment->setPaymentMethod('paypal_express'); $verifyUrl = $this->getVerifyUrl(); + \Yii::info('verifyUrl:'.$verifyUrl, 'fecshop_debug'); $verifyReturn = $this->curlGet($verifyUrl); + \Yii::info('verifyReturn:'.$verifyReturn, 'fecshop_debug'); if ($verifyReturn == 'VERIFIED') { return true; } @@ -124,7 +138,7 @@ class Paypal extends Service } $urlParamStr .= '&cmd=_notify-validate'; $urlParamStr = substr($urlParamStr, 1); - $verifyUrl = Yii::$service->payment->getStandardPaymentUrl(); + $verifyUrl = Yii::$service->payment->getStandardApiUrl('paypal_standard'); $verifyUrl = $verifyUrl.'?'.$urlParamStr; return $verifyUrl; @@ -175,6 +189,7 @@ class Paypal extends Service * paypal 可能发送多次IPN消息 * 判断是否重复,如果不重复,把当前的插入。 */ + /* protected function isNotDuplicate() { $ipn = $this->_ipnMessageModel->find() @@ -196,6 +211,7 @@ class Paypal extends Service return true; } } + */ /** * 验证订单数据是否被篡改。 @@ -229,10 +245,10 @@ class Paypal extends Service } /** - * @property $orderstatus | String 退款状态 - * 更新订单状态。这是express 支付方式使用的。 + * @property $orderstatus | String 订单状态 + * 根据接收的ipn消息,更改订单状态。 */ - protected function updateStandardOrderPayment($orderstatus = '') + protected function updateOrderStatusByIpn($orderstatus = '') { $order_cancel_status = Yii::$service->order->payment_status_canceled; // 如果订单状态被取消,那么不能进行支付。 @@ -280,32 +296,73 @@ class Paypal extends Service // 在service中不要出现事务代码,如果添加事务,请在调用层使用。 //$innerTransaction = Yii::$app->db->beginTransaction(); //try { + // 可以更改的订单状态 + if ($orderstatus) { + $this->_order::updateAll( + [ + 'order_status' => $orderstatus, + 'updated_at' => time(), + ], + [ + 'and', + ['order_id' => $this->_order['order_id']], + ['in','order_status',$this->_allowChangOrderStatus] + ] + ); // 指定了订单状态 - $this->_order->order_status = $orderstatus; - $this->_order->save(); - $payment_status = strtolower($this->_postData['payment_status']); - //Yii::$app->mylog->log('save_'.$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; + // paypal支付完成,将订单状态改成:收款已确认。 + // 只有存在于 $this->_allowChangOrderStatus 数组的状态,才允许更改,按照目前的设置,取消了的订单是不允许更改的 + $orderstatus = Yii::$service->order->payment_status_confirmed; + $updateColumn = $this->_order::updateAll( + [ + 'order_status' => $orderstatus, + 'updated_at' => time(), + ], + [ + 'and', + ['order_id' => $this->_order['order_id']], + ['in','order_status',$this->_allowChangOrderStatus] + ] + ); + //$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(); + // 因为IPN消息可能不止发送一次,但是这里只允许一次, + // 如果重复发送,$updateColumn 的更新返回值将为0 + if (!empty($updateColumn)) { + $orderInfo = Yii::$service->order->getOrderInfoByIncrementId($this->_order['increment_id']); + // 发送新订单邮件 + Yii::$service->email->order->sendCreateEmail($orderInfo); + } + } elseif ($payment_status == $this->payment_status_pending) { + // pending 代表信用卡预付方式,需要等待paypal从信用卡中把钱扣除,因此订单状态是processing + $orderstatus = Yii::$service->order->payment_status_processing; + $updateColumn = $this->_order::updateAll( + [ + 'order_status' => $orderstatus, + 'updated_at' => time(), + ], + [ + 'and', + ['order_id' => $this->_order['order_id']], + ['order_status' => Yii::$service->order->payment_status_pending] + ] + ); + + } elseif ($payment_status == $this->payment_status_failed) { + // 暂不处理 } elseif ($payment_status == $this->payment_status_refunded) { - # 因为涉及到扣库存,因此,先不更改订单状态。 - //$this->_order->order_status = Yii::$service->order->payment_status_canceled; - //$this->_order->save(); + // 暂不处理 } else { - + // 暂不处理 } } //$innerTransaction->commit(); @@ -680,11 +737,6 @@ class Paypal extends Service 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; // 如果订单状态被取消,那么不能进行支付。 @@ -712,28 +764,83 @@ class Paypal extends Service $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']."
"; + //$order['updated_at'] = time(); + if ( + strtolower($PAYMENTINFO_0_PAYMENTSTATUS) == $this->payment_status_completed + || + strtolower($PAYMENTINFO_0_PAYMENTSTATUS) == $this->payment_status_processed + ) { + $order_status = Yii::$service->order->payment_status_confirmed; 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); - + + $updateColumn = $order::updateAll( + [ + 'order_status' => $order_status, + 'updated_at' => time(), + ], + [ + 'and', + ['order_id' => $order['order_id']], + ['in','order_status',$this->_allowChangOrderStatus] + ] + ); + // 因为IPN消息可能不止发送一次,但是这里只允许一次, + // 如果重复发送,$updateColumn 的更新返回值将为0 + if (!empty($updateColumn)) { + $orderInfo = Yii::$service->order->getOrderInfoByIncrementId($order['increment_id']); + // 发送新订单邮件 + 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_status = Yii::$service->order->payment_status_suspected_fraud; + $updateColumn = $order::updateAll( + [ + 'order_status' => $order_status, + 'updated_at' => time(), + ], + [ + 'and', + ['order_id' => $order['order_id']], + ['in','order_status',$this->_allowChangOrderStatus] + ] + ); + } + + } else if (strtolower($PAYMENTINFO_0_PAYMENTSTATUS) == $this->payment_status_pending) { + // 这种情况代表paypal 信用卡预售,需要等待一段时间才知道是否收到钱 + $order_status = Yii::$service->order->payment_status_processing; + if ($currency == $order['order_currency_code'] && $PAYMENTINFO_0_AMT == $order['grand_total']) { + $updateColumn = $order::updateAll( + [ + 'order_status' => $order_status, + 'updated_at' => time(), + ], + [ + 'and', + ['order_id' => $order['order_id']], + ['order_status' => Yii::$service->order->payment_status_pending] + ] + ); + // 这种情况不发送订单。 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(); + $order_status = Yii::$service->order->payment_status_suspected_fraud; + $updateColumn = $order::updateAll( + [ + 'order_status' => $order_status, + 'updated_at' => time(), + ], + [ + 'and', + ['order_id' => $order['order_id']], + ['in','order_status',$this->_allowChangOrderStatus] + ] + ); } } else { Yii::$service->helper->errors->add('paypal express payment is not complete , current payment status is '.$PAYMENTINFO_0_PAYMENTSTATUS); -- GitLab