Bri*_*VPS 11 php paypal magento
在尝试提交说明PayPal网关已拒绝请求的订单时,客户偶尔会遇到错误.由于提供了重复的发票ID,交易被拒绝. 在深入研究这一点之后,我相信我已经缩小了问题范围.在最近的一些案例中,客户曾试图在4个月前下订单,并从PayPal 收到内部错误.我从与PayPal的交谈中了解到,该客户的信用卡已被标记.当他们试图下第一个订单时,PayPal拒绝了它,但仍然认为我们的Magento商店提供的"使用"的发票ID.
快进到今天......同样的客户,新的订单.Magento STILL在sales_flat_quote表中列出了9月份的旧报价.当他们登录时,它加载了客户报价(仍然有效)并尝试将其用于此订单.这导致重复发票ID错误.
我在Mage_Sales_Model_Observer类中看到有一个cleanExpiredQuotes从cron作业调用的方法.但是,这仅影响"is_active"= 0的引号.由于此引用被认为是活动的,因此它永远不会被清除.
很明显,Magento代码和PayPal之间存在脱节.但就我所知,这就是我的意思.还有其他人经历过这个吗?如果有,有什么建议吗?
我已经进一步了解这一点.我已经添加代码到结账的IndexController捕获错误,如果它是一个重复的发票错误,它会取消reserved_order_id在帖中一个调用saveOrderAction一次.这会导致报价保留新的订单ID,然后提交给PayPal.我现在遇到的问题是,当它第二次尝试使用新的发票编号时,所有总数都是0.我尝试将totals_collected_flag设置为false,以便重新收集总数,但它们在第二次总是为0通过.更具体地说,Mage_Sales_Model_Quote_Address中的总数是0,这是Mage_Sales_Model_Order最终使用的.Mage_Sales_Model_Quote中的总数是正确的,但它们会被collectTotals()引用的方法覆盖.
显然,在第一次尝试之后,某些东西正在取消所有的价值,但我不知道是什么或在哪里.如果有人有任何想法,我很乐意听到他们!
本质上发生的事情是,magento 正在向 paypal 发送一个已经在系统中付款的 orderId(发票号码)。这会导致 PayPal 返回一个响应,表明该发票号码重复。因此,我在这里所做的就是尝试检测该消息响应,生成新的 orderId,然后重新提交给 paypal 进行重新处理。
这是启动向 magento 发送信息的整个链的操作。它位于“Mage_Paypal_Controller_Express_Abstract”。我修改了贝宝响应生成的“令牌”。该令牌将包含有关发生的错误的信息。
startAction(){
...
$token = $this->_checkout->start(Mage::getUrl('*/*/return'), Mage::getUrl('*/*/cancel'));
if ($token && $url = $this->_checkout->getRedirectUrl()) {
$this->_initToken($token);
...
}
}
Run Code Online (Sandbox Code Playgroud)
到:
startAction(){
...
$token = $this->_checkout->start(Mage::getUrl('*/*/return'), Mage::getUrl('*/*/cancel'));
//while this token is invalid
while (isset($token['error'])) {
//generate a new token
$token = $this->_checkout->start(Mage::getUrl('*/*/return'),Mage::getUrl('*/*/cancel'), TRUE);
}
if ($token['token'] && $url = $this->_checkout->getRedirectUrl()) {
$this->_initToken($token['token']);
...
}
}
Run Code Online (Sandbox Code Playgroud)
该令牌由“Mage_Paypal_Model_Express_Checkout”中的 start() 方法生成。start() 还处理对象操作的整个过程。在这里,我们将有条件地更改productId。
修改后的函数将如下所示:
public function start($returnUrl, $cancelUrl, $errorAgain = FALSE)
{
$this->_quote->collectTotals();
if (!$this->_quote->getGrandTotal() && !$this->_quote->hasNominalItems()) {
Mage::throwException(Mage::helper('paypal')->__('PayPal does not support processing orders with zero amount. To complete your purchase, proceed to the standard checkout process.'));
}
if ($errorAgain) {
Mage::log('why is this running?');
$this->_quote->setReservedOrderId($this->_quote->getReservedOrderId($this->_quote));
$this->_quote->reserveOrderId()->save();
}
//$this->_quote->setReservedOrderId($this->_quote->_getResource()->getReservedOrderId($this->_quote));
//$this->_quote->setReservedOrderId($this->_quote->getReservedOrderId($this->_quote));
$this->_quote->reserveOrderId()->save();
// prepare API
$this->_getApi();
$this->_api->setAmount($this->_quote->getBaseGrandTotal())
->setCurrencyCode($this->_quote->getBaseCurrencyCode())
->setInvNum($this->_quote->getReservedOrderId())
->setReturnUrl($returnUrl)
->setCancelUrl($cancelUrl)
->setSolutionType($this->_config->solutionType)
->setPaymentAction($this->_config->paymentAction)
;
if ($this->_giropayUrls) {
list($successUrl, $cancelUrl, $pendingUrl) = $this->_giropayUrls;
$this->_api->addData(array(
'giropay_cancel_url' => $cancelUrl,
'giropay_success_url' => $successUrl,
'giropay_bank_txn_pending_url' => $pendingUrl,
));
}
$this->_setBillingAgreementRequest();
if ($this->_config->requireBillingAddress == Mage_Paypal_Model_Config::REQUIRE_BILLING_ADDRESS_ALL) {
$this->_api->setRequireBillingAddress(1);
}
// supress or export shipping address
if ($this->_quote->getIsVirtual()) {
if ($this->_config->requireBillingAddress == Mage_Paypal_Model_Config::REQUIRE_BILLING_ADDRESS_VIRTUAL) {
$this->_api->setRequireBillingAddress(1);
}
$this->_api->setSuppressShipping(true);
} else {
$address = $this->_quote->getShippingAddress();
$isOverriden = 0;
if (true === $address->validate()) {
$isOverriden = 1;
$this->_api->setAddress($address);
}
$this->_quote->getPayment()->setAdditionalInformation(
self::PAYMENT_INFO_TRANSPORT_SHIPPING_OVERRIDEN, $isOverriden
);
$this->_quote->getPayment()->save();
}
// add line items
$paypalCart = Mage::getModel('paypal/cart', array($this->_quote));
$this->_api->setPaypalCart($paypalCart)
->setIsLineItemsEnabled($this->_config->lineItemsEnabled)
;
// add shipping options if needed and line items are available
if ($this->_config->lineItemsEnabled && $this->_config->transferShippingOptions && $paypalCart->getItems()) {
if (!$this->_quote->getIsVirtual() && !$this->_quote->hasNominalItems()) {
if ($options = $this->_prepareShippingOptions($address, true)) {
$this->_api->setShippingOptionsCallbackUrl(
Mage::getUrl('*/*/shippingOptionsCallback', array('quote_id' => $this->_quote->getId()))
)->setShippingOptions($options);
}
}
}
// add recurring payment profiles information
if ($profiles = $this->_quote->prepareRecurringPaymentProfiles()) {
foreach ($profiles as $profile) {
$profile->setMethodCode(Mage_Paypal_Model_Config::METHOD_WPP_EXPRESS);
if (!$profile->isValid()) {
Mage::throwException($profile->getValidationErrors(true, true));
}
}
$this->_api->addRecurringPaymentProfiles($profiles);
}
$this->_config->exportExpressCheckoutStyleSettings($this->_api);
// call API and redirect with token
$response = $this->_api->callSetExpressCheckout();
$token['token'] = $this->_api->getToken();
$this->_redirectUrl = $this->_config->getExpressCheckoutStartUrl($token['token']);
if ($response == 'duplicate') {
$token['error'] = 'duplicate';
return $token;
} elseif (isset($token['error'])) {
unset($token['error']);
}
$this->_quote->getPayment()->unsAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT);
$this->_quote->getPayment()->save();
return $token;
}
Run Code Online (Sandbox Code Playgroud)
现在,最后一部分处理实际的 paypal 调用和响应。这是通过位于“Mage_Paypal_Model_Api_Nvp”的 call() 函数完成的。
生成响应后,我们将检查错误响应,而不是重定向,我们只需将其返回到链上。
位于997号线附近:
if ($response['L_SHORTMESSAGE0'] == 'Duplicate invoice') {
return $response;
}
Run Code Online (Sandbox Code Playgroud)
所以事情是这样的:
startaction()->start()->call()->start()->startaction()->redirect();
Run Code Online (Sandbox Code Playgroud)
如果存在重复输入错误,它将执行此操作。
startaction()->start()->call(error)->start()->call()->start()->staraction()->redirect();
Run Code Online (Sandbox Code Playgroud)
如果您有任何疑问,请告诉我。
| 归档时间: |
|
| 查看次数: |
14964 次 |
| 最近记录: |