Önsöz: Bu, Magento'nun topluluk (ve kendim için) mimarisine ilişkin yazılı bir gözlem ve aynı zamanda gerçek bir soru olarak hizmet etmek içindir. Yoğun olarak değiştirilmiş bir araba ve ödeme deneyimi ile çalışıyoruz, ancak bu sorunun kaynağı Magento'nun ana mantığı içinde.
Arka fon
Standart alışveriş sepeti fiyat kuralları işlevini kullanarak ücretsiz bir nakliye kuponu oluşturduk. Kuponda hiçbir koşul yoktur ve tek eylem bunun Free Shippingayarlandığı şeydir For matching items only. Hiçbir koşul olduğundan, bu ayarlar free_shippingiçin 1satış alıntı öğelerin tümü için.
Geleneksel olduğu gibi, Ücretsiz Kargo sevkıyat yöntemini de etkinleştirdik. Freeshippingİstek ücretsiz kargo veya subtotal eşleşmeye sahip veya eşiğini aştığında taşıyıcı modeli oranları sağlayacaktır (ama biz eşik seçeneği kullanmıyorsanız). Bakınız 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 */
}
Ve Mage_Shipping_Model_Carrier_Freeshipping::_updateFreeMethodQuoteşuna benziyor:
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);
}
}
Bu nedenle, tüm eşyalar free_shippingbir truthy değerine ayarlandığı sürece (ki bu kupondan dolayı olacaktır) ücretsiz nakliye alacağız. Ve yapıyoruz!
Sorun
Bununla birlikte, büyük bir yan etkisi vardır: row_weightFedEx taşıyıcısının özelleştirilmiş sürümünde olduğu gibi, bir öğeye dayanan herhangi bir gönderi yöntemi, her öğenin ücretsiz gönderim etkin olduğunda row_weightayarlandığı için uygun gönderim ücretlerini hesaplayamaz 0.
İlginçtir ki, Magento'nun varsayılan nakliye gemilerinin hiçbiri aslında güvenmiyor row_weight, ancak neden / ne zaman row_weightayarlandığını belirledikten sonra buna varacağız 0.
Neden row_weightayarlandığını bulmak0
Bu kısmı kazmak oldukça kolaydı. Sevkıyat hesaplamalarının büyük bir kısmı Mage_Sales_Model_Quote_Address_Total_Shipping::collect, aşağıdakiler dahil olmak üzere row_weight, içinde 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);
}
}
Bu neden Magento'nun varsayılan operatörlerini etkilemiyor?
Bir için düzenli ifade arama yaparsanız /row_?weight/i(örneğin getRowWeight, setRowWeight, setData('row_weight')içinde, vb) Mage_Shipping(basit taşıyıcılar) ve Mage_Usa(FedEx, UPS, ve diğer bazı taşıyıcılar), hiçbir şey açılır. Niye ya? Çünkü varsayılan taşıyıcılar, her bir öğenin ağırlığını değil, toplam adres ağırlığını kullanır.
Örneğin, bakalım 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());
}
Ve talep paket ağırlığını nereden alıyor? Cevap içinde 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());
Burada kullanımını görmezden gelebiliriz $item->getRowWeight()çünkü requestShippingRatesbelirli bir öğeyi parametre olarak sağlamadan çağrılır 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();
Bu, tanıdık görünmelidir, çünkü bu, ücretsiz gönderimin geçerli olması durumunda her bir öğenin row_weightayarlandığı yerdir 0. $addressWeightHer bir öğenin ne kadarını topladığına dikkat edin $rowWeight, ancak bu daha önce row_weightayarlandığı şekilde0 yapılır .
Temel olarak, adres ağırlığı free_shippingher bir öğenin değerinden bağımsız olarak her zaman tüm öğelerin toplam ağırlığı olacaktır . Magento'nun varsayılan taşıyıcıları yalnızca adres ağırlığına bağlı olduklarından, sorun row_weightgörünmüyor.
Peki neden ihtiyacımız var row_weight
İhtiyacımız var, row_weightçünkü Magento’nun FedEx operatörünü, aynı hedefe gidiyor olsalar bile (ve böylece aynı adresin bir parçası olsalar), farklı kökenlerden gelen ürünler için ayrı oranları hesaplamak üzere özelleştirdik. Örneğin, NJ’de yaşıyorsanız, NJ’den bir öğeyi CA’dan göndermekten daha ucuz (ve daha hızlı) - ve eğer siparişinizde hem NJ hem de CA’dan öğeleriniz varsa, maliyeti görebilirsiniz (ve tahmin edilir). Her gönderinin teslim tarihi).
Sonuç olarak, doğrudan görmezden row_weightve kullanarak bu konuda kolayca çalışabileceğimiz anlaşılıyor weight * qty. Ancak, bizi yönlendirir:
Soru
Ücretsiz gönderim geçerliyse , Shippingtoplam neden row_weightfiyat teklifi öğelerini belirler 0? Bu hiçbir yerde kullanılmıyor gibi görünüyor.
Daha fazla gözlem
Ben belirtmeyi ihmal row_weighthala az aslında sıfırdan olabilir, ama weight * qtyeğer, free_shippingbir sayı yerine ise true. Bunun amacının, böyle bir senaryoya bir çözüm sağlamak olduğunu varsaymaktayım:
Sepetimde aynı üründen 3 ürün var, her ürün 2 lb ağırlığında. Ücretsiz gönderim kuponu uygularım, ancak bu miktar 2 ile sınırlıdır, bu nedenle yalnızca 2 öğeye uygulanır. Şimdi, nakliye ücretlerine baktığımda, 6 lbs (2 + 2 + 2) yerine 2 lbs (2 + 0 + 0) için nakliye ücretlerine bakacağım.
Bu mantıklı görünüyor, ancak onunla iki büyük sorun var:
Varsayılan Magento taşıyıcılarının hiçbiri bu şekilde çalışmaz (adres toplam ağırlığını kullanırlar, yukarıya bakın).
Taşıyıcıların bazıları bu şekilde çalışsa bile, bu, herhangi bir nakliye yöntemini seçebileceğim anlamına gelir (örn. Bir gecede nakliye) ve sadece 1 öğenin ağırlığını öderim - yani, satıcı diğer 2 öğenin maliyetini karşılamak zorunda kalırdı. . Bir şekilde, sadece 1 öğenin ağırlığını ödediğimi ve ardından diğer 2 öğeyi daha düşük maliyetli bir yöntem kullanarak gönderdiğimi, Magento’nun gösterdiği şey ile öğelerin gerçekte nasıl olduğu arasında bir uyumsuzluk yaratacağını anlamaya çalışmak tüccara kalmış. kargolandı.