序文:これは、コミュニティ(および私)に対するMagentoのアーキテクチャの文書による観察と、実際の質問の両方の役割を果たすことを目的としています。大幅に変更されたカートとチェックアウトエクスペリエンスで作業していますが、この問題の原因はMagentoのコアロジック内にあります。
バックグラウンド
標準のショッピングカート価格ルール機能を使用して、送料無料クーポンを作成しました。クーポンには条件はなく、唯一のアクションFree Shipping
はに設定されていFor matching items only
ます。条件がないため、これはすべての販売見積品目に対してに設定free_shipping
さ1
れます。
通常どおり、送料無料配送方法も有効にしています。Freeshipping
リクエストが送料無料や小計マッチを持っているか、しきい値を超えたときにキャリアモデルは、速度を提供します(しかし、我々は、しきい値オプションを使用していません)。参照Mage_Shipping_Model_Carrier_Freeshipping::collectRates
:
$this->_updateFreeMethodQuote($request);
if (($request->getFreeShipping()) // <-- This is the condition we're relying on
|| ($request->getBaseSubtotalInclTax() >=
$this->getConfigData('free_shipping_subtotal'))
) {
/* Snip: Add $0.00 method to the result */
}
そしてMage_Shipping_Model_Carrier_Freeshipping::_updateFreeMethodQuote
、このようになります:
protected function _updateFreeMethodQuote($request)
{
$freeShipping = false;
$items = $request->getAllItems();
$c = count($items);
for ($i = 0; $i < $c; $i++) {
if ($items[$i]->getProduct() instanceof Mage_Catalog_Model_Product) {
if ($items[$i]->getFreeShipping()) {
$freeShipping = true;
} else {
return;
}
}
}
if ($freeShipping) {
$request->setFreeShipping(true);
}
}
そのため、すべてのアイテムがfree_shipping
真実の値に設定されている限り(クーポンのために)、送料が無料になります。そして、私たちはやる!
問題
ただし、大きな副作用があります:アイテムに依存する配送方法row_weight
(カスタマイズ版のFedEx運送業者の場合)は、各アイテムrow_weight
が0
送料無料が有効なときに設定されるため、適切な配送料金の計算に失敗します。
興味深いことに、Magentoのデフォルトの配送業者は実際には依存してrow_weight
いませんが、why / when row_weight
がに設定されていることを理解した後、それについて説明します0
。
にrow_weight
設定されている理由を理解する0
この部分は実際に掘り下げるのが非常に簡単でした。でのMage_Sales_Model_Quote_Address_Total_Shipping::collect
設定row_weight
を含む、出荷計算の大部分が発生します0
。
public function collect(Mage_Sales_Model_Quote_Address $address)
{
parent::collect($address);
foreach ($items as $item) {
/* Snip: Handling virtual items and parent items */
if ($item->getHasChildren() && $item->isShipSeparately()) {
/* Snip: Handling items with children */
}
else {
if (!$item->getProduct()->isVirtual()) {
$addressQty += $item->getQty();
}
$itemWeight = $item->getWeight();
$rowWeight = $itemWeight*$item->getQty();
$addressWeight+= $rowWeight;
if ($freeAddress || $item->getFreeShipping()===true) {
$rowWeight = 0;
} elseif (is_numeric($item->getFreeShipping())) {
$freeQty = $item->getFreeShipping();
if ($item->getQty()>$freeQty) {
$rowWeight = $itemWeight*($item->getQty()-$freeQty);
}
else {
$rowWeight = 0;
}
}
$freeMethodWeight+= $rowWeight;
$item->setRowWeight($rowWeight);
}
}
これがMagentoのデフォルトキャリアに影響を与えない理由
あなたがのための正規表現検索を行う場合/row_?weight/i
(例えばgetRowWeight
、setRowWeight
、setData('row_weight')
で、など)Mage_Shipping
(シンプルキャリア)とMage_Usa
(フェデックス、UPS、およびいくつかの他のキャリア)、何がポップアップしません。どうして?デフォルトの運送業者は、個々のアイテムの重量ではなく、住所の合計重量を使用するためです。
例えば、見てみましょうMage_Usa_Model_Shipping_Carrier_Fedex::setRequest
:
public function setRequest(Mage_Shipping_Model_Rate_Request $request)
{
$this->_request = $request;
$r = new Varien_Object();
/* Snip */
$weight = $this->getTotalNumOfBoxes($request->getPackageWeight());
$r->setWeight($weight);
if ($request->getFreeMethodWeight()!= $request->getPackageWeight()) {
$r->setFreeMethodWeight($request->getFreeMethodWeight());
}
そして、リクエストはどこからパッケージの重量を取得しますか?答えは次のとおりですMage_Sales_Model_Quote_Address::requestShippingRates
。
public function requestShippingRates(Mage_Sales_Model_Quote_Item_Abstract $item = null)
{
/** @var $request Mage_Shipping_Model_Rate_Request */
$request = Mage::getModel('shipping/rate_request');
/* Snip */
$request->setPackageWeight($item ? $item->getRowWeight() : $this->getWeight());
の特定のアイテムをパラメーターとして提供せずに呼び出される$item->getRowWeight()
ため、ここの使用を無視できrequestShippingRates
ますMage_Sales_Model_Quote_Address_Total_Shipping::collect
。
public function collect(Mage_Sales_Model_Quote_Address $address)
{
parent::collect($address);
foreach ($items as $item) {
/* Snip: Handling virtual items and parent items */
if ($item->getHasChildren() && $item->isShipSeparately()) {
/* Snip: Handling items with children */
}
else {
if (!$item->getProduct()->isVirtual()) {
$addressQty += $item->getQty();
}
$itemWeight = $item->getWeight();
$rowWeight = $itemWeight*$item->getQty();
$addressWeight+= $rowWeight;
if ($freeAddress || $item->getFreeShipping()===true) {
$rowWeight = 0;
} elseif (is_numeric($item->getFreeShipping())) {
$freeQty = $item->getFreeShipping();
if ($item->getQty()>$freeQty) {
$rowWeight = $itemWeight*($item->getQty()-$freeQty);
}
else {
$rowWeight = 0;
}
}
$freeMethodWeight+= $rowWeight;
$item->setRowWeight($rowWeight);
}
}
$address->setWeight($addressWeight);
$address->setFreeMethodWeight($freeMethodWeight);
$address->collectShippingRates();
これは、送料無料が有効な場合に各アイテムrow_weight
が設定される場所と同じであるため、おなじみのはずです0
。$addressWeight
各アイテムの集計方法に注意してください$rowWeight
。ただし、前にrow_weight
0
行われた設定はに設定されています。
基本的に、住所の重みはfree_shipping
、各アイテムの値に関係なく、常にすべてのアイテムの合計の重みになります。Magentoのデフォルトキャリアはアドレスの重みにのみ依存するため、問題は発生しrow_weight
ません。
なぜ必要なのか row_weight
必要なのはrow_weight
、MagentoのFedEx運送業者をカスタマイズして、同じ目的地(したがって同じ住所の一部)に行く商品であっても、異なる出発地から来る商品の個別料金を計算するためです。たとえば、NJに住んでいる場合、CAよりもNJからアイテムを出荷する方が安く(そして速く)注文にNJとCAの両方のアイテムがある場合、コストを確認できます(そして推定配送日)。
全体として、無視row_weight
してweight * qty
直接使用することでこの問題を簡単に回避できるようです。しかし、それは私たちを次のように導きます:
質問
送料無料が有効な場合、Shipping
合計でrow_weight
販売見積品目が設定されるのはなぜ0
ですか?これはどこにも利用されていないようです。
さらなる観察
私row_weight
は実際にはゼロ以外である可能性があることに言及することを怠りましたが、それでも未満の場合weight * qty
、のfree_shipping
代わりに数値ですtrue
。この目的は、次のようなシナリオの解決策を提供することだと思います。
私はカートに同じ製品の3つのアイテムがあり、各アイテムの重量は2ポンドです。送料無料クーポンを適用しますが、数量が2に制限されているため、2つのアイテムにのみ適用されます。ここで、配送料金を見ると、6ポンド(2 + 2 + 2)ではなく、2ポンド(2 + 0 + 0)の配送料金を探しています。
これは理にかなっているように思えますが、2つの大きな問題があります。
デフォルトのMagentoキャリアはどれもこのように動作しません(アドレスの総重量を使用します。上記を参照)。
運送業者の一部がこのように働いていたとしても、それは私が任意の配送方法(夜間配送など)を選択し、1つのアイテムの重量だけを支払うことができることを意味します。 。私が1つのアイテムの重量だけを支払ったことを何らかの形で理解してから、より費用対効果の高い方法を使用して他の2つのアイテムを出荷し、Magentoが表示するものとアイテムの実際の方法との間の不一致を効果的に作成するのは商人次第です発送しました。