uc_cart.api.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. <?php
  2. /**
  3. * @file
  4. * Hooks provided by the Cart module.
  5. */
  6. /**
  7. * @addtogroup hooks
  8. * @{
  9. */
  10. /**
  11. * Performs extra processing when an item is added to the shopping cart.
  12. *
  13. * Some modules need to be able to hook into the process of adding items to a
  14. * cart. For example, an inventory system may need to check stock levels and
  15. * prevent an out of stock item from being added to a customer's cart. This hook
  16. * lets developers squeeze right in at the end of the process after the product
  17. * information is all loaded and the product is about to be added to the cart.
  18. * In the event that a product should not be added to the cart, you simply have
  19. * to return a failure message described below. This hook may also be used
  20. * simply to perform some routine action when products are added to the cart.
  21. *
  22. * @param $nid
  23. * The node ID of the product.
  24. * @param $qty
  25. * The quantity being added.
  26. * @param $data
  27. * The data array, including attributes and model number adjustments.
  28. *
  29. * @return
  30. * The function can use this data to whatever purpose to see if the item
  31. * can be added to the cart or not. The function should return an array
  32. * containing the result array. (This is due to the nature of Drupal's
  33. * module_invoke_all() function. You must return an array within an array
  34. * or other module data will end up getting ignored.) At this moment,
  35. * there are only three keys:
  36. * - success: TRUE or FALSE for whether the specified quantity of the item
  37. * may be added to the cart or not; defaults to TRUE.
  38. * - message: The fail message to display in the event of a failure; if
  39. * omitted, Ubercart will display a default fail message.
  40. * - silent: Return TRUE to suppress the display of any messages; useful
  41. * when a module simply needs to do some other processing during an add
  42. * to cart or fail silently.
  43. */
  44. function hook_uc_add_to_cart($nid, $qty, $data) {
  45. if ($qty > 1) {
  46. $result[] = array(
  47. 'success' => FALSE,
  48. 'message' => t('Sorry, you can only add one of those at a time.'),
  49. );
  50. }
  51. return $result;
  52. }
  53. /**
  54. * Adds extra information to a cart item's "data" array.
  55. *
  56. * This is effectively the submit handler of any alterations to the Add to Cart
  57. * form. It provides a standard way to store the extra information so that it
  58. * can be used by hook_uc_add_to_cart().
  59. *
  60. * @param $form_values
  61. * The values submitted to the Add to Cart form.
  62. *
  63. * @return
  64. * An array of data to be merged into the item added to the cart.
  65. */
  66. function hook_uc_add_to_cart_data($form_values) {
  67. $node = node_load($form_values['nid']);
  68. return array('module' => 'uc_product', 'shippable' => $node->shippable);
  69. }
  70. /**
  71. * Controls the display of an item in the cart.
  72. *
  73. * Product type modules allow the creation of nodes that can be added to the
  74. * cart. The cart determines how they are displayed through this hook. This is
  75. * especially important for product kits, because it may be displayed as a
  76. * single unit in the cart even though it is represented as several items.
  77. *
  78. * This hook is only called for the module that owns the cart item in
  79. * question, as set in $item->module.
  80. *
  81. * @param $item
  82. * The item in the cart to display.
  83. *
  84. * @return
  85. * A form array containing the following elements:
  86. * - "nid"
  87. * - #type: value
  88. * - #value: The node id of the $item.
  89. * - "module"
  90. * - #type: value
  91. * - #value: The module implementing this hook and the node represented by
  92. * $item.
  93. * - "remove"
  94. * - #type: submit
  95. * - #value: t('Remove'); when clicked, will remove $item from the cart.
  96. * - "description"
  97. * - #type: markup
  98. * - #value: Themed markup (usually an unordered list) displaying extra
  99. * information.
  100. * - "title"
  101. * - #type: markup
  102. * - #value: The displayed title of the $item.
  103. * - "#total"
  104. * - type: float
  105. * - value: Numeric price of $item. Notice the '#' signifying that this is
  106. * not a form element but just a value stored in the form array.
  107. * - "data"
  108. * - #type: hidden
  109. * - #value: The serialized $item->data.
  110. * - "qty"
  111. * - #type: textfield
  112. * - #value: The quantity of $item in the cart. When "Update cart" is
  113. * clicked, the customer's input is saved to the cart.
  114. */
  115. function hook_uc_cart_display($item) {
  116. $node = node_load($item->nid);
  117. $element = array();
  118. $element['nid'] = array('#type' => 'value', '#value' => $node->nid);
  119. $element['module'] = array('#type' => 'value', '#value' => 'uc_product');
  120. $element['remove'] = array('#type' => 'checkbox');
  121. $element['title'] = array(
  122. '#markup' => node_access('view', $node) ? l($item->title, 'node/' . $node->nid) : check_plain($item->title),
  123. );
  124. $element['#total'] = $item->price * $item->qty;
  125. $element['data'] = array('#type' => 'hidden', '#value' => serialize($item->data));
  126. $element['qty'] = array(
  127. '#type' => 'textfield',
  128. '#default_value' => $item->qty,
  129. '#size' => 5,
  130. '#maxlength' => 6,
  131. );
  132. if ($description = uc_product_get_description($item)) {
  133. $element['description'] = array('#markup' => $description);
  134. }
  135. return $element;
  136. }
  137. /**
  138. * Act on a cart item before it is about to be created or updated.
  139. *
  140. * @param $entity
  141. * The cart item entity object.
  142. */
  143. function hook_uc_cart_item_presave($entity) {
  144. $entity->changed = REQUEST_TIME;
  145. }
  146. /**
  147. * Act on cart item entities when inserted.
  148. *
  149. * @param $entity
  150. * The cart item entity object.
  151. */
  152. function hook_uc_cart_item_insert($entity) {
  153. drupal_set_message(t('An item was added to your cart'));
  154. }
  155. /**
  156. * Act on cart item entities when updated.
  157. *
  158. * @param $entity
  159. * The cart item entity object.
  160. */
  161. function hook_uc_cart_item_update($entity) {
  162. drupal_set_message(t('An item was updated in your cart'));
  163. }
  164. /**
  165. * Act on cart item entities when deleted.
  166. *
  167. * @param $entity
  168. * The cart item entity object.
  169. */
  170. function hook_uc_cart_item_delete($entity) {
  171. drupal_set_message(t('An item was deleted from your cart'));
  172. }
  173. /**
  174. * Registers callbacks for a cart pane.
  175. *
  176. * The default cart view page displays a table of the cart contents and a few
  177. * simple form features to manage the cart contents. For a module to add
  178. * information to this page, it must use hook_uc_cart_pane() to define extra
  179. * panes that may be ordered to appear above or below the default information.
  180. *
  181. * @param $items
  182. * The current contents of the shopping cart.
  183. *
  184. * @return
  185. * The function is expected to return an array of pane arrays, keyed by the
  186. * internal ID of the pane, each with the following members:
  187. * - "title"
  188. * - type: string
  189. * - value: The name of the cart pane displayed to the user. Use t().
  190. * - "enabled"
  191. * - type: boolean
  192. * - value: Whether the pane is enabled by default or not.
  193. * (Defaults to TRUE.)
  194. * - "weight"
  195. * - type: integer
  196. * - value: The weight of the pane to determine its display order.
  197. * (Defaults to 0.)
  198. * - "body"
  199. * - type: array
  200. * - value: The body of the pane to be rendered on the cart view screen.
  201. *
  202. * The body gets printed to the screen if it is on the cart view page. For the
  203. * settings page, the body field is ignored. You may want your function to
  204. * check for a NULL argument before processing any queries or foreach() loops.
  205. */
  206. function hook_uc_cart_pane($items) {
  207. $body = array();
  208. if (!is_null($items)) {
  209. $body = drupal_get_form('uc_cart_view_form', $items) + array(
  210. '#prefix' => '<div id="cart-form-pane">',
  211. '#suffix' => '</div>',
  212. );
  213. }
  214. $panes['cart_form'] = array(
  215. 'title' => t('Default cart form'),
  216. 'enabled' => TRUE,
  217. 'weight' => 0,
  218. 'body' => $body,
  219. );
  220. return $panes;
  221. }
  222. /**
  223. * Alters cart pane definitions.
  224. *
  225. * @param $panes
  226. * The array of pane information in the format defined in hook_uc_cart_pane(),
  227. * passed by reference.
  228. * @param $items
  229. * The array of item information.
  230. */
  231. function hook_uc_cart_pane_alter(&$panes, $items) {
  232. $panes['cart_form']['body'] = drupal_get_form('my_custom_pane_form_builder', $items);
  233. }
  234. /**
  235. * Takes action when checkout is completed.
  236. *
  237. * @param $order
  238. * The resulting order object from the completed checkout.
  239. * @param $account
  240. * The customer that completed checkout, either the current user, or the
  241. * account created for an anonymous customer.
  242. */
  243. function hook_uc_checkout_complete($order, $account) {
  244. // Get previous records of customer purchases.
  245. $nids = array();
  246. $result = db_query("SELECT uid, nid, qty FROM {uc_customer_purchases} WHERE uid = :uid", array(':uid' => $account->uid));
  247. foreach ($result as $record) {
  248. $nids[$record->nid] = $record->qty;
  249. }
  250. // Update records with new data.
  251. $record = array('uid' => $account->uid);
  252. foreach ($order->products as $product) {
  253. $record['nid'] = $product->nid;
  254. if (isset($nids[$product->nid])) {
  255. $record['qty'] = $nids[$product->nid] + $product->qty;
  256. db_write_record($record, 'uc_customer_purchases', array('uid', 'nid'));
  257. }
  258. else {
  259. $record['qty'] = $product->qty;
  260. db_write_record($record, 'uc_customer_purchases');
  261. }
  262. }
  263. }
  264. /**
  265. * Takes action immediately before bringing up the checkout page.
  266. *
  267. * Use drupal_goto() in the hook implementation to abort checkout and
  268. * enforce restrictions on the order.
  269. *
  270. * @param $order
  271. * The order object to check out.
  272. */
  273. function hook_uc_cart_checkout_start($order) {
  274. $account = user_load($order->uid);
  275. if (is_array($account->roles) && in_array('administrator', $account->roles)) {
  276. drupal_set_message(t('Administrators may not purchase products.', 'error'));
  277. drupal_goto('cart');
  278. }
  279. }
  280. /**
  281. * Registers callbacks for a checkout pane.
  282. *
  283. * The checkout screen for Ubercart is a compilation of enabled checkout panes.
  284. * A checkout pane can be used to display order information, collect data from
  285. * the customer, or interact with other panes. Panes are defined in enabled
  286. * modules with hook_uc_checkout_pane() and displayed and processed through
  287. * specified callback functions. Some of the settings for each pane are
  288. * configurable from the checkout settings page with defaults being specified
  289. * in the hooks.
  290. *
  291. * The default panes are defined in uc_cart.module in the function
  292. * uc_cart_checkout_pane(). These include panes to display the contents of the
  293. * shopping cart and to collect essential site user information, a shipping
  294. * address, a payment address, and order comments. Other included modules offer
  295. * panes for shipping and payment purposes as well.
  296. *
  297. * @return
  298. * An array of checkout pane arrays, keyed by the internal ID of the pane,
  299. * each with the following members:
  300. * - title:
  301. * - type: string
  302. * - value: The name of the pane as it appears on the checkout form.
  303. * - desc:
  304. * - type: string
  305. * - value: A short description of the pane for the admin pages.
  306. * - callback:
  307. * - type: string
  308. * - value: The name of the callback function for this pane.
  309. * - weight:
  310. * - type: integer
  311. * - value: Default weight of the pane, defining its order on the checkout
  312. * form.
  313. * - enabled:
  314. * - type: boolean
  315. * - value: Optional. Whether or not the pane is enabled by default.
  316. * Defaults to TRUE.
  317. * - process:
  318. * - type: boolean
  319. * - value: Optional. Whether or not this pane needs to be processed when
  320. * the checkout form is submitted. Defaults to TRUE.
  321. * - collapsible:
  322. * - type: boolean
  323. * - value: Optional. Whether or not this pane is displayed as a collapsible
  324. * fieldset. Defaults to TRUE.
  325. * - shippable:
  326. * - type: boolean
  327. * - value: Optional. If TRUE, the pane is only shown if the cart is
  328. * shippable. Defaults to NULL.
  329. *
  330. * @see http://www.ubercart.org/docs/developer/245/checkout
  331. */
  332. function hook_uc_checkout_pane() {
  333. $panes['cart'] = array(
  334. 'callback' => 'uc_checkout_pane_cart',
  335. 'title' => t('Cart contents'),
  336. 'desc' => t("Display the contents of a customer's shopping cart."),
  337. 'weight' => 1,
  338. 'process' => FALSE,
  339. 'collapsible' => FALSE,
  340. );
  341. return $panes;
  342. }
  343. /**
  344. * Builds and proceses a pane defined by hook_uc_checkout_pane().
  345. *
  346. * @param $op
  347. * The operation the pane is performing. Possible values are "view",
  348. * "process", "review", and "settings".
  349. * @param $order
  350. * The order being viewed or edited.
  351. * @param $form
  352. * The order's edit form. NULL for non-edit ops.
  353. * @param &$form_state
  354. * The form state array of the edit form. NULL for non-edit ops.
  355. *
  356. * @return
  357. * Varies according to the value of $op:
  358. * - view: An array with two keys, "contents" and an optional "description".
  359. * "contents" is a form array to collect the checkout data for the pane. The
  360. * description provides help text for the pane as a whole.
  361. * - process: A boolean indicating that checkout should continue. During this
  362. * op, $order should be modified with the values in
  363. * $form_state['values']['panes'][PANE_ID].
  364. * - review: An array containing review sections. A review section contains
  365. * "title" and "data" keys which have HTML to be displayed on the checkout
  366. * review page.
  367. * - settings: A settings form which can be used with system_settings_form().
  368. */
  369. function uc_checkout_pane_callback($op, $order, $form = NULL, &$form_state = NULL) {
  370. // uc_checkout_pane_comments()
  371. switch ($op) {
  372. case 'view':
  373. $description = t('Use this area for special instructions or questions regarding your order.');
  374. if (!empty($order->order_id)) {
  375. $default = db_query("SELECT message FROM {uc_order_comments} WHERE order_id = :id", array(':id' => $order->order_id))->fetchField();
  376. }
  377. else {
  378. $default = NULL;
  379. }
  380. $contents['comments'] = array(
  381. '#type' => 'textarea',
  382. '#title' => t('Order comments'),
  383. '#default_value' => $default,
  384. );
  385. return array('description' => $description, 'contents' => $contents);
  386. case 'process':
  387. if ($form_state['values']['panes']['comments']['comments']) {
  388. db_delete('uc_order_comments')
  389. ->condition('order_id', $order->order_id)
  390. ->execute();
  391. uc_order_comment_save($order->order_id, 0, $form_state['values']['panes']['comments']['comments'], 'order', uc_order_state_default('post_checkout'), TRUE);
  392. }
  393. return TRUE;
  394. case 'review':
  395. $review = NULL;
  396. $result = db_query("SELECT message FROM {uc_order_comments} WHERE order_id = :id", array(':id' => $order->order_id));
  397. if ($comment = $result->fetchObject()) {
  398. $review[] = array('title' => t('Comment'), 'data' => check_plain($comment->message));
  399. }
  400. return $review;
  401. }
  402. }
  403. /**
  404. * Alters checkout pane definitions.
  405. *
  406. * @param $panes
  407. * Array with the panes information as defined in hook_uc_checkout_pane(),
  408. * passed by reference.
  409. */
  410. function hook_uc_checkout_pane_alter(&$panes) {
  411. $panes['cart']['callback'] = 'my_custom_module_callback';
  412. }
  413. /**
  414. * Handles requests to update a cart item.
  415. *
  416. * @param $nid
  417. * Node id of the cart item.
  418. * @param $data
  419. * Array of extra information about the item.
  420. * @param $qty
  421. * The quantity of this item in the cart.
  422. * @param $cid
  423. * The cart id. Defaults to NULL, which indicates that the current user's cart
  424. * should be retrieved with uc_cart_get_id().
  425. */
  426. function hook_uc_update_cart_item($nid, $data = array(), $qty, $cid = NULL) {
  427. if (!$nid) return NULL;
  428. $cid = !(is_null($cid) || empty($cid)) ? $cid : uc_cart_get_id();
  429. if ($qty < 1) {
  430. uc_cart_remove_item($nid, $cid, $data);
  431. }
  432. else {
  433. db_update('uc_cart_products')
  434. ->fields(array(
  435. 'qty' => $qty,
  436. 'changed' => REQUEST_TIME,
  437. ))
  438. ->condition('nid', $nid)
  439. ->condition('cart_id', $cid)
  440. ->condition('data', serialize($data))
  441. ->execute();
  442. }
  443. // Rebuild the items hash
  444. uc_cart_get_contents(NULL, 'rebuild');
  445. if (!strpos(request_uri(), 'cart', -4)) {
  446. drupal_set_message(t('Your item(s) have been updated.'));
  447. }
  448. }
  449. /**
  450. * @} End of "addtogroup hooks".
  451. */