Project:
UbercartCategory:
bug reportVersion:
Ubercart 1.3Priority:
normalAssigned:
UnassignedStatus:
patch (needs review)uc_quote_request_quotes (line 1349, quotes.module) called by /cart/checkout/shipping/quote, only provides _uc_quote_assemble_quotes (line 1415, quotes.module) with an $order with delivery address (as taken from the $_POST). However this $order is then used by workflow_ng and may contain logic which acts the billing address e.g. if you wanted to use a shipping method if the buyer was in a given country.

Re: Shipping quotes do not provide enough data for workflows
working towards a solution atm... (also in
#drupal-ubercart if you wanted details)
Re: Shipping quotes do not provide enough data for workflows
This fix needs changes in 2 locations.
First we need to send the billing address details to the function, so we need some extra javascript
uc_quote.js :line 65:
function quoteCallback(products) {
var updateCallback = function (progress, status, pb) {
if (progress == 100) {
pb.stopMonitoring();
}
};
page = $("input:hidden[@name*=page]").val();
details = new Object();
details["uid"] = $("input[@name*=uid]").val();
//details["details[zone]"] = $("select[@name*=delivery_zone] option:selected").val();
//details["details[country]"] = $("select[@name*=delivery_country] option:selected").val();
$("select[@name*=delivery_]").each(function(i) {
details["details[delivery][" + $(this).attr("name").split("delivery_")[1].replace(/]/, "") + "]"] = $(this).val();
});
$("input[@name*=delivery_]").each(function(i) {
details["details[delivery][" + $(this).attr("name").split("delivery_")[1].replace(/]/, "") + "]"] = $(this).val();
});
$("select[@name*=billing_]").each(function(i) {
details["details[billing][" + $(this).attr("name").split("billing_")[1].replace(/]/, "") + "]"] = $(this).val();
});
$("input[@name*=billing_]").each(function(i) {
details["details[billing][" + $(this).attr("name").split("billing_")[1].replace(/]/, "") + "]"] = $(this).val();
});
if (!!products) {
details["products"] = products;
}
else {
products = "";
var i = 0;
while ($("input[@name^='products[" + i + "]']").length) {
products += "|" + $("input[@name^='products[" + i + "]']").filter("[@name$='[nid]']").val();
products += "^" + $("input[@name^='products[" + i + "]']").filter("[@name$='[title]']").val();
products += "^" + $("input[@name^='products[" + i + "]']").filter("[@name$='[model]']").val();
products += "^" + $("input[@name^='products[" + i + "]']").filter("[@name$='[manufacturer]']").val();
products += "^" + $("input[@name^='products[" + i + "]']").filter("[@name$='[qty]']").val();
products += "^" + $("input[@name^='products[" + i + "]']").filter("[@name$='[cost]']").val();
products += "^" + $("input[@name^='products[" + i + "]']").filter("[@name$='[price]']").val();
products += "^" + $("input[@name^='products[" + i + "]']").filter("[@name$='[weight]']").val();
i++;
}
details["products"] = products.substr(1);
}
var progress = new Drupal.progressBar("quoteProgress");
progress.setProgress(-1, Drupal.settings.uc_quote.progress_msg);
$("#quote").empty().append(progress.element);
$("#quote").addClass("solid-border");
// progress.startMonitoring(Drupal.settings['base_path'] + "shipping/quote", 0);
$.ajax({
type: "POST",
url: Drupal.settings['base_path'] + "cart/checkout/shipping/quote",
data: details,
dataType: "json",
success: displayQuote
});
return false;
}
The new/modified part is
$("select[@name*=delivery_]").each(function(i) {
details["details[delivery][" + $(this).attr("name").split("delivery_")[1].replace(/]/, "") + "]"] = $(this).val();
});
$("input[@name*=delivery_]").each(function(i) {
details["details[delivery][" + $(this).attr("name").split("delivery_")[1].replace(/]/, "") + "]"] = $(this).val();
});
$("select[@name*=billing_]").each(function(i) {
details["details[billing][" + $(this).attr("name").split("billing_")[1].replace(/]/, "") + "]"] = $(this).val();
});
$("input[@name*=billing_]").each(function(i) {
details["details[billing][" + $(this).attr("name").split("billing_")[1].replace(/]/, "") + "]"] = $(this).val();
});
With the new data being submitted, we now need to make corresponding changes to uc_quote.module :line 1346:
<?php
/**
* Callback to return the shipping quote(s) of the appropriate quoting method(s).
*/
function uc_quote_request_quotes() {
/* print '<pre>';
print_r($_POST);
print '</pre>'; */
$products = array();
foreach (explode('|', urldecode($_POST['products'])) as $item) {
$props = explode('^', $item);
$product = new stdClass();
$product->nid = $props[0];
$product->title = $props[1];
$product->model = $props[2];
$product->manufacturer = $props[3];
$product->qty = $props[4];
$product->cost = $props[5];
$product->price = $props[6];
$product->weight = $props[7];
if ($data = unserialize($props[8])) {
$product->data = $data;
}
else {
$product->data = $props[8];
}
if ($product->nid) {
$node = (array)node_load($product->nid);
foreach ($node as $key => $value) {
if (!isset($product->$key)) {
$product->$key = $value;
}
}
}
$products[] = $product;
}
$fake_order = new stdClass();
$fake_order->uid = $_POST['uid'];
$fake_order->products = $products;
foreach ($_POST['details'] as $type => $address) {
foreach ($address as $key => $value) {
if ($key == 'country' AND $value == '') {
$value = variable_get('uc_store_country', 840);
}
$field = $type .'_'. $key;
$fake_order->$field = $value;
}
}
// Consider the total to be from products only, because line items are
// mostly non-existent at this point.
$fake_order->order_total = uc_order_get_total($fake_order, true);
// Get all quote types neccessary to fulfill order.
$quote_data = _uc_quote_assemble_quotes($fake_order);
//drupal_set_message('<pre>'. print_r($methods, true) .'</pre>');
//drupal_set_message('<pre>'. print_r($quote_data, true) .'</pre>');
$return_quotes = array();
foreach ($quote_data as $method_id => $options) {
foreach ($options as $accsrl => $data) {
$return_quotes[$method_id .'---'. $accsrl] = $data;
}
}
drupal_set_header("Content-Type: text/javascript; charset=utf-8");
print drupal_to_js($return_quotes);
exit();
}
function _uc_quote_assemble_quotes($order) {
$products = $order->products;
$shipping_types = array();
foreach ($products as $product) {
$shipping_types[] = uc_product_get_shipping_type($product);
}
$shipping_types = array_unique($shipping_types);
$all_types = module_invoke_all('shipping_type');
$shipping_type = '';
// Use the most prominent shipping type (lightest weight).
$type_weight = 1000; // arbitrary large number
foreach ($shipping_types as $type) {
if ($all_types[$type]['weight'] < $type_weight) {
$shipping_type = $all_types[$type]['id'];
$type_weight = $all_types[$type]['weight'];
}
}
$methods = array_filter(module_invoke_all('shipping_method'), '_uc_quote_method_enabled');
uasort($methods, '_uc_quote_type_sort');
foreach ($methods as $id => $method) {
if ($method['quote']['type'] != 'order' && $method['quote']['type'] != $shipping_type) {
unset($methods[$id]);
}
}
ob_start();
//drupal_set_message('<pre>'. print_r($products, true) .'</pre>');
$quote_data = array();
foreach ($methods as $method) {
workflow_ng_invoke_event('get_quote_from_'. $method['id'], $order, $method, $user);
$data = ob_get_contents();
if ($data = unserialize($data)) {
$quote_data[$method['id']] = $data;
}
ob_clean();
}
ob_end_clean();
return $quote_data;
}
?>
the new bit being, removing the old $details handling code at the top of the function and then modifying the loop around line 1390 :
<?phpforeach ($_POST['details'] as $type => $address) {
foreach ($address as $key => $value) {
if ($key == 'country' AND $value == '') {
$value = variable_get('uc_store_country', 840);
}
$field = $type .'_'. $key;
$fake_order->$field = $value;
}
}
?>
Re: Re: Shipping quotes do not provide enough data for workflows
OK, looks good. I'll get that committed.
However, for next time when there's more than a simple change to the code, I'd appreciate a patch. It helps me figure out just what I'm replacing.
Re: Re: Re: Shipping quotes do not provide enough data for workf
yeah sorry about that, will do next time