Magento:更改现有订单的送货方式
Magento: change shipping method on existing order
我正在尝试更改 Magento 中现有订单的运费。这在管理后端工作得很好,即使它是一个完整的过程,因为在我对送货地址对象设置新的送货方式并重新计算报价总额后,我必须手动更新很多订单 fields/attributes。
我的问题是 运行 在前端使用相同的代码时,它根本不起作用,引用 collectTotals 将恢复我在 shippingAddress 中所做的任何更改,我不知道如何解决它或为什么它在后端工作。
这是它的样子:
$shippingAddress = $quote->getShippingAddress();
$shippingAddress->setShippingMethod('dynamicshipping_'.$shippingCode);
$shippingAddress->setCollectShippingRates(true);
$shippingAddress->collectShippingRates();
$quote->setUseCustomerBalance(1)->setTotalsCollectedFlag(false)->collectTotals()->save();
$order->setShippingHiddenTaxAmount($shippingAddress->getShippingHiddenTaxAmount());
$order->setBaseShippingHiddenTaxAmount($shippingAddress->getBaseShippingHiddenTaxAmount());
$order->setBaseShippingHiddenTaxAmnt($shippingAddress->getBaseShippingHiddenTaxAmnt());
$order->setShippingInclTax($shippingAddress->getShippingInclTax());
$order->setBaseShippingInclTax($shippingAddress->getBaseShippingInclTax());
$order->setShippingTaxAmount($shippingAddress->getShippingTaxAmount());
$order->setBaseShippingTaxAmount($shippingAddress->getBaseShippingTaxAmount());
$order->setShippingAmount($shippingAddress->getShippingAmount());
$order->setBaseShippingAmount($shippingAddress->getBaseShippingAmount());
$order->setShippingDiscountAmount($shippingAddress->getShippingDiscountAmount());
$order->setBaseShippingDiscountAmount($shippingAddress->getBaseShippingDiscountAmount());
$order->setGrandTotal($shippingAddress->getGrandTotal());
$order->setBaseGrandTotal($shippingAddress->getBaseGrandTotal());
$order->setShippingMethod('dynamicshipping_'.$shippingCode);
$order->setShippingDescription($shippingDescription);
$order->setServicePoint($servicePoint);
$order->save();
正如我所说,每次从后端都运行良好,但从前端调用时却不行。
我试过各种变体,例如尝试消除旧运输方式的任何痕迹,但没有成功。
$quote->getShippingAddress()->removeAllShippingRates()
->setShippingMethod('dynamicshipping_'.$shippingCode)
->setShippingDescription($shippingDescription)
//->setBaseShippingAmount(0)
//->setBaseShippingTaxAmount(0)
//->setShippingTaxAmount(0)
//->setShippingInclTax(0)
->setCollectShippingRates(true)
//->unsetData('cached_items_all')
//->unsetData('cached_items_nominal')
//->unsetData('cached_items_nonnominal')
->collectShippingRates()
//->collectTotals()
->save();
在我看来,无论我做什么,当我调用 collectTotals 时,报价都好像使用了送货地址的 older/diffrent 副本。
任何建议,或者关于这在后端而不是前端如何工作的可能的见解?
编辑
经过更多的调试,我发现前端和后端的运费确实发生了变化。问题是,只有当 运行 此代码通过后端时,费用才会发生变化。很奇怪。它只是拒绝更新运费。
看起来我在 collectTotals 上遇到了一些问题,这就是它在事件未被触发的后端工作的原因。
完整代码供参考,我最近更改为使用更安全的方法将所有字段复制回订单。
/* @var $order Mage_Sales_Model_Order */
/* @var $quote Mage_Sales_Model_Quote */
$shippingAddress = $quote->getShippingAddress();
$shippingAddress->setShippingMethod('dynamicshipping_'.$shippingCode);
$shippingAddress->setShippingDescription($shippingDescription);
$shippingAddress->setCollectShippingRates(true)->collectShippingRates();
$quote->collectTotals();
if ($this->updateMagentoOrder($order, $quote)) {
// here's where I check if we successfully updated the authorized
// amount at the payment gateway, before saving anything
// wrapping the payment update and save in a try-catch
$quote->save();
$order->save();
}
并使用此方法更新所有订单字段:
/**
* Updates a Magento order based on quote changes
* will not save anything, up to the caller.
* deleting items not supported.
*
* @param $order Mage_Sales_Model_Order
* @param $quote Mage_Sales_Model_Quote
* @return bool
*/
public function updateMagentoOrder($order, $quote) {
if (!$order instanceof Mage_Sales_Model_Order || !$quote instanceof Mage_Sales_Model_Quote) {
return false;
}
try {
$converter = Mage::getSingleton('sales/convert_quote');
$converter->toOrder($quote, $order);
foreach ($quote->getAllItems() as $quoteItem) {
$orderItem = $converter->itemToOrderItem($quoteItem);
$quoteItemId = $quoteItem->getId();
$origOrderItem = empty($quoteItemId) ? null : $order->getItemByQuoteItemId($quoteItemId);
if ($origOrderItem) {
$origOrderItem->addData($orderItem->getData());
} else {
if ($quoteItem->getParentItem()) {
$orderItem->setParentItem(
$order->getItemByQuoteItemId($quoteItem->getParentItem()->getId())
);
$orderItem->setParentItemId($quoteItem->getParentItemId());
}
$order->addItem($orderItem);
}
}
if ($shippingAddress = $quote->getShippingAddress()) {
$converter->addressToOrder($shippingAddress, $order);
}
} catch (Exception $e) {
Mage::logException($e);
return false;
}
return true;
}
作为参考,上面的方法可以循环 $order->getAllItems()
并先对它们执行 $orderItem->cancel()->delete();
- 但我现在不支持删除项目。
删除前的cancel()
部分是为了让CatalogInventory模块恢复库存。它正在监听 sales_order_item_cancel
事件。
我正在尝试更改 Magento 中现有订单的运费。这在管理后端工作得很好,即使它是一个完整的过程,因为在我对送货地址对象设置新的送货方式并重新计算报价总额后,我必须手动更新很多订单 fields/attributes。
我的问题是 运行 在前端使用相同的代码时,它根本不起作用,引用 collectTotals 将恢复我在 shippingAddress 中所做的任何更改,我不知道如何解决它或为什么它在后端工作。
这是它的样子:
$shippingAddress = $quote->getShippingAddress();
$shippingAddress->setShippingMethod('dynamicshipping_'.$shippingCode);
$shippingAddress->setCollectShippingRates(true);
$shippingAddress->collectShippingRates();
$quote->setUseCustomerBalance(1)->setTotalsCollectedFlag(false)->collectTotals()->save();
$order->setShippingHiddenTaxAmount($shippingAddress->getShippingHiddenTaxAmount());
$order->setBaseShippingHiddenTaxAmount($shippingAddress->getBaseShippingHiddenTaxAmount());
$order->setBaseShippingHiddenTaxAmnt($shippingAddress->getBaseShippingHiddenTaxAmnt());
$order->setShippingInclTax($shippingAddress->getShippingInclTax());
$order->setBaseShippingInclTax($shippingAddress->getBaseShippingInclTax());
$order->setShippingTaxAmount($shippingAddress->getShippingTaxAmount());
$order->setBaseShippingTaxAmount($shippingAddress->getBaseShippingTaxAmount());
$order->setShippingAmount($shippingAddress->getShippingAmount());
$order->setBaseShippingAmount($shippingAddress->getBaseShippingAmount());
$order->setShippingDiscountAmount($shippingAddress->getShippingDiscountAmount());
$order->setBaseShippingDiscountAmount($shippingAddress->getBaseShippingDiscountAmount());
$order->setGrandTotal($shippingAddress->getGrandTotal());
$order->setBaseGrandTotal($shippingAddress->getBaseGrandTotal());
$order->setShippingMethod('dynamicshipping_'.$shippingCode);
$order->setShippingDescription($shippingDescription);
$order->setServicePoint($servicePoint);
$order->save();
正如我所说,每次从后端都运行良好,但从前端调用时却不行。
我试过各种变体,例如尝试消除旧运输方式的任何痕迹,但没有成功。
$quote->getShippingAddress()->removeAllShippingRates()
->setShippingMethod('dynamicshipping_'.$shippingCode)
->setShippingDescription($shippingDescription)
//->setBaseShippingAmount(0)
//->setBaseShippingTaxAmount(0)
//->setShippingTaxAmount(0)
//->setShippingInclTax(0)
->setCollectShippingRates(true)
//->unsetData('cached_items_all')
//->unsetData('cached_items_nominal')
//->unsetData('cached_items_nonnominal')
->collectShippingRates()
//->collectTotals()
->save();
在我看来,无论我做什么,当我调用 collectTotals 时,报价都好像使用了送货地址的 older/diffrent 副本。
任何建议,或者关于这在后端而不是前端如何工作的可能的见解?
编辑
经过更多的调试,我发现前端和后端的运费确实发生了变化。问题是,只有当 运行 此代码通过后端时,费用才会发生变化。很奇怪。它只是拒绝更新运费。
看起来我在 collectTotals 上遇到了一些问题,这就是它在事件未被触发的后端工作的原因。
完整代码供参考,我最近更改为使用更安全的方法将所有字段复制回订单。
/* @var $order Mage_Sales_Model_Order */
/* @var $quote Mage_Sales_Model_Quote */
$shippingAddress = $quote->getShippingAddress();
$shippingAddress->setShippingMethod('dynamicshipping_'.$shippingCode);
$shippingAddress->setShippingDescription($shippingDescription);
$shippingAddress->setCollectShippingRates(true)->collectShippingRates();
$quote->collectTotals();
if ($this->updateMagentoOrder($order, $quote)) {
// here's where I check if we successfully updated the authorized
// amount at the payment gateway, before saving anything
// wrapping the payment update and save in a try-catch
$quote->save();
$order->save();
}
并使用此方法更新所有订单字段:
/**
* Updates a Magento order based on quote changes
* will not save anything, up to the caller.
* deleting items not supported.
*
* @param $order Mage_Sales_Model_Order
* @param $quote Mage_Sales_Model_Quote
* @return bool
*/
public function updateMagentoOrder($order, $quote) {
if (!$order instanceof Mage_Sales_Model_Order || !$quote instanceof Mage_Sales_Model_Quote) {
return false;
}
try {
$converter = Mage::getSingleton('sales/convert_quote');
$converter->toOrder($quote, $order);
foreach ($quote->getAllItems() as $quoteItem) {
$orderItem = $converter->itemToOrderItem($quoteItem);
$quoteItemId = $quoteItem->getId();
$origOrderItem = empty($quoteItemId) ? null : $order->getItemByQuoteItemId($quoteItemId);
if ($origOrderItem) {
$origOrderItem->addData($orderItem->getData());
} else {
if ($quoteItem->getParentItem()) {
$orderItem->setParentItem(
$order->getItemByQuoteItemId($quoteItem->getParentItem()->getId())
);
$orderItem->setParentItemId($quoteItem->getParentItemId());
}
$order->addItem($orderItem);
}
}
if ($shippingAddress = $quote->getShippingAddress()) {
$converter->addressToOrder($shippingAddress, $order);
}
} catch (Exception $e) {
Mage::logException($e);
return false;
}
return true;
}
作为参考,上面的方法可以循环 $order->getAllItems()
并先对它们执行 $orderItem->cancel()->delete();
- 但我现在不支持删除项目。
删除前的cancel()
部分是为了让CatalogInventory模块恢复库存。它正在监听 sales_order_item_cancel
事件。