diff --git a/modules/tax/commerce_tax.module b/modules/tax/commerce_tax.module index bb56e77..ff429d5 100644 --- a/modules/tax/commerce_tax.module +++ b/modules/tax/commerce_tax.module @@ -451,54 +451,65 @@ function commerce_tax_price_field_validate($element, &$form_state) { * Implements hook_field_attach_load(). */ function commerce_tax_field_attach_load($entity_type, $entities, $age, $options) { - // If product entities are being loaded... - if ($entity_type == 'commerce_product') { - // Loop over all the products looking for prices needing tax calculation. - foreach ($entities as $product) { - // Examine every field instance attached to this product's bundle. - foreach (field_info_instances('commerce_product', $product->type) as $field_name => $instance) { - // Load the instance's field data. - $field = field_info_field($instance['field_name']); - - // If the instance is of a price field... - if ($field['type'] == 'commerce_price' && !empty($product->{$field_name})) { - // Check to see if the product has specified an included tax. - foreach ($product->{$field_name} as $langcode => $items) { - foreach ($items as $delta => $item) { - // If it specifies a tax and we can load it... - if (!empty($item['data']['include_tax']) && $tax_rate = commerce_tax_rate_load($item['data']['include_tax'])) { - // Clean the price's components array, as we must start with a - // blank slate to rebuild the components for inclusive taxes. - $item['data']['components'] = array(); - - // Reverse apply the tax. - $tax_amount = $item['amount'] - ($item['amount'] / (1 + $tax_rate['rate'])); - $tax_amount = commerce_tax_rate_round_amount($tax_rate, $tax_amount); - - // Add a base price to the data array. - $component = array( - 'amount' => $item['amount'] - $tax_amount, - 'currency_code' => $item['currency_code'], - 'data' => array(), - ); - - $item['data'] = commerce_price_component_add($item, 'base_price', $component, TRUE); - - // Add the tax to the data array. - $component['amount'] = $tax_amount; - $component['data']['tax_rate'] = $tax_rate; - - $item['data'] = commerce_price_component_add($item, $tax_rate['price_component'], $component, TRUE); - - // Set the new item on the product entity. - $product->{$field_name}[$langcode][$delta] = $item; - } + + // Check if this is in the list of valid entities + $valid_entities = variable_get('commerce_tax_include_tax_entities', array('commerce_product')); + + if (!in_array($entity_type, $valid_entities)) { + return; + } + + // Loop over all the products looking for prices needing tax calculation. + foreach ($entities as $entity) { + + // Extract bundle + $ids = entity_extract_ids($entity_type, $entity); + $bundle = $ids[2]; + + // Examine every field instance attached to this product's bundle. + foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) { + // Load the instance's field data. + $field = field_info_field($instance['field_name']); + + // If the instance is of a price field... + if ($field['type'] == 'commerce_price' && !empty($entity->{$field_name})) { + // Check to see if the product has specified an included tax. + foreach ($entity->{$field_name} as $langcode => $items) { + foreach ($items as $delta => $item) { + // If it specifies a tax and we can load it... + if (!empty($item['data']['include_tax']) && $tax_rate = commerce_tax_rate_load($item['data']['include_tax'])) { + // Clean the price's components array, as we must start with a + // blank slate to rebuild the components for inclusive taxes. + $item['data']['components'] = array(); + + // Reverse apply the tax. + $tax_amount = $item['amount'] - ($item['amount'] / (1 + $tax_rate['rate'])); + $tax_amount = commerce_tax_rate_round_amount($tax_rate, $tax_amount); + + // Add a base price to the data array. + $component = array( + 'amount' => $item['amount'] - $tax_amount, + 'currency_code' => $item['currency_code'], + 'data' => array(), + ); + + $item['data'] = commerce_price_component_add($item, 'base_price', $component, TRUE); + + // Add the tax to the data array. + $component['amount'] = $tax_amount; + $component['data']['tax_rate'] = $tax_rate; + + $item['data'] = commerce_price_component_add($item, $tax_rate['price_component'], $component, TRUE); + + // Set the new item on the product entity. + $entity->{$field_name}[$langcode][$delta] = $item; } } } } } } + } /** @@ -639,3 +650,84 @@ function commerce_tax_components($components) { return $tax_components; } + +/** + * Implements hook_field_attach_form(). + */ +function commerce_tax_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) { + + // Check if this is in the list of valid entities + $valid_entities = variable_get('commerce_tax_include_tax_entities', array('commerce_product')); + + if (!in_array($entity_type, $valid_entities)) { + return; + } + + // Alter price widgets on the product form to have tax inclusive price entry. + // Build an array of tax types that are display inclusive. + $inclusive_types = array(); + + foreach (commerce_tax_types() as $name => $tax_type) { + if ($tax_type['display_inclusive']) { + $inclusive_types[$name] = $tax_type['title']; + } + } + + // Build an options array of tax rates of these types. + $options = array(); + + foreach (commerce_tax_rates() as $name => $tax_rate) { + if (in_array($tax_rate['type'], array_keys($inclusive_types))) { + $options[$inclusive_types[$tax_rate['type']]][$name] = t('Including !title', array('!title' => $tax_rate['title'])); + } + } + + // Get an array of price fields attached to products. + $fields = commerce_info_fields('commerce_price', $entity_type); + + // Loop over each child element of the form. + foreach (element_children($form) as $key) { + // If the current element is for a price field... + if (in_array($key, array_keys($fields))) { + // Loop over each of its child items... + foreach (element_children($form[$key][$form[$key]['#language']]) as $delta) { + if (!empty($options)) { + // Find the default value for the tax included element. + $default = ''; + + if (!empty($form[$key][$form[$key]['#language']][$delta]['data']['#default_value']['include_tax'])) { + $default = $form[$key][$form[$key]['#language']][$delta]['data']['#default_value']['include_tax']; + } + + $form[$key][$form[$key]['#language']][$delta]['currency_code']['#title'] = ' '; + + // Note that because this is a select element, the values in the + // #options array have not been sanitized. They will be passed + // through check_plain() in form_select_options() when this form + // element is processed. If you alter the type of this element to + // radios or checkboxes, you are responsible for sanitizing the + // values of the #options array as well. + $form[$key][$form[$key]['#language']][$delta]['include_tax'] = array( + '#type' => 'select', + '#title' => t('Include tax in this price'), + '#description' => t('Saving prices tax inclusive will bypass later calculations for the specified tax.'), + '#options' => count($options) == 1 ? reset($options) : $options, + '#default_value' => $default, + '#required' => FALSE, + '#empty_value' => '', + '#suffix' => '
', + '#attached' => array( + 'css' => array(drupal_get_path('module', 'commerce_tax') . '/theme/commerce_tax.theme.css'), + ), + ); + } + + // Append a validation handler to the price field's element validate + // array to add the included tax price component after the price has + // been converted from a decimal. + $form[$key][$form[$key]['#language']][$delta]['#element_validate'][] = 'commerce_tax_price_field_validate'; + } + } + } +} +