Ö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 Shipping
ayarlandığı şeydir For matching items only
. Hiçbir koşul olduğundan, bu ayarlar free_shipping
için 1
satış 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_shipping
bir 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_weight
FedEx 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_weight
ayarlandığı 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_weight
ayarlandığını belirledikten sonra buna varacağız 0
.
Neden row_weight
ayarlandığı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ü requestShippingRates
belirli 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_weight
ayarlandığı yerdir 0
. $addressWeight
Her bir öğenin ne kadarını topladığına dikkat edin $rowWeight
, ancak bu daha önce row_weight
ayarlandığı şekilde0
yapılır .
Temel olarak, adres ağırlığı free_shipping
her 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_weight
gö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_weight
ve kullanarak bu konuda kolayca çalışabileceğimiz anlaşılıyor weight * qty
. Ancak, bizi yönlendirir:
Soru
Ücretsiz gönderim geçerliyse , Shipping
toplam neden row_weight
fiyat teklifi öğelerini belirler 0
? Bu hiçbir yerde kullanılmıyor gibi görünüyor.
Daha fazla gözlem
Ben belirtmeyi ihmal row_weight
hala az aslında sıfırdan olabilir, ama weight * qty
eğer, free_shipping
bir 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ı.