commerce_userpoints_discount.module in Commerce userpoints 7
The module core functions
Implementation of all the functions calling different hooks on userpoints and commerce module
File
commerce_userpoints_discount/commerce_userpoints_discount.moduleView source
<?php
/**
* @file
* The module core functions
*
* Implementation of all the functions calling different hooks on userpoints
* and commerce module
*/
/**
* Implements hook_menu().
*/
function commerce_userpoints_discount_menu() {
$items = array();
$items['admin/commerce/config/commerce-userpoints'] = array(
'title' => 'Commerce discount settings',
'description' => 'Configure settings for commerce userpoints.',
'position' => 'left',
'weight' => 50,
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array(
'access administration pages',
),
'file path' => drupal_get_path('module', 'system'),
'file' => 'system.admin.inc',
);
$items['admin/commerce/config/commerce-userpoints/discount'] = array(
'title' => 'Commerce userpoints discount settings',
'description' => 'Configure the commerce userpoints module',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'commerce_userpoints_discount_settings_form',
),
'access arguments' => array(
'configure store',
),
'file' => 'commerce_userpoints_discount.admin.inc',
);
$items['commerce_userpoints_discount/ajax/useall/%commerce_order/%commerce_currency'] = array(
'page callback' => 'commerce_userpoints_discount_use_credit_callback_all',
'page arguments' => array(
1,
3,
4,
),
'access callback' => TRUE,
// TODO: limit access properly.
'type' => MENU_CALLBACK,
'delivery callback' => 'ajax_deliver',
);
$items['commerce_userpoints_discount/ajax/removeall/%commerce_order/%commerce_currency'] = array(
'page callback' => 'commerce_userpoints_discount_remove_credit_callback',
'page arguments' => array(
1,
3,
4,
),
'access callback' => TRUE,
// TODO: limit access properly.
'type' => MENU_CALLBACK,
'delivery callback' => 'ajax_deliver',
);
return $items;
}
/**
* Implements hook_views_api().
*/
function commerce_userpoints_discount_views_api() {
return array(
'api' => 3,
'path' => drupal_get_path('module', 'commerce_userpoints_discount') . '/includes/views',
);
}
/**
* Implements hook_commerce_checkout_pane_info().
*/
function commerce_userpoints_discount_commerce_checkout_pane_info() {
$checkout_panes = array();
$checkout_panes['commerce_userpoints_discount'] = array(
'title' => t('!Points discount', userpoints_translation()),
'page' => 'checkout',
'locked' => TRUE,
'file' => 'includes/commerce_userpoints_discount.checkout_pane.inc',
'base' => 'commerce_userpoints_discount_pane',
'weight' => 10,
);
return $checkout_panes;
}
/**
* Implements hook_commerce_line_item_type_info().
*/
function commerce_userpoints_discount_commerce_line_item_type_info() {
$line_item_types['userpoints'] = array(
'type' => 'userpoints',
'name' => t('!Points', userpoints_translation()),
'description' => t('!Points value line item.', userpoints_translation()),
'add_form_submit_value' => t('Use !points', userpoints_translation()),
'base' => 'commerce_userpoints_discount_line_item',
'callbacks' => array(
'configuration' => 'commerce_userpoints_discount_configure_line_item',
),
);
return $line_item_types;
}
/**
* This function is called by the line item module when it is enabled or this
* module is enabled.
*/
function commerce_userpoints_discount_configure_line_item() {
$entity_type = 'commerce_line_item';
$bundle = 'userpoints';
$field_name = 'commerce_userpoints_discount_txn';
$field = field_info_field($field_name);
$instance = field_info_instance($entity_type, $field_name, $bundle);
if (empty($field)) {
$field = array(
'field_name' => $field_name,
'type' => 'text',
'cardinality' => 1,
'entity_types' => array(
$entity_type,
),
'translatable' => FALSE,
'locked' => TRUE,
'settings' => array(),
);
field_create_field($field);
}
if (empty($instance)) {
$instance = array(
'field_name' => $field_name,
'entity_type' => $entity_type,
'bundle' => $bundle,
'label' => t('!Points transaction reference', userpoints_translation()),
'required' => FALSE,
'settings' => array(),
'display' => array(),
);
field_create_instance($instance);
}
}
/**
* Returns an appropriate title for this line item.
*/
function commerce_userpoints_discount_line_item_title($line_item) {
return t('Points');
}
/**
* Returns the elements necessary to add a product line item through a line item
* manager widget.
*/
function commerce_userpoints_discount_line_item_add_form($form_state) {
$form = array();
$form['amount'] = array(
'#type' => 'textfield',
'#title' => t('Amount'),
'#default_value' => 0,
'#size' => 10,
);
$form['current_points'] = array(
'#type' => 'item',
'#title' => t('User current !points', userpoints_translation()),
// TODO: Display the correct points value related to the order owner rather than the currently logged in user.
// Related to this issue http://drupal.org/node/1233790.
'#markup' => check_plain(userpoints_get_current_points(NULL, variable_get('commerce_userpoints_discount_default_termid'))),
);
$form['currency_code'] = array(
'#type' => 'select',
'#title' => t('Currency'),
'#options' => commerce_currency_code_options_list(),
'#default_value' => commerce_default_currency(),
);
return $form;
}
/**
* @param $line_item
* The newly created line item object.
* @param $element
* The array representing the widget form element.
* @param $form_state
* The present state of the form upon the latest submission.
* @param $form
* The actual form array.
*
* @return
* NULL if all is well or an error message if something goes wrong.
*/
function commerce_userpoints_discount_line_item_add_form_submit(&$line_item, $element, &$form_state, $form) {
$order = $form_state['commerce_order'];
if ($element['actions']['amount']['#value'] >= 0) {
form_set_error("amount", t("The amount should be less than 0"));
}
if ($element['actions']['amount']['#value'] > userpoints_get_current_points($order->uid, variable_get('commerce_userpoints_discount_default_termid'))) {
form_set_error("amount", t("The user doesn't have enough !points", userpoints_translation()));
}
$userpoints_params = array(
'points' => intval($element['actions']['amount']['#value']),
'uid' => $order->uid,
'operation' => 'commerce_userpoints_discount_credit',
'tid' => variable_get('commerce_userpoints_discount_default_termid', userpoints_get_default_tid()),
'display' => FALSE,
'entity_id' => $order->order_id,
'entity_type' => 'commerce_order',
);
$result = userpoints_userpointsapi($userpoints_params);
$label = "TXNID" . $result['transaction']['txn_id'];
commerce_userpoints_discount_line_item_populate($line_item, $order->order_id, $result['transaction'], $element['actions']['currency_code']['#value'], $label);
}
/**
* Implements hook_userpoints_info().
*/
function commerce_userpoints_discount_userpoints_info() {
return array(
'commerce_userpoints_discount_credit' => array(
'description' => t('Using credit for purchase'),
),
);
}
/**
* This function checks if an order already have a userpoint line_item type attached to it.
* @param $order_id
* Id of the order to check
*
* @return ...
* line_item_id if exists, or NULL if not
*/
function commerce_userpoints_discount_order_has_userpoint_line_item($order_id) {
$query = new EntityFieldQuery();
$result = $query
->entityCondition('entity_type', 'commerce_line_item', '=')
->entityCondition('bundle', 'userpoints', '=')
->propertyCondition('order_id', $order_id, '=')
->execute();
if (empty($result)) {
return NULL;
}
$line_item = array_shift($result['commerce_line_item']);
return $line_item->line_item_id;
}
/**
* Safely create or retrieve a userpoints line item from an order.
* Only one userpoints line item can be created for an order, if the order
* already have a userpoints line item, it will be returned.
* @param $order_id
* Id of the order to check
*
* @return ...
* The existing line item of the passed order id if it exists, or a
* new empty line item otherwise
*/
function commerce_userpoints_discount_line_item_factory_new($order_id) {
$line_item_id = commerce_userpoints_discount_order_has_userpoint_line_item($order_id);
if ($line_item_id == NULL) {
return _commerce_userpoints_discount_line_item_new();
}
return commerce_line_item_load($line_item_id);
}
/**
* Private shorthand function to create a userpoints line item.
* @return commerce_line_item
* Populated commerce_line_item of userpoints type, with default values
*/
function _commerce_userpoints_discount_line_item_new() {
// Create the new line item.
$line_item = entity_create('commerce_line_item', array(
'type' => 'userpoints',
'quantity' => 1,
));
return $line_item;
}
/**
* Helper function to populate a userpoints commerce_line_item.
* @param ... $line_item
* The commerce_line_item to populate. It can be either an array or object of
* entity_medatadata_wrapper
* @param int $order_id
* Order id the line item should be assigned to
* @param array $userpoints_txn
* Userpoints taxonomy term the line item should be populated with
* @param string $currency
* Currency code the line item should be populated with
* @param string $label
* Label the line item should be populated with
*
* @return object
* The populated line item
*/
function commerce_userpoints_discount_line_item_populate(&$line_item, $order_id, $userpoints_txn, $currency, $label) {
if (!$line_item instanceof EntityMetadataWrapper) {
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
}
$line_item_wrapper->order_id = $order_id;
$line_item_wrapper->commerce_userpoints_discount_txn = $userpoints_txn['txn_id'];
$line_item_wrapper->line_item_label = t($label);
$line_item_wrapper->commerce_unit_price->currency_code = $currency;
$line_item_wrapper->commerce_unit_price->amount = intval($userpoints_txn['points']) / variable_get('commerce_userpoints_discount_royalties_multiple', 1);
$line_item_wrapper->commerce_unit_price->data = commerce_price_component_add($line_item_wrapper->commerce_unit_price
->value(), 'userpoints', $line_item_wrapper->commerce_unit_price
->value(), TRUE, FALSE);
// Return the line item.
return $line_item_wrapper
->value();
}
/**
* Saves the line item in the database and add it to the appropriate order
* @param $line_item
* The line item to be saved
*/
function commerce_userpoints_discount_line_item_save($line_item) {
commerce_line_item_save($line_item);
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$order = commerce_order_load($line_item_wrapper->order_id
->value());
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$order_wrapper->commerce_line_items[] = $line_item;
$order_wrapper
->save();
}
/**
* Delete all userpoints line items on an order.
* (Function copied from Commerce_shipping)
* @param $order
* The order object to delete the shipping line items from.
*/
function commerce_userpoints_discount_clear_order($order_id) {
$order = commerce_order_load($order_id);
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
// When deleting more than one line item, metadata_wrapper will give problems if deleting while looping through the line items.
// So first remove from order and then delete the line items.
$line_items_to_delete = array();
foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
if ($line_item_wrapper->type
->value() == 'userpoints') {
$line_items_to_delete[] = $line_item_wrapper->line_item_id
->value();
$order_wrapper->commerce_line_items
->offsetUnset($delta);
}
}
$order_wrapper
->save();
// Delete line items.
foreach ($line_items_to_delete as $line_item_id) {
commerce_line_item_delete($line_item_id);
}
}
/**
* Implements hook_entity_delete().
*/
function commerce_userpoints_discount_entity_delete($entity, $type) {
// When a line item of userpoints type is delete, we set the related userpoints transaction to Declined status.
if ($type == 'commerce_line_item') {
if ($entity->type == 'userpoints') {
// Get the existing transaction.
$txn_field = field_get_items('commerce_line_item', $entity, 'commerce_userpoints_discount_txn');
// Update the userpoints transaction.
$userpoints_params = array(
'txn_id' => $txn_field[0]['value'],
'status' => USERPOINTS_TXN_STATUS_DECLINED,
);
userpoints_userpointsapi($userpoints_params);
}
}
}
/**
* Implements hook_commerce_price_component_type_info().
*/
function commerce_userpoints_discount_commerce_price_component_type_info() {
return array(
'userpoints' => array(
'title' => t('Royalties'),
'display_title' => t('Royalties'),
'weight' => 1000,
),
);
}
/**
* Callback function for commerce_userpoints_discount_pane_checkout_form()
* This function calls the commerce_userpoints_discount_use_credit_callback with the parameters
* set for the case where the user wishes to use a specified amount of points
*
* @param array $form
* $form variable from commerce_userpoints_discount_pane_checkout_form()
* @param array $form_state
* $form_state variable from commerce_userpoints_discount_pane_checkout_form()
*/
function commerce_userpoints_discount_use_credit_callback_input($form, $form_state) {
$order = $form_state['order'];
$amount = $form_state['values']['commerce_userpoints_discount']['amount'];
$currency = $form_state['values']['commerce_userpoints_discount']['currency'];
commerce_userpoints_discount_use_credit_callback($order, $amount, $currency);
$cart_contents_view = _commerce_userpoints_discount_update_cart_view($order->order_id);
$commands = array();
$commands[] = ajax_command_html('#commerce-userpoints-discount-cart-contents-wrapper', render($cart_contents_view));
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
/**
* Callback function for commerce_userpoints_discount_pane_checkout_form()
* This function calls the commerce_userpoints_discount_use_credit_callback with the parameters
* set for the case where the user wishes to use all his points for the current order
*
* @param array $form
* $form variable from commerce_userpoints_discount_pane_checkout_form()
* @param array $form_state
* $form_state variable from commerce_userpoints_discount_pane_checkout_form()
*/
function commerce_userpoints_discount_use_credit_callback_all($ajax, $order, $currency) {
$is_ajax = $ajax === 'ajax';
// Since clicking this link updates the database, we used drupal_get_token() for security.
if (empty($_GET['tok']) || !drupal_valid_token($_GET['tok'], 'commerce_userpoints_discount_useall' . $order->order_id . $currency['code'])) {
return MENU_ACCESS_DENIED;
}
$cur_user_points = userpoints_get_current_points($order->uid, variable_get('commerce_userpoints_discount_default_termid'));
// If the current user is out of points, we leave directly.
if ($cur_user_points == 0) {
return;
}
// Retrieve the order total for selected components.
$order_total = commerce_userpoints_discount_get_applicable_order_discount($order);
// work out the max number of credits that can be applied.
$amount = $cur_user_points >= $order_total ? $order_total : $cur_user_points;
// Apply all credits.
commerce_userpoints_discount_use_credit_callback($order, $amount, $currency);
if ($is_ajax) {
$cart_contents_view = _commerce_userpoints_discount_update_cart_view($order->order_id);
$use_links = _commerce_userpoints_discount_update_use_links($order, $currency['code']);
$commands = array();
// Re-render the cart so that updated line items are shown.
$commands[] = ajax_command_html('#commerce-userpoints-discount-cart-contents-wrapper', render($cart_contents_view));
// Regenerate the use all / remove all link.
$commands[] = ajax_command_html('#commerce-userpoints-use-links', render($use_links));
// Update the value in the input box.
$commands[] = ajax_command_invoke('input[name="commerce_userpoints_discount[amount]"]', 'val', array(
$amount,
));
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
else {
// TODO: What to return if there is no ajax?
}
}
/**
* Callback function for commerce_userpoints_discount_pane_checkout_form()
* This function calls commerce_userpoints_discount_clear_order() to remove all the userpoints
* line item of the current order
*
* @param array $form
* $form variable from commerce_userpoints_discount_pane_checkout_form()
* @param array $form_state
* $form_state variable from commerce_userpoints_discount_pane_checkout_form()
*/
function commerce_userpoints_discount_remove_credit_callback($ajax, $order, $currency) {
$is_ajax = $ajax === 'ajax';
// Since clicking this link updates the database, we used drupal_get_token() for security.
if (empty($_GET['tok']) || !drupal_valid_token($_GET['tok'], 'commerce_userpoints_discount_removeall' . $order->order_id . $currency['code'])) {
return MENU_ACCESS_DENIED;
}
commerce_userpoints_discount_clear_order($order->order_id);
if ($is_ajax) {
$cart_contents_view = _commerce_userpoints_discount_update_cart_view($order->order_id);
$use_links = _commerce_userpoints_discount_update_use_links($order, $currency['code']);
$commands = array();
// Re-render the cart so that updated line items are shown.
$commands[] = ajax_command_html('#commerce-userpoints-discount-cart-contents-wrapper', render($cart_contents_view));
// Regenerate the use all / remove all link.
$commands[] = ajax_command_html('#commerce-userpoints-use-links', render($use_links));
// Update the value in the input box.
$commands[] = ajax_command_invoke('input[name="commerce_userpoints_discount[amount]"]', 'val', array(
'',
));
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
else {
// TODO: What to return if there is no ajax?
}
}
/**
* Function called by commerce_userpoints_discount_use_credit_callback_input() and
* commerce_userpoints_discount_use_credit_callback_all().
* Perform the creation of the line item for the current order.
*
* @param array $form
* $form variable from commerce_userpoints_discount_pane_checkout_form()
* @param array $form_state
* $form_state variable from commerce_userpoints_discount_pane_checkout_form()
* @param bool $use_all_credit
* TRUE if all the points available should be used for this order. FALSE otherwise
*/
function commerce_userpoints_discount_use_credit_callback($order, $amount, $currency) {
$cur_user_points = userpoints_get_current_points($order->uid, variable_get('commerce_userpoints_discount_default_termid'));
// If the current user is out of points, we leave directly.
if ($cur_user_points == 0) {
return;
}
// If there is "no points" to use, we leave directly.
if ($amount == 0) {
return;
}
if ($amount > $cur_user_points) {
form_set_error('commerce_userpoints_discount][amount', t("You don't have enough credit"));
return FALSE;
}
if ($amount < 0) {
form_set_error('commerce_userpoints_discount][amount', t("The amount should be a positive value"));
return FALSE;
}
// Retrieve the order total for selected components.
$order_total = commerce_userpoints_discount_get_applicable_order_discount($order);
if ($amount > $order_total) {
form_set_error('commerce_userpoints_discount][amount', t("Too much !"));
return FALSE;
}
$line_item_id = commerce_userpoints_discount_order_has_userpoint_line_item($order->order_id);
// If there is no existing userpoints line item, we create a new one.
if ($line_item_id == NULL) {
// Create the line item.
$line_item = commerce_userpoints_discount_line_item_factory_new($order->order_id);
// Create the userpoints transaction.
$userpoints_params = array(
'points' => $amount * -1,
'uid' => $order->uid,
'operation' => 'commerce_userpoints_discount_credit',
'tid' => variable_get('commerce_userpoints_discount_default_termid', userpoints_get_default_tid()),
'display' => FALSE,
'entity_id' => $order->order_id,
'entity_type' => 'commerce_order',
);
$result = userpoints_userpointsapi($userpoints_params);
if ($result['status'] == FALSE) {
form_set_error("commerce_userpoints_discount][amount", t("Sorry, you cannot use your !points right now. Please contact us for more information", userpoints_translation()));
return FALSE;
}
$label = "User credit";
commerce_userpoints_discount_line_item_populate($line_item, $order->order_id, $result['transaction'], commerce_default_currency(), $label);
commerce_userpoints_discount_line_item_save($line_item);
}
else {
// If there is an existing userpoints line item for this order, we load it to get its userpoints transaction id.
$line_item = commerce_line_item_load($line_item_id);
// Get the existing transaction.
$txn_field = field_get_items('commerce_line_item', $line_item, 'commerce_userpoints_discount_transaction');
// Clear out the old $line_item.
commerce_userpoints_discount_clear_order($order->order_id);
unset($line_item);
// Update the userpoints transaction.
$userpoints_params = array(
'points' => intval($amount) * -1,
'txn_id' => $txn_field[0]['value'],
'status' => 0,
);
$result = userpoints_userpointsapi($userpoints_params);
if ($result['status'] == FALSE) {
form_set_error("commerce_userpoints_discount][amount", t("Sorry, you cannot use your !points right now. Please contact us for more information", userpoints_translation()));
return FALSE;
}
// Create the new line item.
$line_item = commerce_userpoints_discount_line_item_factory_new($order->order_id);
$label = t("User credit");
commerce_userpoints_discount_line_item_populate($line_item, $order->order_id, $result['transaction'], commerce_default_currency(), $label);
commerce_userpoints_discount_line_item_save($line_item);
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function commerce_userpoints_discount_form_commerce_checkout_form_checkout_alter(&$form, &$form_state) {
$form['cart_contents']['#prefix'] = '<div id="commerce-userpoints-discount-cart-contents-wrapper">';
$form['cart_contents']['#suffix'] = '</div>';
}
/**
* Retrieve the order total for selected components.
*
* @param $order
* The order whose total should be rendered for commerce_userpoints_discount
* enabled price components.
* @return
* The total amount of commerce_userpoints_discount enabled price components.
*/
function commerce_userpoints_discount_get_applicable_order_discount($order) {
$order_total = 0;
$commerce_order_total_field = field_get_items('commerce_order', $order, 'commerce_order_total');
return $commerce_order_total_field[0]['amount'];
foreach ($commerce_order_total_field[0]['data']['components'] as $price_component) {
$var = variable_get('commerce_userpoints_discount_total_price_components');
if (array_key_exists($price_component['name'], variable_get('commerce_userpoints_discount_total_price_components', array()))) {
$order_total += intval($price_component['price']['amount']) / variable_get('commerce_userpoints_discount_royalties_multiple', 1);
}
}
return $order_total;
}
/**
* Helper function to return rendered version of the commerce cart
* content view to be used when updating the cart via ajax.
* @param $order_id
* The order_id of the order who's cart view should be rendered.
* @return
* A rendered shopping cart.
*/
function _commerce_userpoints_discount_update_cart_view($order_id) {
// Extract the View and display keys from the cart contents pane setting.
list($view_id, $display_id) = explode('|', variable_get('commerce_cart_contents_pane_view', 'commerce_cart_summary|default'));
return array(
'#markup' => commerce_embed_view($view_id, $display_id, array(
$order_id,
)),
);
}
// Gt in for for a specific code.
function _commerce_userpoints_discount_get_info($order, $code = NULL) {
$currencies = commerce_userpoints_currencies();
$default_currency = reset($currencies);
if (isset($code)) {
$current_code = $code;
$current_tid = $currencies[$code]['tid'];
}
else {
$current_code = $default_currency['code'];
$current_tid = $default_currency['tid'];
}
$total = field_get_items('commerce_order', $order, 'commerce_order_total');
$total = $total[0];
$worth_of_a_point = commerce_currency_convert(1, $current_code, $total['currency_code']);
$worth_of_order = commerce_currency_convert($total['amount'], $total['currency_code'], $current_code);
$order_total = commerce_userpoints_discount_get_applicable_order_discount($order);
$count_applied = ($total['amount'] - $order_total) * -1;
$arguments = array(
'%points' => $worth_of_a_point,
'@order_currency' => commerce_currency_format($worth_of_a_point, $total['currency_code']),
'@count_needed' => commerce_currency_format($worth_of_order, $current_code),
'@count_applied' => $order_total,
'@count_available' => commerce_currency_format(userpoints_get_current_points(NULL, $current_tid), $current_code),
'@total_count_needed' => commerce_currency_format($order_total, $current_code),
) + userpoints_translation();
return $arguments;
}
function _commerce_userpoints_discount_update_use_links($order, $code) {
$arguments = _commerce_userpoints_discount_get_info($order, $code);
if ($arguments['@count_needed'] > 0) {
$text = t('Use @total_count_needed', $arguments);
$path = 'commerce_userpoints_discount/nojs/useall/' . $order->order_id . '/' . $code;
$options = array(
'attributes' => array(
'class' => array(
'use-ajax',
),
),
'query' => array(
'tok' => drupal_get_token('commerce_userpoints_discount_useall' . $order->order_id . $code),
) + drupal_get_destination(),
);
$description = l($text, $path, $options);
}
else {
$text = t('Remove @count_applied', $arguments);
$path = 'commerce_userpoints_discount/nojs/removeall/' . $order->order_id . '/' . $code;
$options = array(
'attributes' => array(
'class' => array(
'use-ajax',
),
),
'query' => array(
'tok' => drupal_get_token('commerce_userpoints_discount_removeall' . $order->order_id . $code),
) + drupal_get_destination(),
);
$description = l($text, $path, $options);
}
return $description;
}
/**
* Ajajx callback to update the exchange rate/points info.
*/
function _commerce_userpoints_discount_ajax_update_info($form, &$form_state) {
return $form['commerce_userpoints_discount']['info'];
}