| 1 |
<?php
|
| 2 |
// $Id: uc_aac.module,v 1.5.2.4 2009/01/14 19:49:42 cyu Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Updates product display_price and sell_price fields using AJAX
|
| 7 |
* whenever a product attribute is altered. Also updates the attribute
|
| 8 |
* adjustments dynamically if they are configured to display.
|
| 9 |
*
|
| 10 |
* Coded by Chris Yu (cYu).
|
| 11 |
*/
|
| 12 |
|
| 13 |
|
| 14 |
/*******************************************************************************
|
| 15 |
* Hook Functions
|
| 16 |
******************************************************************************/
|
| 17 |
|
| 18 |
/**
|
| 19 |
* Implementation of hook_theme().
|
| 20 |
**/
|
| 21 |
function uc_aac_theme() {
|
| 22 |
return array(
|
| 23 |
'uc_aac_js' => array(
|
| 24 |
'arguments' => array('node' => null),
|
| 25 |
),
|
| 26 |
);
|
| 27 |
}
|
| 28 |
|
| 29 |
|
| 30 |
/**
|
| 31 |
* Implementation of hook_menu().
|
| 32 |
*/
|
| 33 |
function uc_aac_menu() {
|
| 34 |
$items['uc_aac'] = array(
|
| 35 |
'title' => t('Price Calculation'),
|
| 36 |
'description' => t('Calculate the price of your product.'),
|
| 37 |
'page callback' => '_uc_aac_calculate_price',
|
| 38 |
'access arguments' => array('access content'),
|
| 39 |
'weight' => 5,
|
| 40 |
'type' => MENU_CALLBACK,
|
| 41 |
);
|
| 42 |
return $items;
|
| 43 |
}
|
| 44 |
|
| 45 |
/**
|
| 46 |
* Implementation of hook_form_alter().
|
| 47 |
*/
|
| 48 |
function uc_aac_form_alter(&$form, $form_state, $form_id) {
|
| 49 |
if (strstr($form_id, 'uc_product_add_to_cart_form_')) {
|
| 50 |
$priced_attributes = count(uc_attribute_priced_attributes($form['nid']['#value']));
|
| 51 |
|
| 52 |
if ($priced_attributes >= 1) {
|
| 53 |
drupal_add_js('misc/jquery.form.js');
|
| 54 |
drupal_add_js(_uc_aac_markup($form_id, $form['nid']['#value']), 'inline');
|
| 55 |
$form[$form_id]['uc_aac_nid'] = array(
|
| 56 |
'#type' => 'hidden',
|
| 57 |
'#value' => $form['nid']['#value'],
|
| 58 |
'#id' => 'uc_aac_nid_'. $form['nid']['#value'],
|
| 59 |
);
|
| 60 |
}
|
| 61 |
}
|
| 62 |
|
| 63 |
if ($form_id == 'uc_attribute_admin_settings') {
|
| 64 |
$form['uc_attribute_option_price_format']['uc_aac_reprice'] = array(
|
| 65 |
'#type' => 'checkbox',
|
| 66 |
'#title' => t('Ajax Attribute Calculations dynamically adjusts attribute prices as a product\'s sell price is updated.'),
|
| 67 |
'#default_value' => variable_get('uc_aac_attribute_reprice', '1'),
|
| 68 |
'#weight' => 0,
|
| 69 |
'#description' => t('When checked, a customer\'s selected attributes will display no price adjustment and all other attribute prices will be relative to the current price.'),
|
| 70 |
);
|
| 71 |
$form['#submit'][] = 'uc_aac_settings_submit';
|
| 72 |
}
|
| 73 |
}
|
| 74 |
|
| 75 |
/**
|
| 76 |
* Submit handler for uc_aac attribute setting.
|
| 77 |
*/
|
| 78 |
function uc_aac_settings_submit($form, &$form_state) {
|
| 79 |
variable_set('uc_aac_attribute_reprice', $form_state['values']['uc_aac_reprice']);
|
| 80 |
}
|
| 81 |
|
| 82 |
function _uc_aac_markup($form_id, $nid) {
|
| 83 |
$result = db_query('SELECT sell_price FROM {uc_products} WHERE nid=%d AND vid=(SELECT vid FROM {node} WHERE nid=%d)', $nid, $nid);
|
| 84 |
$priced_attributes = count(uc_attribute_priced_attributes($nid));
|
| 85 |
|
| 86 |
$price = 0;
|
| 87 |
if ($product = db_fetch_object($result)) {
|
| 88 |
$price = $product->sell_price;
|
| 89 |
}
|
| 90 |
$update_attributes = 0;
|
| 91 |
if (variable_get('uc_aac_attribute_reprice', '1') == 1 && (variable_get('uc_attribute_option_price_format', 'adjustment') == 'adjustment' || $priced_attributes > 1) && (variable_get('uc_attribute_option_price_format', 'adjustment') != 'none')) {
|
| 92 |
$update_attributes = 1;
|
| 93 |
}
|
| 94 |
return theme('uc_aac_js', $nid, $price, $update_attributes);
|
| 95 |
}
|
| 96 |
|
| 97 |
function theme_uc_aac_js($nid, $price, $update_attributes) {
|
| 98 |
/**
|
| 99 |
* If events aren't being properly attached to form elements, refer to the
|
| 100 |
* note at http://drupal.org/project/uc_aac about themes identifying product
|
| 101 |
* divs as 'node-$nid'.
|
| 102 |
*/
|
| 103 |
|
| 104 |
return '
|
| 105 |
var replace_price_'. $nid .' = "'. uc_currency_format($price) .'";
|
| 106 |
var aac_'. $nid .'_update = 0;
|
| 107 |
|
| 108 |
/**
|
| 109 |
* Initialize select attributes so that prices update on change, radio
|
| 110 |
* buttons update on click.
|
| 111 |
*/
|
| 112 |
function initialize_fields_'. $nid .'() {
|
| 113 |
$("#node-'. $nid .' select").each(function () {
|
| 114 |
var element = this;
|
| 115 |
if (element.name && element.name.match("attributes")) {
|
| 116 |
$(this).change(function () {
|
| 117 |
perform_ajax_calculation_'. $nid .'();
|
| 118 |
});
|
| 119 |
}
|
| 120 |
});
|
| 121 |
$("#node-'. $nid .' :radio").each(function () {
|
| 122 |
var element = this;
|
| 123 |
if (element.name && element.name.match("attributes")) {
|
| 124 |
// Needed because off odd click() behavior in IE with Jquery Update
|
| 125 |
// See http://drupal.org/node/336350
|
| 126 |
$(this).unbind("click");
|
| 127 |
$(this).bind("click", function () {
|
| 128 |
perform_ajax_calculation_'. $nid .'();
|
| 129 |
});
|
| 130 |
}
|
| 131 |
});
|
| 132 |
}
|
| 133 |
|
| 134 |
function perform_ajax_calculation_'. $nid .'() {
|
| 135 |
var aac_form = document.createElement("div");
|
| 136 |
aac_form.setAttribute( "target", "" );
|
| 137 |
aac_form.setAttribute( "action", "'. url("uc_aac",array('absolute' => TRUE)) .'" );
|
| 138 |
aac_form.setAttribute( "method", "post" );
|
| 139 |
aac_form.elements = [];
|
| 140 |
var element = document.getElementById("uc_aac_nid_'. $nid .'");
|
| 141 |
aac_form.elements[0] = element;
|
| 142 |
$("#node-'. $nid .' select").each(function () {
|
| 143 |
var element = this;
|
| 144 |
if (element.name && element.name.match("attributes")) {
|
| 145 |
aac_form.elements[aac_form.elements.length] = element;
|
| 146 |
}
|
| 147 |
});
|
| 148 |
$("#node-'. $nid .' :radio").each(function () {
|
| 149 |
var element = this;
|
| 150 |
if (element.name && element.name.match("attributes")) {
|
| 151 |
aac_form.elements[aac_form.elements.length] = element;
|
| 152 |
}
|
| 153 |
});
|
| 154 |
var this_update = new Date();
|
| 155 |
aac_'. $nid .'_update = this_update.getTime();
|
| 156 |
$(aac_form).ajaxSubmit( {
|
| 157 |
dataType: "json",
|
| 158 |
success: function(json_results) {
|
| 159 |
if (aac_'. $nid .'_update == this_update.getTime()) {
|
| 160 |
if ('. $update_attributes .' == 1) {
|
| 161 |
for (var i in json_results.attributes) {
|
| 162 |
if (json_results.attributes[i].type == "select") {
|
| 163 |
$("#node-'. $nid .' select").each(function () {
|
| 164 |
if (json_results.attributes[i].name == this.name) {
|
| 165 |
var select_attribute = this;
|
| 166 |
// Assume that any options removed from the select are at the beginning, like "Please select", and adjust selected index accordingly
|
| 167 |
var attribute_index = select_attribute.selectedIndex - select_attribute.length + json_results.attributes[i].options.length;
|
| 168 |
while (select_attribute.length) {
|
| 169 |
select_attribute.remove(0);
|
| 170 |
}
|
| 171 |
for (var j in json_results.attributes[i].options) {
|
| 172 |
select_option = json_results.attributes[i].options[j];
|
| 173 |
new_option = document.createElement("option");
|
| 174 |
new_option.text = select_option.label + " " + select_option.adjustment;
|
| 175 |
new_option.value = select_option.key;
|
| 176 |
if (j == attribute_index) {
|
| 177 |
new_option.selected = true;
|
| 178 |
new_option.defaultSelected = true;
|
| 179 |
}
|
| 180 |
if ($.browser.msie) {
|
| 181 |
select_attribute.add(new_option);
|
| 182 |
}
|
| 183 |
else {
|
| 184 |
select_attribute.add(new_option, null);
|
| 185 |
}
|
| 186 |
}
|
| 187 |
}
|
| 188 |
});
|
| 189 |
}
|
| 190 |
if (json_results.attributes[i].type == "radio") {
|
| 191 |
var radio_index = 0;
|
| 192 |
$("#node-'. $nid .' :radio").parent().each(function (j) {
|
| 193 |
if (this.firstChild.name == json_results.attributes[i].name) {
|
| 194 |
radio_option = json_results.attributes[i].options[radio_index];
|
| 195 |
if (radio_option.adjustment.length > 0) {
|
| 196 |
radio_option.label += ",";
|
| 197 |
}
|
| 198 |
radio_index ++;
|
| 199 |
if ($.browser.msie) {
|
| 200 |
var radio_input = this.innerHTML.slice(0, this.innerHTML.indexOf(">") + 1);
|
| 201 |
this.innerHTML = radio_input + " " + radio_option.label + " " + radio_option.adjustment;
|
| 202 |
}
|
| 203 |
else {
|
| 204 |
this.childNodes[this.childNodes.length-1].textContent = " " + radio_option.label + " " + radio_option.adjustment;
|
| 205 |
}
|
| 206 |
}
|
| 207 |
});
|
| 208 |
if ($.browser.msie) {
|
| 209 |
// Re-apply all of the onClick events that get lost when using innerHTML
|
| 210 |
initialize_fields_'. $nid .'();
|
| 211 |
}
|
| 212 |
}
|
| 213 |
}
|
| 214 |
}
|
| 215 |
var currentsellHTML= $("#node-'. $nid .' .uc-price-sell").html();
|
| 216 |
var currentdisplayHTML = $("#node-'. $nid .' .uc-price-display").html();
|
| 217 |
updated_price = json_results.updated_price;
|
| 218 |
if (currentdisplayHTML) {
|
| 219 |
$("#node-'. $nid .' .uc-price-display").html(currentdisplayHTML.replace(replace_price_'. $nid .', updated_price));
|
| 220 |
}
|
| 221 |
if (currentsellHTML) {
|
| 222 |
$("#node-'. $nid .' .uc-price-sell").html(currentsellHTML.replace(replace_price_'. $nid .', updated_price));
|
| 223 |
}
|
| 224 |
replace_price_'. $nid .' = updated_price;
|
| 225 |
}
|
| 226 |
},
|
| 227 |
error: function() {
|
| 228 |
//alert("Price update failed.");
|
| 229 |
}
|
| 230 |
});
|
| 231 |
}
|
| 232 |
|
| 233 |
function load_function_'. $nid .'() {
|
| 234 |
initialize_fields_'. $nid .'();
|
| 235 |
perform_ajax_calculation_'. $nid .'();
|
| 236 |
}
|
| 237 |
$().ready(load_function_'. $nid .');
|
| 238 |
';
|
| 239 |
}
|
| 240 |
|
| 241 |
function _uc_aac_calculate_price() {
|
| 242 |
$field_values = $_POST;
|
| 243 |
$nid = $field_values['uc_aac_nid'];
|
| 244 |
$base_price = db_result(db_query('SELECT sell_price FROM {uc_products} WHERE nid=%d AND vid=(SELECT vid FROM {node} WHERE nid=%d)', $nid, $nid));
|
| 245 |
$updated_price = $base_price;
|
| 246 |
$attributes = $field_values['attributes'];
|
| 247 |
$types = array(0 => "text", 1 => "select", 2 => "radio");
|
| 248 |
if ($attributes) {
|
| 249 |
foreach ($attributes as $attribute) {
|
| 250 |
$aid = db_result(db_query('SELECT aid FROM {uc_attribute_options} WHERE oid = %d', $attribute));
|
| 251 |
$display = db_result(db_query('SELECT display FROM {uc_product_attributes} WHERE aid = %d AND nid = %d', $aid, $nid));
|
| 252 |
$options = db_query('SELECT DISTINCT upo.oid, uao.name, upo.cost, upo.price FROM {uc_attribute_options} AS uao LEFT JOIN {uc_product_options} AS upo ON uao.oid = upo.oid WHERE uao.aid = %d AND upo.nid = %d ORDER BY upo.ordering, uao.ordering, uao.name', $aid, $nid);
|
| 253 |
$names = array();
|
| 254 |
$prices = array();
|
| 255 |
while ($option = db_fetch_object($options)) {
|
| 256 |
$names[$option->oid] = $option->name;
|
| 257 |
$prices[$option->oid] = $option->price;
|
| 258 |
if ($option->oid == $attribute) {
|
| 259 |
$used_price[$aid] = $option->price;
|
| 260 |
$updated_price += $option->price;
|
| 261 |
}
|
| 262 |
}
|
| 263 |
$attribute_options = array();
|
| 264 |
foreach ($prices as $oid => $attribute_price) {
|
| 265 |
$adjusted_price = $attribute_price - $used_price[$aid];
|
| 266 |
$price_text = '';
|
| 267 |
if ($adjusted_price != 0) {
|
| 268 |
if ($adjusted_price > 0) {
|
| 269 |
$price_text .= "+";
|
| 270 |
}
|
| 271 |
$price_text .= uc_currency_format($adjusted_price);
|
| 272 |
}
|
| 273 |
$attribute_options[] = array('key' => $oid, 'label' => $names[$oid], 'adjustment' => $price_text);
|
| 274 |
}
|
| 275 |
$output['attributes'][] = array('name' => 'attributes['. $aid .']', 'type' => $types[$display], 'options' => $attribute_options);
|
| 276 |
}
|
| 277 |
}
|
| 278 |
$output['updated_price'] = uc_currency_format($updated_price);
|
| 279 |
drupal_json($output);
|
| 280 |
exit();
|
| 281 |
}
|