You are here

br_tax_number_fields.module in Brazilian IDs 7

Adds Brazilian Tax Number field widgets to text field type at the Field UI and creates new form element types for use in the Form API.

File

br_tax_number_fields.module
View source
<?php

/**
 * @file
 * Adds Brazilian Tax Number field widgets to text field type at the Field UI
 * and creates new form element types for use in the Form API.
 */

/**
 * Implements hook_field_display_alter().
 */
function br_tax_number_fields_field_display_alter(&$display, $context) {
  if ($context['instance']['widget']['module'] == 'br_tax_number_fields') {
    $display['type'] = $context['instance']['widget']['type'];

    // Change from text module to br_tax_number_fields so
    // br_tax_number_fields_field_formatter_view is called.
    $display['module'] = 'br_tax_number_fields';
  }
}

/**
 * Implements hook_field_formatter_view().
 */
function br_tax_number_fields_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  if (in_array($display['type'], array(
    'number_cnpj',
    'number_cpf',
    'number_cnpj_cpf',
  ))) {
    $markup = '';
    foreach ($items as $delta => $item) {
      $v = $item['value'];
      if (strlen($item['value']) == 11) {

        // This is a CPF.
        $markup = sprintf('%s.%s.%s-%s', $v[0] . $v[1] . $v[2], $v[3] . $v[4] . $v[5], $v[6] . $v[7] . $v[8], $v[9] . $v[10]);
      }
      elseif (strlen($item['value']) == 14) {

        // This is a CNPJ.
        $v1 = $v[0] . $v[1];
        $v2 = $v[2] . $v[3] . $v[4];
        $v3 = $v[5] . $v[6] . $v[7];
        $v4 = $v[8] . $v[9] . $v[10] . $v[11];
        $v5 = $v[12] . $v[13];
        $markup = sprintf('%s.%s.%s/%s-%s', $v1, $v2, $v3, $v4, $v5);
      }
      $element[$delta]['#markup'] = $markup;
    }
  }
  return $element;
}

/**
 * Implements hook_field_widget_info().
 */
function br_tax_number_fields_field_widget_info() {
  return array(
    'number_cnpj' => array(
      'label' => t('CNPJ'),
      'field types' => array(
        'text',
      ),
    ),
    'number_cpf' => array(
      'label' => t('CPF'),
      'field types' => array(
        'text',
      ),
    ),
    'number_cnpj_cpf' => array(
      'label' => t('CNPJ / CPF'),
      'field types' => array(
        'text',
      ),
    ),
  );
}

/**
 * Implements hook_form_alter().
 *
 * Hide the unnecessary fields from settings page
 */
function br_tax_number_fields_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'field_ui_field_edit_form') {
    if (in_array($form['#instance']['widget']['type'], array(
      'number_cnpj',
      'number_cpf',
      'number_cnpj_cpf',
    ))) {
      $form['instance']['settings']['text_processing']['#type'] = 'hidden';
      $form['field']['settings']['max_length']['#type'] = 'hidden';
    }
  }
}

/**
 * Implements hook_field_widget_form().
 */
function br_tax_number_fields_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $value = isset($items[$delta]['value']) ? $items[$delta]['value'] : '';
  $maxlength = 18;
  $size = 18;
  switch ($instance['widget']['type']) {
    case 'number_cnpj':
      $callback_validate = 'br_tax_number_fields_cnpj_validate';
      break;
    case 'number_cpf':
      $maxlength = 14;
      $size = 14;
      $callback_validate = 'br_tax_number_fields_cpf_validate';
      break;
    case 'number_cnpj_cpf':
      $callback_validate = 'br_tax_number_fields_cnpj_cpf_validate';
      break;
  }
  $element += array(
    '#type' => 'textfield',
    '#default_value' => $value,
    '#maxlength' => $maxlength,
    '#size' => $size,
    '#element_validate' => array(
      $callback_validate,
    ),
  );
  return array(
    'value' => $element,
  );
}

/**
 * Validation callback.
 */
function br_tax_number_fields_cnpj_validate($element, &$form_state) {
  $value = _br_tax_number_fields_is_number($element, $form_state['values']);
  $cnpj_result = br_tax_number_cnpj_validator($value);
  if (!$cnpj_result['status']) {
    form_error($element, $cnpj_result['msg']);
  }
}

/**
 * Function to validate if value is a cnpj
 * @param  string $value
 * @return array  TRUE or FALSE and MSG error
 */
function br_tax_number_cnpj_validator($value) {
  if (!empty($value)) {
    $forbidden = array(
      '00000000000000',
      '11111111111111',
      '22222222222222',
      '33333333333333',
      '44444444444444',
      '55555555555555',
      '66666666666666',
      '77777777777777',
      '88888888888888',
      '99999999999999',
    );
    if (in_array($value, $forbidden)) {
      return array(
        'status' => FALSE,
        'msg' => t('CNPJ field does not allow a sequence of the same number.'),
      );
    }
    if (strlen($value) != 14) {
      return array(
        'status' => FALSE,
        'msg' => t('CNPJ must have 14 digits.'),
      );
    }
    else {

      //@TODO - Translate variables to english
      $cnpj = $value;
      $k = 6;
      $soma1 = 0;
      $soma2 = 0;
      for ($i = 0; $i < 13; $i++) {
        $k = $k == 1 ? 9 : $k;
        $soma2 += $cnpj[$i] * $k;
        $k--;
        if ($i < 12) {
          if ($k == 1) {
            $k = 9;
            $soma1 += $cnpj[$i] * $k;
            $k = 1;
          }
          else {
            $soma1 += $cnpj[$i] * $k;
          }
        }
      }
      $digito1 = $soma1 % 11 < 2 ? 0 : 11 - $soma1 % 11;
      $digito2 = $soma2 % 11 < 2 ? 0 : 11 - $soma2 % 11;
      if ($cnpj[12] != $digito1 && $cnpj[13] != $digito2) {
        return array(
          'status' => FALSE,
          'msg' => t('CNPJ number you have entered is invalid.'),
        );
      }
    }
  }
  return array(
    'status' => TRUE,
  );
}

/**
 * Validation callback.
 */
function br_tax_number_fields_cpf_validate($element, &$form_state) {
  $value = _br_tax_number_fields_is_number($element, $form_state['values']);
  $cpf_result = br_tax_number_cpf_validator($value);
  if (!$cpf_result['status']) {
    form_error($element, $cpf_result['msg']);
  }
}

/**
 * Function to validate if value is a cpf
 * @param  string $value
 * @return array  TRUE or FALSE and MSG error
 */
function br_tax_number_cpf_validator($value) {
  if (!empty($value)) {
    $forbidden = array(
      '00000000000',
      '11111111111',
      '22222222222',
      '33333333333',
      '44444444444',
      '55555555555',
      '66666666666',
      '77777777777',
      '88888888888',
      '99999999999',
    );
    if (in_array($value, $forbidden)) {
      return array(
        'status' => FALSE,
        'msg' => t('CPF field does not allow a sequence of the same number.'),
      );
    }
    if (strlen($value) != 11) {
      return array(
        'status' => FALSE,
        'msg' => t('CPF must have 11 digits.'),
      );
    }
    else {

      // @TODO - Translate variables to english
      $cpf_validar = substr($value, 0, 9);
      $soma = 0;
      $n = 11;
      for ($i = 0; $i <= 9; $i++) {
        $n = $n - 1;
        $soma = $soma + substr($cpf_validar, $i, 1) * $n;
      }
      $resto = $soma % 11;
      if ($resto < 2) {
        $cpf_validar .= 0;
      }
      else {
        $cpf_validar = $cpf_validar . (11 - $resto);
      }

      // Segunda parte da validação do CPF.
      $soma = 0;
      $n = 12;
      for ($i = 0; $i <= 10; $i++) {
        $n = $n - 1;
        $soma = $soma + substr($cpf_validar, $i, 1) * $n;
      }
      $resto = $soma % 11;
      if ($resto < 2) {
        $cpf_validar .= 0;
      }
      else {
        $cpf_validar = $cpf_validar . (11 - $resto);
      }
      if ($cpf_validar != $value) {
        return array(
          'status' => FALSE,
          'msg' => t('CPF number you have entered is invalid.'),
        );
      }
    }
  }
  return array(
    'status' => TRUE,
  );
}

/**
 * Validation callback.
 */
function br_tax_number_fields_cnpj_cpf_validate($element, &$form_state) {
  $value = _br_tax_number_fields_is_number($element, $form_state['values']);
  if (!empty($value)) {
    $length = strlen($value);
    if (!in_array($length, array(
      11,
      14,
    ))) {
      form_error($element, t('CPF / CNPJ field must have either 11 or 14 digits.'));
    }
    else {
      if ($length == 11) {
        br_tax_number_fields_cpf_validate($element, $form_state);
      }
      else {
        br_tax_number_fields_cnpj_validate($element, $form_state);
      }
    }
  }
}

/**
 * Helper function for checking if the entered value contains only numbers.
 *
 * @param Array $element
 *   The form element array.
 *
 * @param Array $form_state_values
 *   The $form_state['values'] array.
 *
 * @return String
 *   The trimmed value entered by the user.
 */
function _br_tax_number_fields_is_number($element, &$form_state_values) {
  $value = trim($element['#value']);
  $value = str_replace(array(
    '.',
    '-',
    '/',
  ), '', $value);

  // The value of $depth_pointer will end up being, in most cases, something
  // like: [group][field_name][un][0][value]
  $depth_pointer = '';
  foreach ($element['#parents'] as $parent) {
    $depth_pointer .= "['{$parent}']";
  }

  // Set the clean value for $form_state[group][field_name][un][0][value]
  // which will be saved into the database.
  eval("\$form_state_values" . $depth_pointer . " = \$value;");
  if (strlen($value) != strlen(preg_replace('/[^0-9]+/', '', $value))) {
    form_error($element, t('%name must have only numbers.', array(
      '%name' => $element['#title'],
    )));
  }
  return $value;
}

/**
 * Implements hook_field_widget_error().
 */
function br_tax_number_fields_field_widget_error($element, $error, $form, &$form_state) {
  form_error($element['value'], $error['message']);
}

/**
 * Implements hook_element_info().
 */
function br_tax_number_fields_element_info() {
  $types['number_cpf'] = array(
    '#input' => TRUE,
    '#element_validate' => array(
      'br_tax_number_fields_cpf_validate',
    ),
    '#theme' => array(
      'textfield',
    ),
    '#autocomplete_path' => FALSE,
    '#maxlength' => 14,
    '#theme_wrappers' => array(
      'form_element',
    ),
  );
  $types['number_cnpj'] = array(
    '#input' => TRUE,
    '#element_validate' => array(
      'br_tax_number_fields_cnpj_validate',
    ),
    '#theme' => array(
      'textfield',
    ),
    '#autocomplete_path' => FALSE,
    '#maxlength' => 18,
    '#theme_wrappers' => array(
      'form_element',
    ),
  );
  $types['number_cnpj_cpf'] = array(
    '#input' => TRUE,
    '#element_validate' => array(
      'br_tax_number_fields_cnpj_cpf_validate',
    ),
    '#theme' => array(
      'textfield',
    ),
    '#autocomplete_path' => FALSE,
    '#maxlength' => 18,
    '#theme_wrappers' => array(
      'form_element',
    ),
  );
  return $types;
}