Lời nói đầu: Điều này có nghĩa là đóng vai trò là một quan sát bằng văn bản về kiến trúc của Magento cho cộng đồng (và bản thân tôi), cũng như một câu hỏi thực tế. Chúng tôi đang làm việc với một giỏ hàng được sửa đổi nhiều và trải nghiệm thanh toán, nhưng gốc rễ của vấn đề này nằm trong logic cốt lõi của Magento.
Lý lịch
Chúng tôi đã tạo một phiếu giảm giá vận chuyển miễn phí bằng cách sử dụng chức năng quy tắc giá mua sắm tiêu chuẩn. Không có điều kiện trên phiếu giảm giá, và hành động duy nhất là Free Shipping
được đặt thành For matching items only
. Vì không có điều kiện, điều này sẽ được đặt free_shipping
thành 1
cho tất cả các mục báo giá bán hàng.
Theo thông lệ, chúng tôi cũng đã kích hoạt phương thức Giao hàng miễn phí. Các Freeshipping
mô hình hãng sẽ cung cấp giá bất cứ khi nào theo yêu cầu có miễn phí vận chuyển hoặc các trận đấu tổng phụ hoặc vượt quá ngưỡng (nhưng chúng tôi không sử dụng tùy chọn ngưỡng). Xem 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 */
}
Và Mage_Shipping_Model_Carrier_Freeshipping::_updateFreeMethodQuote
trông như thế này:
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);
}
}
Vì vậy, miễn là tất cả các mặt hàng đã free_shipping
được đặt thành một giá trị trung thực (mà chúng sẽ, do phiếu giảm giá), chúng tôi sẽ được giao hàng miễn phí. Và chúng tôi làm!
Vấn đề
Tuy nhiên, có một tác dụng phụ lớn: mọi phương thức vận chuyển phụ thuộc vào một mặt hàng row_weight
(như trường hợp với phiên bản tùy chỉnh của hãng vận chuyển FedEx) sẽ không tính được mức giá vận chuyển phù hợp vì mỗi mặt hàng row_weight
được đặt thành 0
khi vận chuyển miễn phí được kích hoạt.
Thật thú vị, không có nhà vận chuyển mặc định nào của Magento thực sự dựa vào row_weight
, nhưng chúng ta sẽ hiểu điều đó sau khi chúng ta tìm hiểu tại sao / khi nào row_weight
được đặt thành 0
.
Tìm hiểu tại sao row_weight
được đặt thành0
Phần này thực sự khá dễ dàng để đào lên. Một phần lớn các tính toán vận chuyển xảy ra Mage_Sales_Model_Quote_Address_Total_Shipping::collect
, bao gồm cài đặt row_weight
thành 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);
}
}
Tại sao điều này không ảnh hưởng đến các nhà mạng mặc định của Magento
Nếu bạn thực hiện tìm kiếm regex cho /row_?weight/i
(ví dụ getRowWeight
, setRowWeight
, setData('row_weight')
, vv) trong Mage_Shipping
(tàu sân bay đơn giản) và Mage_Usa
(FedEx, UPS, và một số hãng khác), không có gì bật lên. Tại sao? Bởi vì các nhà mạng mặc định sử dụng tổng trọng lượng địa chỉ, không phải trọng lượng vật phẩm riêng lẻ.
Ví dụ: chúng ta hãy nhìn vào 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());
}
Và yêu cầu có được trọng lượng gói từ đâu? Câu trả lời là trong 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());
Chúng ta có thể bỏ qua việc sử dụng $item->getRowWeight()
ở đây vì requestShippingRates
được gọi mà không cung cấp một mục cụ thể làm tham số trong 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();
Điều này sẽ trông quen thuộc, vì đây là cùng một nơi mà mỗi mặt hàng row_weight
được đặt 0
nếu giao hàng miễn phí có hiệu lực. Lưu ý cách tính $addressWeight
tổng của từng mục $rowWeight
, nhưng điều đó được thực hiện trước đó row_weight
được đặt thành0
.
Về cơ bản, trọng lượng địa chỉ sẽ luôn là tổng trọng lượng của tất cả các mặt hàng, bất kể free_shipping
giá trị của từng mặt hàng. Vì các nhà mạng mặc định của Magento chỉ dựa vào trọng lượng địa chỉ, nên vấn đề row_weight
không xuất hiện.
Vậy tại sao chúng ta cần row_weight
Chúng tôi cần row_weight
bởi vì chúng tôi đã tùy chỉnh nhà cung cấp dịch vụ FedEx của Magento để tính giá riêng cho các mặt hàng đến từ các nguồn gốc khác nhau, ngay cả khi chúng sẽ đến cùng một đích (và do đó là một phần của cùng một địa chỉ). Ví dụ: nếu bạn sống ở NJ, việc gửi một mặt hàng từ NJ rẻ hơn (và nhanh hơn) từ CA - và nếu bạn có các mặt hàng từ cả NJ và CA trong đơn đặt hàng của mình, bạn có thể thấy chi phí (và ước tính ngày giao hàng) của từng lô hàng.
Nói chung, có vẻ như chúng ta có thể dễ dàng giải quyết vấn đề này bằng cách bỏ qua row_weight
và sử dụng weight * qty
trực tiếp. Nhưng, nó dẫn chúng ta đến:
Câu hỏi
Tại sao Shipping
tổng số đặt các row_weight
mục báo giá bán hàng 0
nếu vận chuyển miễn phí có hiệu lực? Điều này dường như không được sử dụng ở bất cứ đâu.
Quan sát thêm
Tôi đã bỏ qua đề cập rằng row_weight
thực sự có thể là khác không, nhưng vẫn ít hơn weight * qty
, nếu free_shipping
là một số thay vì true
. Tôi giả sử mục đích của việc này là cung cấp giải pháp cho một kịch bản như thế này:
Tôi có 3 mặt hàng của cùng một sản phẩm trong giỏ hàng của tôi, mỗi mặt hàng nặng 2 lbs. Tôi áp dụng phiếu giảm giá vận chuyển miễn phí, nhưng nó giới hạn ở số lượng 2, vì vậy nó chỉ áp dụng cho 2 trong số các mặt hàng. Bây giờ, khi tôi nhìn vào giá vận chuyển, tôi sẽ xem giá vận chuyển cho 2 lbs (2 + 0 + 0) thay vì 6 lbs (2 + 2 + 2).
Điều này có vẻ có ý nghĩa, nhưng có hai vấn đề lớn với nó:
Không có nhà mạng Magento mặc định nào hoạt động như thế này (họ sử dụng tổng trọng lượng địa chỉ, xem ở trên).
Ngay cả khi một số hãng vận chuyển hoạt động như vậy, điều đó có nghĩa là tôi có thể chọn bất kỳ phương thức vận chuyển nào (ví dụ: vận chuyển qua đêm) và chỉ trả cho trọng lượng của 1 mặt hàng - có nghĩa là, thương gia sẽ phải trả chi phí cho 2 mặt hàng khác . Người bán sẽ tùy thuộc vào việc bằng cách nào đó tôi nhận ra rằng tôi chỉ trả cho trọng lượng của 1 mặt hàng, sau đó vận chuyển 2 mặt hàng khác bằng phương pháp hiệu quả hơn về chi phí, tạo ra sự không phù hợp giữa những gì Magento hiển thị và cách các mặt hàng thực sự vận chuyển ra.