/[drupal]/contributions/modules/ubercart/uc_product/uc_product.module
ViewVC logotype

Contents of /contributions/modules/ubercart/uc_product/uc_product.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.14 - (show annotations) (download) (as text)
Thu Jul 10 12:41:03 2008 UTC (16 months, 2 weeks ago) by islandusurper
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--2
Changes since 1.13: +1025 -792 lines
File MIME type: text/x-php
Begin the Ubercart 6.x-2.x branch.
1 <?php
2 // $Id$
3
4 /**
5 * @file
6 * The product module for Ubercart.
7 *
8 * Provides information that is common to all products, and user-defined product
9 * classes for more specification. Recommends the image and taxonomy modules.
10 *
11 * Coded by: Lyle Mantooth
12 * Product Features by: Ryan Szrama
13 */
14
15 /******************************************************************************
16 * Drupal Hooks *
17 ******************************************************************************/
18
19 /**
20 * Implementation of hook_menu().
21 */
22 function uc_product_menu() {
23 $items = array();
24
25 $items['admin/store/products'] = array(
26 'title' => 'Products',
27 'description' => 'Administer products, classes, and more.',
28 'access arguments' => array('administer products'),
29 'page callback' => 'uc_product_administration',
30 'type' => MENU_NORMAL_ITEM,
31 'weight' => -2,
32 );
33 $items['admin/store/products/view'] = array(
34 'title' => 'View products',
35 'description' => 'Build and view a list of product nodes.',
36 'access arguments' => array('administer products'),
37 'type' => MENU_NORMAL_ITEM,
38 'weight' => -10,
39 );
40 $items['admin/store/products/classes'] = array(
41 'title' => 'Manage classes',
42 'description' => 'Create and edit product node types.',
43 'access arguments' => array('administer product classes'),
44 'page callback' => 'uc_product_class_default',
45 'type' => MENU_NORMAL_ITEM,
46 'weight' => -2,
47 );
48 $items['admin/store/settings/products'] = array(
49 'title' => 'Product settings',
50 'description' => 'Configure product settings.',
51 'access arguments' => array('administer products'),
52 'page callback' => 'uc_product_settings_overview',
53 'type' => MENU_NORMAL_ITEM,
54 );
55 $items['admin/store/settings/products/overview'] = array(
56 'title' => 'Overview',
57 'weight' => -10,
58 'type' => MENU_DEFAULT_LOCAL_TASK,
59 );
60 $items['admin/store/settings/products/edit'] = array(
61 'title' => 'Edit',
62 'access arguments' => array('administer products'),
63 'page callback' => 'drupal_get_form',
64 'page arguments' => array('uc_product_settings_form'),
65 'weight' => -5,
66 'type' => MENU_LOCAL_TASK,
67 );
68 $items['admin/store/settings/products/edit/general'] = array(
69 'title' => 'Product settings',
70 'access arguments' => array('administer products'),
71 'weight' => -10,
72 'type' => MENU_DEFAULT_LOCAL_TASK,
73 );
74 $items['admin/store/settings/products/edit/fields'] = array(
75 'title' => 'Product fields',
76 'page callback' => 'drupal_get_form',
77 'page arguments' => array('uc_product_field_settings_form'),
78 'access arguments' => array('administer products'),
79 'weight' => -5,
80 'type' => MENU_LOCAL_TASK,
81 );
82 $items['admin/store/settings/products/edit/features'] = array(
83 'title' => 'Product features',
84 'page callback' => 'drupal_get_form',
85 'page arguments' => array('uc_product_feature_settings_form'),
86 'access arguments' => array('administer product features'),
87 'weight' => 0,
88 'type' => MENU_LOCAL_TASK,
89 );
90 // Insert subitems into the edit node page for product types.
91 $items['node/%node/edit/product'] = array(
92 'title' => 'Product',
93 'access callback' => 'uc_product_edit_access',
94 'access arguments' => array(1),
95 'weight' => -10,
96 'type' => MENU_DEFAULT_LOCAL_TASK,
97 );
98 $features = module_invoke_all('product_feature');
99 if (!empty($features)) {
100 $items['node/%node/edit/features'] = array(
101 'title' => 'Features',
102 'page callback' => 'uc_product_features',
103 'page arguments' => array(1),
104 'access callback' => 'uc_product_feature_access',
105 'access arguments' => array(1),
106 'weight' => 10,
107 'type' => MENU_LOCAL_TASK,
108 );
109 }
110
111 $items['admin/store/settings/products/defaults/%'] = array(
112 'title' => 'Imagecache default settings',
113 'access arguments' => array('administer products'),
114 'page callback' => 'uc_product_image_defaults',
115 'page arguments' => array(5),
116 'type' => MENU_CALLBACK,
117 );
118 $items['admin/store/products/classes/%uc_product_class'] = array(
119 'title' => 'Product class',
120 'access arguments' => array('administer product classes'),
121 'page callback' => 'drupal_get_form',
122 'page arguments' => array('uc_product_class_form', 4),
123 'type' => MENU_CALLBACK,
124 );
125 $items['admin/store/products/classes/%uc_product_class/edit'] = array(
126 'title' => 'Edit',
127 'type' => MENU_DEFAULT_LOCAL_TASK,
128 'weight' => -5,
129 );
130 $items['admin/store/products/classes/%uc_product_class/delete'] = array(
131 'access arguments' => array('administer product classes'),
132 'page callback' => 'drupal_get_form',
133 'page arguments' => array('uc_product_class_delete_confirm', 4),
134 'type' => MENU_CALLBACK,
135 );
136
137 $items['products/field_image_cache/%'] = array(
138 'access callback' => TRUE,
139 'page callback' => '_uc_product_get_image_field_filepath',
140 'page arguments' => array(2),
141 'type' => MENU_CALLBACK,
142 );
143
144 return $items;
145 }
146
147 /**
148 * Implementation of hook_help().
149 */
150 function uc_product_help($path, $arg) {
151 // Do things here later. Figure out what you need to say for each section.
152 switch ($path) {
153 case 'admin/settings/module#description':
154 $output = t('Create products for sale in an online store.');
155 break;
156 }
157 return $output;
158 }
159
160 /**
161 * Implementation of hook_perm().
162 */
163 function uc_product_perm() {
164 $perms = array('administer products', 'administer product classes', 'administer product features');
165 foreach (node_get_types() as $type) {
166 if ($type->module == 'uc_product') {
167 $name = check_plain($type->type);
168 if ($name == 'product') {
169 $name = '';
170 }
171 else {
172 $name .= ' ';
173 }
174 $perms[] = 'create '. $name .'products';
175 $perms[] = 'edit own '. $name .'products';
176 $perms[] = 'edit '. $name .'products';
177 }
178 }
179 return $perms;
180 }
181
182 /**
183 * Implementation of hook_access().
184 */
185 function uc_product_access($op, $node) {
186 global $user;
187 $type = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type);
188
189 if ($type == 'product') {
190 $type = '';
191 }
192 else {
193 $type .= ' ';
194 }
195 switch ($op) {
196 case 'create':
197 return user_access('create '. $type .'products');
198 case 'update':
199 case 'delete':
200 if (user_access('edit '. $type .'products') || (user_access('edit own '. $type .'products') && ($user->uid == $node->uid))) {
201 return TRUE;
202 }
203 }
204 }
205
206 /**
207 * Menu access callback for 'node/%node/edit/product'.
208 */
209 function uc_product_edit_access($node) {
210 // Re-inherit access callback for 'node/%node/edit'
211 return uc_product_is_product($node) && node_access('update', $node);
212 }
213
214 /**
215 * Menu access callback for 'node/%node/edit/features'.
216 */
217 function uc_product_feature_access($node) {
218 return uc_product_is_product($node) && user_access('administer product features');
219 }
220
221 /**
222 * Implementation of hook_init().
223 */
224 function uc_product_init() {
225 drupal_add_css(drupal_get_path('module', 'uc_product') .'/uc_product.css');
226 }
227
228 /**
229 * Implementation of hook_enable().
230 *
231 * Set up default imagefield and imagecache settings.
232 */
233 function uc_product_enable() {
234 $node_types = node_get_types('types');
235 $product_classes = array('product');
236 $result = db_query("SELECT pcid, name, description FROM {uc_product_classes}");
237 while ($product_class = db_fetch_object($result)) {
238 $product_classes[] = $product_class->pcid;
239 }
240 foreach ($node_types as $type => $info) {
241 if ($info->module == 'node' && in_array($type, $product_classes)) {
242 $info->module = 'uc_product';
243 $info->custom = 0;
244 node_type_save($info);
245 }
246 }
247
248 if (module_exists('imagefield')) {
249 $result = db_query("SELECT field_name FROM {node_field} WHERE field_name = 'field_image_cache' AND type = 'image'");
250 if (!db_num_rows($result)) {
251 db_query("INSERT INTO {node_field} (field_name, type, global_settings, required, multiple, db_storage) VALUES ('field_image_cache', 'image', '%s', 0, 1, 0)", 'a:0:{}');
252 }
253 $image_path = file_create_path();
254 $widget_settings = array(
255 'max_resolution' => '0',
256 'image_path' => $image_path,
257 'custom_alt' => 1,
258 'custom_title' => 1,
259 'teaser_preset' => null,
260 'body_preset' => null,
261 );
262 $display_settings = array(
263 'label' => array(
264 'format' => 'hidden',
265 ),
266 'teaser' => array(
267 'format' => 'hidden',
268 ),
269 'full' => array(
270 'format' => 'hidden',
271 ),
272 );
273 foreach (module_invoke_all('product_types') as $type) {
274 $result = db_query("SELECT * FROM {node_field_instance} WHERE field_name = 'field_image_cache' and type_name = '%s'", $type);
275 if (!db_num_rows($result)) {
276 db_query("INSERT INTO {node_field_instance} VALUES ('field_image_cache', '%s', -2, 'Image', 'image', '%s', '%s', '')", $type, serialize($widget_settings), serialize($display_settings));
277 }
278 switch ($GLOBALS['db_type']) {
279 case 'mysql':
280 case 'mysqli':
281 db_query("CREATE TABLE IF NOT EXISTS {content_field_image_cache} (
282 `vid` int(10) unsigned NOT NULL default '0',
283 `delta` int(10) unsigned NOT NULL default '0',
284 `nid` int(10) unsigned NOT NULL default '0',
285 `field_image_cache_fid` int(11) NOT NULL default '0',
286 `field_image_cache_title` varchar(255) NOT NULL default '',
287 `field_image_cache_alt` varchar(255) NOT NULL default '',
288 PRIMARY KEY (`vid`,`delta`)
289 ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
290 break;
291 case 'pgsql':
292 $result = db_query("SELECT relname FROM pg_class WHERE relname = '{content_field_image_cache}'");
293 if (!db_num_rows($result)) {
294 db_query('CREATE TABLE {content_field_image_cache} (
295 "vid" int_unsigned NOT NULL default \'0\',
296 "delta" int_unsigned NOT NULL default \'0\',
297 "nid" int_unsigned NOT NULL default \'0\',
298 "field_image_cache_fid" integer NOT NULL default \'0\',
299 "field_image_cache_title" varchar(255) NOT NULL,
300 "field_image_cache_alt" varchar(255) NOT NULL,
301 PRIMARY KEY ("vid","delta")
302 );');
303 }
304 break;
305 }
306 }
307 content_clear_type_cache();
308 }
309 if (module_exists('imagecache')) {
310 $presets = array('product' => 0, 'product_list' => 0, 'uc_thumbnail' => 0);
311 $result = db_query("SELECT * FROM {imagecache_preset} WHERE presetname IN ('". implode("','", array_keys($presets)) ."')");
312 while ($preset = db_fetch_array($result)) {
313 $presets[$preset['presetname']] = $preset['presetid'];
314 }
315 //drupal_set_message('<pre>'. print_r($presets, true) .'</pre>');
316 foreach ($presets as $name => $id) {
317 if ($id == 0) {
318 $id = db_next_id('{imagecache_preset}_presetid');
319 db_query("INSERT INTO {imagecache_preset} (presetid, presetname) VALUES (%d, '%s')", $id, $name);
320 }
321 }
322 $result = db_query("SELECT ia.actionid, ip.presetid, ip.presetname FROM {imagecache_preset} AS ip LEFT JOIN {imagecache_action} AS ia ON ip.presetid = ia.presetid WHERE ip.presetname IN ('". implode("','", array_keys($presets)) ."')");
323 $presets = array();
324 while ($preset = db_fetch_array($result)) {
325 if (is_null($preset['actionid'])) {
326 switch ($preset['presetname']) {
327 case 'product':
328 db_query("INSERT INTO {imagecache_action} (actionid, presetid, weight, data) VALUES (%d, %d, 0, '%s')", db_next_id('{imagecache_action}_actionid'), $preset['presetid'], 'a:4:{s:8:"function";s:5:"scale";s:3:"fit";s:6:"inside";s:5:"width";s:3:"100";s:6:"height";s:3:"100";}');
329 break;
330 case 'product_list':
331 db_query("INSERT INTO {imagecache_action} (actionid, presetid, weight, data) VALUES (%d, %d, 0, '%s')", db_next_id('{imagecache_action}_actionid'), $preset['presetid'], 'a:4:{s:8:"function";s:5:"scale";s:3:"fit";s:6:"inside";s:5:"width";s:3:"100";s:6:"height";s:3:"100";}');
332 break;
333 case 'uc_thumbnail':
334 db_query("INSERT INTO {imagecache_action} (actionid, presetid, weight, data) VALUES (%d, %d, 0, '%s')", db_next_id('{imagecache_action}_actionid'), $preset['presetid'], 'a:4:{s:8:"function";s:5:"scale";s:3:"fit";s:6:"inside";s:5:"width";s:2:"35";s:6:"height";s:2:"35";}');
335 break;
336 }
337 }
338 }
339 cache_clear_all('imagecache:presets', 'cache');
340 }
341 }
342
343 function uc_product_disable() {
344 $product_types = node_get_types('types');
345 // node_type_rebuild() deletes disabled modules' node types. Give these
346 // node types to node.module to prevent this. Get them back during
347 // hook_enable().
348 foreach ($product_types as $type) {
349 if ($type->module == 'uc_product') {
350 $type->module = 'node';
351 $type->custom = 1;
352 node_type_save($type);
353 }
354 }
355 }
356
357 function uc_product_theme() {
358 return array(
359 'uc_product_form_prices' => array(
360 'arguments' => array('form' => NULL),
361 ),
362 'uc_product_form_weight' => array(
363 'arguments' => array('form' => NULL),
364 ),
365 'uc_product_dimensions' => array(
366 'arguments' => array('form' => NULL),
367 ),
368 'uc_product_field_settings_form' => array(
369 'arguments' => array('form' => NULL),
370 ),
371 'uc_product_model' => array(
372 'arguments' => array('model' => ''),
373 ),
374 'uc_product_add_to_cart' => array(
375 'arguments' => array('node' => NULL),
376 ),
377 'uc_product_price' => array(
378 'arguments' => array('price' => 0, 'class' => ''),
379 ),
380 'uc_product_sell_price' => array(
381 'arguments' => array('price' => 0, 'teaser' => FALSE),
382 ),
383 'uc_product_weight' => array(
384 'arguments' => array('weight' => 0, 'unit' => NULL),
385 ),
386 'uc_product_dimensions' => array(
387 'arguments' => array('length' => 0, 'width' => 0, 'height' => 0, 'units' => NULL),
388 ),
389 'uc_product_image' => array(
390 'arguments' => array('images'),
391 ),
392 'uc_product_display_price' => array(
393 'arguments' => array('price' => 0),
394 ),
395 'uc_product_feature_add_form' => array(
396 'arguments' => array('form' => NULL),
397 ),
398 );
399 }
400
401 /**
402 * Implementation of hook_node_info().
403 *
404 * Create node types for each product class and other product modules.
405 */
406 function uc_product_node_info($reset = false) {
407 static $types = array();
408 $title_label = t('Name');
409 $body_label = t('Description');
410
411 if (empty($types) || $reset) {
412 $types = array();
413 $types['product'] = array(
414 'name' => t('Product'),
415 'module' => 'uc_product',
416 'description' => t('This node displays the representation of a product for sale on the website. It includes
417 all the unique information that can be attributed to a specific model number.'),
418 'title_label' => $title_label,
419 'body_label' => $body_label,
420 );
421
422 $result = db_query("SELECT pcid, name, description FROM {uc_product_classes}");
423 while ($class = db_fetch_object($result)) {
424 $types[$class->pcid] = array(
425 'name' => $class->name,
426 'module' => 'uc_product',
427 'description' => $class->description,
428 'title_label' => $title_label,
429 'body_label' => $body_label,
430 );
431 }
432 }
433 return $types;
434 }
435
436 /**
437 * Implementation of hook_forms().
438 *
439 * Register an "add to cart" form for each product to prevent id collisions.
440 */
441 function uc_product_forms($form_id, $args) {
442 $forms = array();
443 if (substr($form_id, 0, 27) == 'uc_product_add_to_cart_form' || substr($form_id, 0, 26) == 'uc_catalog_buy_it_now_form') {
444 $products = db_query("SELECT DISTINCT nid, type FROM {node} WHERE nid = %d", $args[0]->nid);
445
446 while ($product = db_fetch_object($products)) {
447 if (in_array($product->type, array_keys(uc_product_node_info()))) {
448 $forms['uc_product_add_to_cart_form_'. $product->nid] = array('callback' => 'uc_product_add_to_cart_form');
449 $forms['uc_catalog_buy_it_now_form_'. $product->nid] = array('callback' => 'uc_catalog_buy_it_now_form');
450 }
451 }
452 }
453 return $forms;
454 }
455
456 /**
457 * Implementation of hook_form().
458 *
459 * @ingroup forms
460 * @see theme_uc_product_form_prices
461 * @see theme_uc_product_form_weight
462 * @see theme_uc_product_dimensions
463 * @see uc_product_form_validate
464 */
465 function uc_product_form(&$node) {
466 $location = array();
467 $location[] = menu_get_item('admin');
468 $location[] = menu_get_item('admin/store');
469 $location[] = menu_get_item('admin/store/products');
470 $location[] = menu_get_item('admin/store/settings/products');
471 $breadcrumb = array(l('Home', ''));
472 foreach ($location as $item) {
473 $breadcrumb[] = l($item['title'], $item['path']);
474 }
475 drupal_set_breadcrumb($breadcrumb);
476 $sign_flag = variable_get('uc_sign_after_amount', FALSE);
477 $currency_sign = variable_get('uc_currency_sign', '$');
478
479 $form['title'] = array('#type' => 'textfield',
480 '#title' => t('Name'),
481 '#required' => TRUE,
482 '#weight' => -5,
483 '#default_value' => $node->title,
484 '#description' => t('Name of the product.')
485 );
486
487 $form['body_filter']['body'] = array('#type' => 'textarea',
488 '#title' => t('Description'),
489 '#required' => FALSE,
490 '#default_value' => $node->body,
491 '#rows' => 20,
492 '#description' => t('Enter the product description used for product teasers and pages.'),
493 );
494 $form['body_filter']['format'] = filter_form($node->format);
495 $form['body_filter']['#weight'] = -4;
496
497 $form['base'] = array('#type' => 'fieldset',
498 '#title' => t('Product information'),
499 '#collapsible' => true,
500 '#collapsed' => false,
501 '#weight' => -1,
502 '#attributes' => array('class' => 'product-field'),
503 );
504 $form['base']['model'] = array('#type' => 'textfield',
505 '#title' => t('SKU'),
506 '#required' => TRUE,
507 '#default_value' => $node->model,
508 '#description' => t('Product SKU/model.'),
509 '#weight' => 0,
510 '#size' => 32,
511 );
512
513 $form['base']['prices'] = array(
514 '#weight' => 5,
515 '#theme' => 'uc_product_form_prices',
516 );
517
518 $form['base']['prices']['list_price'] = array(
519 '#type' => 'textfield',
520 '#title' => t('List price'),
521 '#required' => FALSE,
522 '#default_value' => $node->list_price,
523 '#description' => t('The listed MSRP.'),
524 '#weight' => 0,
525 '#size' => 20,
526 '#maxlength' => 35,
527 '#field_prefix' => $sign_flag ? '' : $currency_sign,
528 '#field_suffix' => $sign_flag ? $currency_sign : '',
529 );
530 $form['base']['prices']['cost'] = array(
531 '#type' => 'textfield',
532 '#title' => t('Cost'),
533 '#required' => FALSE,
534 '#default_value' => $node->cost,
535 '#description' => t("Your store's cost."),
536 '#weight' => 1,
537 '#size' => 20,
538 '#maxlength' => 35,
539 '#field_prefix' => $sign_flag ? '' : $currency_sign,
540 '#field_suffix' => $sign_flag ? $currency_sign : '',
541 );
542 $form['base']['prices']['sell_price'] = array(
543 '#type' => 'textfield',
544 '#title' => t('Sell price'),
545 '#required' => TRUE,
546 '#default_value' => $node->sell_price,
547 '#description' => t('Customer purchase price.'),
548 '#weight' => 2,
549 '#size' => 20,
550 '#maxlength' => 35,
551 '#field_prefix' => $sign_flag ? '' : $currency_sign,
552 '#field_suffix' => $sign_flag ? $currency_sign : '',
553 );
554
555 $form['base']['shippable'] = array(
556 '#type' => 'checkbox',
557 '#title' => t('Product and its derivatives are shippable.'),
558 '#default_value' => isset($node->shippable) ? $node->shippable : TRUE,
559 '#weight' => 10,
560 );
561
562 $form['base']['weight'] = array(
563 '#weight' => 15,
564 '#theme' => 'uc_product_form_weight',
565 );
566 $form['base']['weight']['weight'] = array('#type' => 'textfield',
567 '#title' => t('Weight'),
568 '#default_value' => $node->weight,
569 '#size' => 10,
570 '#maxlength' => 15,
571 );
572 $units = array(
573 'lb' => t('Pounds'),
574 'kg' => t('Kilograms'),
575 'oz' => t('Ounces'),
576 'g' => t('Grams'),
577 );
578 $form['base']['weight']['weight_units'] = array('#type' => 'select',
579 '#title' => t('Unit of measurement'),
580 '#default_value' => $node->weight_units ? $node->weight_units : variable_get('uc_weight_unit', 'lb'),
581 '#options' => $units,
582 );
583 $form['base']['dimensions'] = array('#type' => 'fieldset',
584 '#title' => t('Dimensions'),
585 '#description' => t('Physical dimensions of the packaged product.'),
586 '#weight' => 20,
587 '#theme' => 'uc_product_dimensions_form',
588 );
589 $form['base']['dimensions']['length_units'] = array('#type' => 'select',
590 '#title' => t('Units of measurement'),
591 '#options' => array(
592 'in' => t('Inches'),
593 'ft' => t('Feet'),
594 'cm' => t('Centimeters'),
595 'mm' => t('Millimeters'),
596 ),
597 '#default_value' => $node->length_units ? $node->length_units : variable_get('uc_length_unit', 'in'),
598 );
599 $form['base']['dimensions']['length'] = array('#type' => 'textfield',
600 '#title' => t('Length'),
601 '#default_value' => $node->length,
602 '#size' => 10,
603 );
604 $form['base']['dimensions']['width'] = array('#type' => 'textfield',
605 '#title' => t('Width'),
606 '#default_value' => $node->width,
607 '#size' => 10,
608 );
609 $form['base']['dimensions']['height'] = array('#type' => 'textfield',
610 '#title' => t('Height'),
611 '#default_value' => $node->height,
612 '#size' => 10,
613 );
614 $form['base']['pkg_qty'] = array('#type' => 'textfield',
615 '#title' => t('Package quantity'),
616 '#default_value' => $node->pkg_qty ? $node->pkg_qty : 1,
617 '#description' => t('For a package containing only this product, how many are in it?'),
618 '#weight' => 25,
619 );
620 $form['base']['default_qty'] = array('#type' => 'textfield',
621 '#title' => t('Default quantity to add to cart'),
622 '#default_value' => !is_null($node->default_qty) ? $node->default_qty : 1,
623 '#description' => t('Leave blank or zero to disable the quantity field in the add to cart form.'),
624 '#weight' => 27,
625 '#size' => 5,
626 '#maxlength' => 6,
627 );
628 $form['base']['ordering'] = array('#type' => 'weight',
629 '#title' => t('List position'),
630 '#description' => t("Specify a value to set this product's position in product lists.<br />Products in the same position will be sorted alphabetically."),
631 '#delta' => 25,
632 '#default_value' => isset($node->ordering) ? $node->ordering : 0,
633 '#weight' => 30,
634 );
635
636 return $form;
637 }
638
639 /**
640 * @ingroup themeable
641 */
642 function theme_uc_product_form_prices($form) {
643 return "<table><tr><td>\n". drupal_render($form['list_price'])
644 .'</td><td>'. drupal_render($form['cost'])
645 .'</td><td>'. drupal_render($form['sell_price'])
646 ."</td></tr></table>\n";
647 }
648
649 /**
650 * @ingroup themeable
651 */
652 function theme_uc_product_form_weight($form) {
653 return '<table><tr><td>'. drupal_render($form['weight']) .'</td><td>'
654 . drupal_render($form['weight_units']) .'</td></tr></table>';
655 }
656
657 /**
658 * Put length, width, and height fields on the same line.
659 *
660 * @ingroup themeable
661 */
662 function theme_uc_product_dimensions_form($form) {
663 $output = '';
664 $row = array();
665 foreach (element_children($form) as $dimension) {
666 $row[] = drupal_render($form[$dimension]);
667 }
668 $output .= theme('table', array(), array($row));
669 return $output;
670 }
671
672 function uc_product_validate($node) {
673 $pattern = '/^\d*(\.\d*)?$/';
674 $price_error = t('Price must be in a valid number format. No commas and only one decimal point.');
675 if (!empty($node->list_price) && !is_numeric($node->list_price) && !preg_match($pattern, $node->list_price)) {
676 form_set_error('list_price', $price_error);
677 }
678 if (!empty($node->cost) && !is_numeric($node->cost) && !preg_match($pattern, $node->cost)) {
679 form_set_error('cost', $price_error);
680 }
681 if (!is_numeric($node->sell_price) && !preg_match($pattern, $node->sell_price)) {
682 form_set_error('sell_price', $price_error);
683 }
684 if (!empty($node->weight) && !is_numeric($node->weight)) {
685 form_set_error('weight', t('Weight must be in a valid number format. No commas and only one decimal point.'));
686 }
687 if ($node->default_qty) {
688 if (!is_numeric($node->default_qty)) {
689 form_set_error('default_qty', t('Quantities should be numeric.'));
690 }
691 else if ($node->default_qty < 0) {
692 form_set_error('default_qty', t("Adding negative items to the cart doesn't make sense, so don't make it easy."));
693 }
694 }
695 }
696
697 /**
698 * Implementation of hook_insert().
699 */
700 function uc_product_insert($node) {
701 if (!isset($node->unique_hash)) {
702 $node->unique_hash = md5($node->vid . $node->nid . $node->model . $node->list_price . $node->cost . $node->sell_price . $node->weight . $node->weight_units . $node->length . $node->width . $node->height . $node->length_units . $node->pkg_qty . $node->default_qty . $node->shippable . time());
703 }
704 db_query("INSERT INTO {uc_products} (vid, nid, model, list_price, cost, sell_price, weight, weight_units, length, width, height, length_units, pkg_qty, default_qty, unique_hash, ordering, shippable) VALUES (%d, %d, '%s', %f, %f, %f, %f, '%s', %f, %f, %f, '%s', %d, %d, '%s', %d, %d)",
705 $node->vid, $node->nid, $node->model, $node->list_price, $node->cost, $node->sell_price, $node->weight, $node->weight_units, $node->length, $node->width, $node->height, $node->length_units, $node->pkg_qty, $node->default_qty, $node->unique_hash, $node->ordering, $node->shippable
706 );
707 }
708
709 /**
710 * Implementation of hook_update().
711 */
712 function uc_product_update($node) {
713 if ($node->revision) {
714 db_query("INSERT INTO {uc_products} (vid, nid, model, list_price, cost, sell_price, weight, weight_units, length, width, height, length_units, pkg_qty, default_qty, unique_hash, ordering, shippable) VALUES (%d, %d, '%s', %f, %f, %f, %f, '%s', %f, %f, %f, '%s', %d, %d, '%s', %d, %d)",
715 $node->vid, $node->nid, $node->model, $node->list_price, $node->cost, $node->sell_price, $node->weight, $node->weight_units, $node->length, $node->width, $node->height, $node->length_units, $node->pkg_qty, $node->default_qty, $node->unique_hash, $node->ordering, $node->shippable
716 );
717 }
718 else {
719 //drupal_set_message('<pre>'. print_r($node, true) .'</pre>');drupal_set_message('<pre>'. print_r($node, true) .'</pre>');
720 db_query("UPDATE {uc_products} SET model = '%s', list_price = %f, cost = %f, sell_price = %f, weight = %f, weight_units = '%s', length = %f, width = %f, height = %f, length_units = '%s', pkg_qty = %d, default_qty = %d, ordering = %d, shippable = %d WHERE vid = %d",
721 $node->model, $node->list_price, $node->cost, $node->sell_price, $node->weight, $node->weight_units, $node->length, $node->width, $node->height, $node->length_units, $node->pkg_qty, $node->default_qty, $node->ordering, $node->shippable, $node->vid);
722 }
723 }
724
725 /**
726 * Implementation of hook_load().
727 */
728 function uc_product_load(&$node) {
729 return db_fetch_object(db_query('SELECT model, list_price, cost, sell_price, weight, weight_units, length, width, height, length_units, pkg_qty, default_qty, unique_hash, ordering, shippable FROM {uc_products} WHERE vid = %d', $node->vid));
730 }
731
732 /**
733 * Implementation of hook_delete().
734 */
735 function uc_product_delete(&$node) {
736 db_query("DELETE from {uc_products} WHERE nid = %d", $node->nid);
737 }
738
739 /**
740 * Implementation of hook_view().
741 */
742 function uc_product_view($node, $teaser = 0, $page = 0) {
743 $node = node_prepare($node, $teaser);
744
745 $enabled = variable_get('uc_product_field_enabled', array(
746 'image' => 1,
747 'display_price' => 1,
748 'model' => 1,
749 'list_price' => 0,
750 'cost' => 0,
751 'sell_price' => 1,
752 'weight' => 0,
753 'dimensions' => 0,
754 'add_to_cart' => 1,
755 ));
756 $weight = variable_get('uc_product_field_weight', array(
757 'image' => -2,
758 'display_price' => -1,
759 'model' => 0,
760 'list_price' => 2,
761 'cost' => 3,
762 'sell_price' => 4,
763 'weight' => 5,
764 'dimensions' => 6,
765 'add_to_cart' => 10,
766 ));
767
768 //drupal_set_message('<pre>'. print_r($node->field_image_cache, true) .'</pre>');
769 if (isset($node->field_image_cache) && file_exists($node->field_image_cache[0]['filepath'])) {
770 $node->content['image'] = array('#value' => theme('uc_product_image', $node->field_image_cache),
771 '#access' => $enabled['image'] && module_exists('imagecache'),
772 '#weight' => $weight['image'],
773 );
774 }
775 $node->content['display_price'] = array('#value' => theme('uc_product_display_price', $node->sell_price),
776 '#access' => $enabled['display_price'],
777 '#weight' => $weight['display_price'],
778 );
779 if (!$teaser) {
780 $node->content['model'] = array('#value' => theme('uc_product_model', $node->model),
781 '#access' => $enabled['model'],
782 '#weight' => $weight['model'],
783 );
784 $node->content['body']['#weight'] = 1;
785 $node->content['list_price'] = array('#value' => theme('uc_product_price', $node->list_price, 'list_price'),
786 '#access' => $enabled['list_price'],
787 '#weight' => $weight['list_price'],
788 );
789 $node->content['cost'] = array('#value' => theme('uc_product_price', $node->cost, 'cost'),
790 '#access' => $enabled['cost'] && user_access('administer products'),
791 '#weight' => $weight['cost'],
792 );
793 }
794 else {
795 $node->content['#attributes'] = array('style' => 'display: inline');
796 }
797
798 $node->content['sell_price'] = array('#value' => theme('uc_product_sell_price', $node->sell_price, $teaser),
799 '#access' => $enabled['sell_price'],
800 '#weight' => $weight['sell_price'],
801 );
802
803 if (!$teaser) {
804 $node->content['weight'] = array('#value' => theme('uc_product_weight', $node->weight, $node->weight_units),
805 '#access' => $enabled['weight'],
806 '#weight' => $weight['weight'],
807 );
808 $node->content['dimensions'] = array('#value' => theme('uc_product_dimensions', $node->length, $node->width, $node->height, $node->length_units),
809 '#access' => $enabled['dimensions'],
810 '#weight' => $weight['dimensions'],
811 );
812 if (module_exists('uc_cart')) {
813 $node->content['add_to_cart'] = array('#value' => theme('uc_product_add_to_cart', $node),
814 '#access' => $enabled['add_to_cart'],
815 '#weight' => $weight['add_to_cart'],
816 );
817 }
818 }
819 else if (module_exists('uc_cart') && variable_get('uc_product_add_to_cart_teaser', true)) {
820 $node->content['add_to_cart'] = array('#value' => theme('uc_product_add_to_cart', $node),
821 '#access' => $enabled['add_to_cart'],
822 '#weight' => $weight['add_to_cart'],
823 );
824 }
825 //drupal_set_message('<pre>'. print_r($breadcrumb, true) .'</pre>');
826 return $node;
827 }
828
829 function uc_product_form_alter(&$form, &$form_state, $form_id) {
830 if ($form_id == 'search_form' && arg(0) == 'admin' && arg(1) == 'store' && arg(2) == 'products' && user_access('use advanced search')) {
831 // Keyword boxes:
832 $form['advanced'] = array(
833 '#type' => 'fieldset',
834 '#title' => t('Advanced search'),
835 '#collapsible' => TRUE,
836 '#collapsed' => TRUE,
837 '#attributes' => array('class' => 'search-advanced'),
838 );
839 $form['advanced']['keywords'] = array(
840 '#prefix' => '<div class="criterion">',
841 '#suffix' => '</div>',
842 );
843 $form['advanced']['keywords']['or'] = array(
844 '#type' => 'textfield',
845 '#title' => t('Containing any of the words'),
846 '#size' => 30,
847 '#maxlength' => 255,
848 );
849 $form['advanced']['keywords']['phrase'] = array(
850 '#type' => 'textfield',
851 '#title' => t('Containing the phrase'),
852 '#size' => 30,
853 '#maxlength' => 255,
854 );
855 $form['advanced']['keywords']['negative'] = array(
856 '#type' => 'textfield',
857 '#title' => t('Containing none of the words'),
858 '#size' => 30,
859 '#maxlength' => 255,
860 );
861
862 // Taxonomy box:
863 if ($taxonomy = module_invoke('taxonomy', 'form_all', 1)) {
864 $form['advanced']['category'] = array(
865 '#type' => 'select',
866 '#title' => t('Only in the category(s)'),
867 '#prefix' => '<div class="criterion">',
868 '#size' => 10,
869 '#suffix' => '</div>',
870 '#options' => $taxonomy,
871 '#multiple' => TRUE,
872 );
873 }
874
875 // Node types:
876 $types = array();
877 $product_types = module_invoke_all('product_types');
878 $node_types = module_invoke_all('node_info');
879 foreach ($product_types as $id) {
880 $types[$id] = $node_types[$id]['name'];
881 }
882 $form['advanced']['type'] = array(
883 '#type' => 'checkboxes',
884 '#title' => t('Only of the type(s)'),
885 '#prefix' => '<div class="criterion">',
886 '#suffix' => '</div>',
887 '#options' => $types,
888 );
889 $form['advanced']['submit'] = array(
890 '#type' => 'submit',
891 '#value' => t('Advanced search'),
892 '#prefix' => '<div class="action clear-block">',
893 '#suffix' => '</div>',
894 );
895
896 $form['#validate'][] = 'node_search_validate';
897 }
898 }
899
900 /******************************************************************************
901 * TAPIr Hooks *
902 ******************************************************************************/
903
904 /**
905 * Define up the product list table.
906 *
907 * @see uc_product_table
908 */
909 function uc_product_table_settings() {
910 $tables = array();
911
912 $tables[] = array(
913 'id' => 'uc_product_table',
914 'description' => t('Lists a group of products in an abbreviated format.'),
915 'path' => 'admin/store/settings/tables',
916 'access' => 'administer store',
917 'preview' => FALSE,
918 );
919
920 return $tables;
921 }
922
923 function uc_product_table_header() {
924 $columns = array();
925
926 if (module_exists('imagecache')) {
927 $columns[] = array(
928 'id' => 'image',
929 'weight' => -5,
930 'cell' => array('data' => t('Image')),
931 );
932 }
933 $columns[] = array(
934 'id' => 'name',
935 'weight' => 0,
936 'cell' => array('data' => t('Name'), 'field' => 'n.title'),
937 );
938 $columns[] = array(
939 'id' => 'list_price',
940 'weight' => 3,
941 'cell' => array('data' => t('List price'), 'field' => 'p.list_price'),
942 );
943 $columns[] = array(
944 'id' => 'price',
945 'weight' => 5,
946 'cell' => array('data' => t('Price'), 'field' => 'p.sell_price'),
947 );
948 if (module_exists('uc_cart') && (arg(0) != 'admin' || $_GET['q'] == 'admin/store/settings/tables/uc_product_table')) {
949 $columns[] = array(
950 'id' => 'add_to_cart',
951 'weight' => 10,
952 'cell' => array('data' => t('Add to cart'), 'nowrap' => 'nowrap'),
953 );
954 }
955
956 return $columns;
957 }
958
959 /**
960 * Display product fields in a TAPIr table.
961 *
962 * Display image, name, price, and add to cart form.
963 */
964 function uc_product_table($form_state, $args = array()) {
965 $table = array();
966
967 $table['columns'] = uc_product_table_header();
968
969 foreach ($args['nids'] as $nid) {
970 $data = array();
971 $node = node_load($nid);
972 if ($node->type != 'image') {
973 if (module_exists('imagecache') && isset($node->field_image_cache) && file_exists($node->field_image_cache[0]['filepath'])) {
974 $data['image'] = array('cell' => l(theme('imagecache', 'product_list', $node->field_image_cache[0]['filepath'], $node->field_image_cache[0]['alt'], $node->field_image_cache[0]['title']), 'node/'. $node->nid, array('html' => TRUE)));
975 }
976 else {
977 $data['image'] = array('cell' => t('n/a'));
978 }
979 $data['name'] = array('value' => $node->title, 'cell' => array('data' => l($node->title, 'node/'. $node->nid), 'width' => '100%'));
980 $data['list_price'] = array('value' => $node->list_price, 'cell' => array('data' => theme('uc_product_price', $node->list_price, 'list_price'), 'nowrap' => 'nowrap'));
981 $data['price'] = array('value' => $node->sell_price, 'cell' => array('data' => theme('uc_product_sell_price', $node->sell_price, true), 'nowrap' => 'nowrap'));
982 if (module_exists('uc_cart') && arg(0) != 'admin') {
983 $data['add_to_cart'] = array('cell' => drupal_get_form('uc_catalog_buy_it_now_form_'. $node->nid, $node));
984 }
985 $table['rows'][] = $data;
986 }
987 }
988
989 $form['table'] = array(
990 '#value' => $table,
991 '#theme' => 'tapir_table',
992 '#attributes' => array(
993 'class' => 'category-products',
994 ),
995 );
996
997 return $form;
998 }
999
1000 /**
1001 * @ingroup forms
1002 * @see uc_product_forms
1003 * @see uc_catalog_buy_it_now_form_submit
1004 */
1005 function uc_catalog_buy_it_now_form($form_state, $node) {
1006 $form = array();
1007 $form['#validate'][] = 'uc_catalog_buy_it_now_form_validate';
1008 $form['#submit'][] = 'uc_catalog_buy_it_now_form_submit';
1009 $form['nid'] = array('#type' => 'hidden', '#value' => $node->nid);
1010 $form['submit'] = array(
1011 '#type' => 'submit',
1012 '#value' => variable_get('uc_teaser_add_to_cart_text', t('Add to cart')),
1013 '#id' => 'edit-submit-'. $node->nid,
1014 '#attributes' => array(
1015 'class' => 'list-add-to-cart',
1016 ),
1017 );
1018 return $form;
1019 }
1020
1021 function uc_catalog_buy_it_now_form_validate($form, &$form_state) {
1022 $node = node_load($form_state['values']['nid']);
1023 if (module_exists('uc_attribute')) {
1024 $attributes = uc_product_get_attributes($node->nid);
1025 if (!empty($attributes)) {
1026 drupal_set_message(t('This product has options that need to be selected before purchase. Please select them in the form below.'), 'error');
1027 drupal_goto('node/'. $form_state['values']['nid']);
1028 }
1029 if (is_array($node->products)) {
1030 foreach ($node->products as $nid => $product) {
1031 $attributes = uc_product_get_attributes($nid);
1032 if (!empty($attributes)) {
1033 drupal_set_message(t('This product has options that need to be selected before purchase. Please select them in the form below.'), 'error');
1034 drupal_goto('node/'. $form_state['values']['nid']);
1035 }
1036 }
1037 }