实际上发生的事情是,magento 正在向贝宝发送一个已经在系统中支付的 orderId(发票号码)。这会导致贝宝返回指示此发票编号重复的响应。因此,我在这里所做的是尝试检测该消息响应,生成新的 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);
...
}
}
到:
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']);
...
}
}
此令牌由“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;
}
现在,最后一部分处理实际的 paypal 调用和响应。这是通过位于“Mage_Paypal_Model_Api_Nvp”的 call() 函数完成的。
在生成响应后,我们将检查错误响应,而不是重定向,我们将简单地将其返回链上。
位于第 997 行附近:
if ($response['L_SHORTMESSAGE0'] == 'Duplicate invoice') {
return $response;
}
原来是这样的:
startaction()->start()->call()->start()->startaction()->redirect();
如果有重复输入错误,它将执行此操作..
startaction()->start()->call(error)->start()->call()->start()->staraction()->redirect();
如果您有任何问题,请告诉我。