/**
  * Validate the checkout
  */
 public function validate_checkout()
 {
     if (fflcommerce_cart::is_empty()) {
         fflcommerce::add_error(sprintf(__('Sorry, your session has expired. <a href="%s">Return to homepage &rarr;</a>', 'fflcommerce'), home_url()));
     }
     // Process Discount Codes
     if (!empty($_POST['coupon_code'])) {
         $coupon = sanitize_title($_POST['coupon_code']);
         fflcommerce_cart::add_discount($coupon);
     }
     foreach (fflcommerce_cart::get_coupons() as $coupon) {
         fflcommerce_cart::is_valid_coupon($coupon);
     }
     // Checkout fields
     $this->posted['shipping_method'] = '';
     $this->posted['shipping_service'] = '';
     if (isset($_POST['shipping_method'])) {
         $shipping_method = fflcommerce_clean($_POST['shipping_method']);
         $shipping_data = explode(':', $shipping_method);
         $this->posted['shipping_method'] = $shipping_data[0];
         $this->posted['shipping_service'] = $shipping_data[1];
     }
     $this->posted['shiptobilling'] = isset($_POST['shiptobilling']) ? fflcommerce_clean($_POST['shiptobilling']) : '';
     $this->posted['payment_method'] = isset($_POST['payment_method']) ? fflcommerce_clean($_POST['payment_method']) : '';
     $this->posted['order_comments'] = isset($_POST['order_comments']) ? fflcommerce_clean($_POST['order_comments']) : '';
     $this->posted['terms'] = isset($_POST['terms']) ? fflcommerce_clean($_POST['terms']) : '';
     $this->posted['create_account'] = isset($_POST['create_account']) ? fflcommerce_clean($_POST['create_account']) : '';
     $this->posted['account_username'] = isset($_POST['account_username']) ? fflcommerce_clean($_POST['account_username']) : '';
     $this->posted['account_password'] = isset($_POST['account_password']) ? fflcommerce_clean($_POST['account_password']) : '';
     $this->posted['account_password_2'] = isset($_POST['account_password_2']) ? fflcommerce_clean($_POST['account_password_2']) : '';
     if (fflcommerce_cart::get_total(false) == 0) {
         $this->posted['payment_method'] = 'no_payment';
     }
     // establish customer billing and shipping locations
     if (fflcommerce_cart::ship_to_billing_address_only()) {
         $this->posted['shiptobilling'] = 'true';
     }
     $country = isset($_POST['billing_country']) ? fflcommerce_clean($_POST['billing_country']) : '';
     $state = isset($_POST['billing_state']) ? fflcommerce_clean($_POST['billing_state']) : '';
     $allowed_countries = FFLCommerce_Base::get_options()->get('fflcommerce_allowed_countries');
     if ($allowed_countries === 'specific') {
         $specific_countries = FFLCommerce_Base::get_options()->get('fflcommerce_specific_allowed_countries');
         if (!in_array($country, $specific_countries)) {
             fflcommerce::add_error(__('Invalid billing country.', 'fflcommerce'));
             return;
         }
     }
     if (fflcommerce_countries::country_has_states($country)) {
         $states = fflcommerce_countries::get_states($country);
         if (!in_array($state, array_keys($states))) {
             fflcommerce::add_error(__('Invalid billing state.', 'fflcommerce'));
             return;
         }
     }
     $postcode = isset($_POST['billing_postcode']) ? fflcommerce_clean($_POST['billing_postcode']) : '';
     $ship_to_billing = FFLCommerce_Base::get_options()->get('fflcommerce_ship_to_billing_address_only') == 'yes';
     fflcommerce_customer::set_location($country, $state, $postcode);
     if (FFLCommerce_Base::get_options()->get('fflcommerce_calc_shipping') == 'yes') {
         if ($ship_to_billing || !empty($_POST['shiptobilling'])) {
             fflcommerce_customer::set_shipping_location($country, $state, $postcode);
         } else {
             $country = isset($_POST['shipping_country']) ? fflcommerce_clean($_POST['shipping_country']) : '';
             $state = isset($_POST['shipping_state']) ? fflcommerce_clean($_POST['shipping_state']) : '';
             $postcode = isset($_POST['shipping_postcode']) ? fflcommerce_clean($_POST['shipping_postcode']) : '';
             if ($allowed_countries === 'specific') {
                 $specific_countries = FFLCommerce_Base::get_options()->get('fflcommerce_specific_allowed_countries');
                 if (!in_array($country, $specific_countries)) {
                     fflcommerce::add_error(__('Invalid shipping country.', 'fflcommerce'));
                     return;
                 }
             }
             if (fflcommerce_countries::country_has_states($country)) {
                 $states = fflcommerce_countries::get_states($country);
                 if (!in_array($state, array_keys($states))) {
                     fflcommerce::add_error(__('Invalid shipping state.', 'fflcommerce'));
                     return;
                 }
             }
             fflcommerce_customer::set_shipping_location($country, $state, $postcode);
         }
     }
     // Billing Information
     foreach ($this->billing_fields as $field) {
         $field = apply_filters('fflcommerce_billing_field', $field);
         $this->posted[$field['name']] = isset($_POST[$field['name']]) ? fflcommerce_clean($_POST[$field['name']]) : '';
         // Format
         if (isset($field['format'])) {
             switch ($field['format']) {
                 case 'postcode':
                     $this->posted[$field['name']] = strtolower(str_replace(' ', '', $this->posted[$field['name']]));
                     break;
             }
         }
         // Required
         if ($field['name'] == 'billing_state' && fflcommerce_customer::has_valid_shipping_state()) {
             $field['required'] = false;
         }
         if (isset($field['required']) && $field['required'] && empty($this->posted[$field['name']])) {
             fflcommerce::add_error($field['label'] . __(' (billing) is a required field.', 'fflcommerce'));
         }
         if ($field['name'] == 'billing_euvatno') {
             $vatno = isset($this->posted['billing_euvatno']) ? $this->posted['billing_euvatno'] : '';
             $vatno = str_replace(' ', '', $vatno);
             $country = fflcommerce_tax::get_customer_country();
             // strip any country code from the beginning of the number
             if (strpos($vatno, $country) === 0) {
                 $vatno = substr($vatno, strlen($country));
             }
             if ($vatno != '') {
                 $url = 'http://isvat.appspot.com/' . $country . '/' . $vatno . '/';
                 $httpRequest = curl_init();
                 curl_setopt($httpRequest, CURLOPT_FAILONERROR, true);
                 curl_setopt($httpRequest, CURLOPT_RETURNTRANSFER, true);
                 curl_setopt($httpRequest, CURLOPT_HEADER, false);
                 curl_setopt($httpRequest, CURLOPT_URL, $url);
                 $result = curl_exec($httpRequest);
                 curl_close($httpRequest);
                 if ($result === 'false') {
                     fflcommerce_log('EU VAT validation error with URL: ' . $url);
                     fflcommerce::add_error($field['label'] . __(' (billing) is not a valid VAT Number.  Leave it blank to disable VAT validation. (VAT may be charged depending on your location)', 'fflcommerce'));
                 } else {
                     $this->valid_euvatno = fflcommerce_countries::get_base_country() != fflcommerce_tax::get_customer_country() && fflcommerce_countries::is_eu_country(fflcommerce_tax::get_customer_country());
                 }
             }
         }
         // Validation
         if (isset($field['validate']) && !empty($this->posted[$field['name']])) {
             switch ($field['validate']) {
                 case 'phone':
                     if (!fflcommerce_validation::is_phone($this->posted[$field['name']])) {
                         fflcommerce::add_error($field['label'] . __(' (billing) is not a valid number.', 'fflcommerce'));
                     }
                     break;
                 case 'email':
                     if (!fflcommerce_validation::is_email($this->posted[$field['name']])) {
                         fflcommerce::add_error($field['label'] . __(' (billing) is not a valid email address.', 'fflcommerce'));
                     }
                     break;
                 case 'postcode':
                     if (!fflcommerce_validation::is_postcode($this->posted[$field['name']], $_POST['billing_country'])) {
                         fflcommerce::add_error($field['label'] . __(' (billing) is not a valid postcode/ZIP.', 'fflcommerce'));
                     } else {
                         $this->posted[$field['name']] = fflcommerce_validation::format_postcode($this->posted[$field['name']], $_POST['billing_country']);
                     }
                     break;
             }
         }
     }
     // Shipping Information
     if (fflcommerce_shipping::is_enabled() && !fflcommerce_cart::ship_to_billing_address_only() && empty($this->posted['shiptobilling'])) {
         foreach ($this->shipping_fields as $field) {
             $field = apply_filters('fflcommerce_shipping_field', $field);
             if (isset($_POST[$field['name']])) {
                 $this->posted[$field['name']] = fflcommerce_clean($_POST[$field['name']]);
             } else {
                 $this->posted[$field['name']] = '';
             }
             // Format
             if (isset($field['format'])) {
                 switch ($field['format']) {
                     case 'postcode':
                         $this->posted[$field['name']] = strtolower(str_replace(' ', '', $this->posted[$field['name']]));
                         break;
                 }
             }
             // Required
             if ($field['name'] == 'shipping_state' && fflcommerce_customer::has_valid_shipping_state()) {
                 $field['required'] = false;
             }
             if (isset($field['required']) && $field['required'] && empty($this->posted[$field['name']])) {
                 fflcommerce::add_error($field['label'] . __(' (shipping) is a required field.', 'fflcommerce'));
             }
             // Validation
             if (isset($field['validate']) && !empty($this->posted[$field['name']])) {
                 switch ($field['validate']) {
                     case 'postcode':
                         if (!fflcommerce_validation::is_postcode($this->posted[$field['name']], $country)) {
                             fflcommerce::add_error($field['label'] . __(' (shipping) is not a valid postcode/ZIP.', 'fflcommerce'));
                         } else {
                             $this->posted[$field['name']] = fflcommerce_validation::format_postcode($this->posted[$field['name']], $country);
                         }
                         break;
                 }
             }
         }
     }
     if ($this->must_register && empty($this->posted['create_account'])) {
         fflcommerce::add_error(__('Sorry, you must agree to creating an account', 'fflcommerce'));
     }
     if ($this->must_register || empty($user_id) && $this->posted['create_account']) {
         if (!$this->show_signup) {
             fflcommerce::add_error(__('Sorry, the shop owner has disabled guest purchases.', 'fflcommerce'));
         }
         if (empty($this->posted['account_username'])) {
             fflcommerce::add_error(__('Please enter an account username.', 'fflcommerce'));
         }
         if (empty($this->posted['account_password'])) {
             fflcommerce::add_error(__('Please enter an account password.', 'fflcommerce'));
         }
         if ($this->posted['account_password_2'] !== $this->posted['account_password']) {
             fflcommerce::add_error(__('Passwords do not match.', 'fflcommerce'));
         }
         // Check the username
         if (!validate_username($this->posted['account_username'])) {
             fflcommerce::add_error(__('Invalid email/username.', 'fflcommerce'));
         } elseif (username_exists($this->posted['account_username'])) {
             fflcommerce::add_error(__('An account is already registered with that username. Please choose another.', 'fflcommerce'));
         }
         // Check the e-mail address
         if (email_exists($this->posted['billing_email'])) {
             fflcommerce::add_error(__('An account is already registered with your email address. Please login.', 'fflcommerce'));
         }
     }
     // Terms
     if (!isset($_POST['update_totals']) && empty($this->posted['terms']) && fflcommerce_get_page_id('terms') > 0) {
         fflcommerce::add_error(__('You must accept our Terms &amp; Conditions.', 'fflcommerce'));
     }
     if (fflcommerce_cart::needs_shipping()) {
         // Shipping Method
         $available_methods = fflcommerce_shipping::get_available_shipping_methods();
         if (!isset($available_methods[$this->posted['shipping_method']])) {
             fflcommerce::add_error(__('Invalid shipping method.', 'fflcommerce'));
         }
     }
 }
    /**
     * Outputs a form field
     *
     * @param array $args contains a list of args for showing the field, merged with defaults (below)
     * @return string
     */
    public static function address_form_field($args)
    {
        $defaults = array('type' => 'text', 'name' => '', 'label' => '', 'placeholder' => '', 'required' => false, 'class' => array(), 'label_class' => array(), 'rel' => '', 'return' => false, 'options' => array(), 'value' => '');
        $args = wp_parse_args($args, $defaults);
        if ($args['required']) {
            $required = ' <span class="required">*</span>';
            $input_required = ' input-required';
        } else {
            $required = '';
            $input_required = '';
        }
        if (in_array('form-row-last', $args['class'])) {
            $after = '<div class="clear"></div>';
        } else {
            $after = '';
        }
        switch ($args['type']) {
            case "country":
                $current_c = self::get_value($args['name']);
                $is_shipping_c = strpos($args['name'], 'shipping');
                if (!$current_c) {
                    if ($is_shipping_c === false) {
                        $current_c = fflcommerce_customer::get_country();
                    } else {
                        $current_c = fflcommerce_customer::get_shipping_country();
                    }
                }
                // Remove 'Select a Country' option from drop-down menu for countries.
                // There is no need to have it, because was assume when user hasn't selected
                // a country that they are from the shop base country.
                $field = '<p class="form-row ' . implode(' ', $args['class']) . '">
        <label for="' . esc_attr($args['name']) . '" class="' . esc_attr(implode(' ', $args['label_class'])) . '">' . $args['label'] . $required . '</label>
        <select name="' . esc_attr($args['name']) . '" id="' . esc_attr($args['name']) . '" class="country_to_state" rel="' . esc_attr($args['rel']) . '">';
                foreach (fflcommerce_countries::get_allowed_countries() as $key => $value) {
                    $field .= '<option value="' . esc_attr($key) . '"';
                    if (self::get_value($args['name']) == $key) {
                        $field .= ' selected="selected"';
                    } elseif (self::get_value($args['name']) && $current_c == $key) {
                        $field .= ' selected="selected"';
                    }
                    $field .= '>' . __($value, 'fflcommerce') . '</option>';
                }
                $field .= '</select></p>' . $after;
                break;
            case "state":
                $field = '<p class="form-row ' . implode(' ', $args['class']) . '">
					<label for="' . esc_attr($args['name']) . '" class="' . implode(' ', $args['label_class']) . '">' . $args['label'] . $required . '</label>';
                $is_shipping_s = strpos($args['name'], 'shipping');
                $current_cc = self::get_value($args['rel']);
                if (!$current_cc) {
                    if ($is_shipping_s === false) {
                        $current_cc = fflcommerce_customer::get_country();
                    } else {
                        $current_cc = fflcommerce_customer::get_shipping_country();
                    }
                }
                $current_r = self::get_value($args['name']);
                if (!$current_r) {
                    if ($is_shipping_s === false) {
                        $current_r = fflcommerce_customer::get_state();
                    } else {
                        $current_r = fflcommerce_customer::get_shipping_state();
                    }
                }
                $states = fflcommerce_countries::get_states($current_cc);
                if (!empty($states)) {
                    // Dropdown
                    $field .= '<select name="' . esc_attr($args['name']) . '" id="' . esc_attr($args['name']) . '" class="' . esc_attr($input_required) . '"><option value="">' . __('Select a state&hellip;', 'fflcommerce') . '</option>';
                    foreach ($states as $key => $value) {
                        $field .= '<option value="' . esc_attr($key) . '"';
                        if ($current_r == $key) {
                            $field .= ' selected="selected"';
                        }
                        $field .= '>' . __($value, 'fflcommerce') . '</option>';
                    }
                    $field .= '</select>';
                } else {
                    // Input
                    $field .= '<input type="text" class="input-text" value="' . esc_attr($current_r) . '" placeholder="' . __('State/Province', 'fflcommerce') . '" name="' . esc_attr($args['name']) . '" id="' . esc_attr($args['name']) . '" />';
                }
                $field .= '</p>' . $after;
                break;
            case "postcode":
                $current_pc = self::get_value($args['name']);
                $is_shipping_pc = strpos($args['name'], 'shipping');
                if (!$current_pc) {
                    if ($is_shipping_pc === false) {
                        $current_pc = fflcommerce_customer::get_postcode();
                    } else {
                        $current_pc = fflcommerce_customer::get_shipping_postcode();
                    }
                }
                $field = '<p class="form-row ' . implode(' ', $args['class']) . '">
					<label for="' . esc_attr($args['name']) . '" class="' . implode(' ', $args['label_class']) . '">' . $args['label'] . $required . '</label>
					<input type="text" class="input-text" name="' . esc_attr($args['name']) . '" id="' . esc_attr($args['name']) . '" placeholder="' . $args['placeholder'] . '" value="' . esc_attr($current_pc) . '" />
				</p>' . $after;
                break;
            case "textarea":
                $field = '<p class="form-row ' . implode(' ', $args['class']) . '">
					<label for="' . esc_attr($args['name']) . '" class="' . implode(' ', $args['label_class']) . '">' . $args['label'] . $required . '</label>
					<textarea name="' . esc_attr($args['name']) . '" class="input-text' . esc_attr($input_required) . '" id="' . esc_attr($args['name']) . '" placeholder="' . $args['placeholder'] . '" cols="5" rows="2">' . esc_textarea(self::get_value($args['name'])) . '</textarea>
				</p>' . $after;
                break;
                //Adds a drop down custom type
            //Adds a drop down custom type
            case "select":
                $field = '<p class="form-row ' . implode(' ', $args['class']) . '">
						  <label for="' . esc_attr($args['name']) . '" class="' . implode(' ', $args['label_class']) . '">' . $args['label'] . $required . '</label>';
                $field .= '<select name="' . esc_attr($args['name']) . '" id="' . esc_attr($args['name']) . '" class="' . esc_attr($input_required) . '">';
                foreach ($args['options'] as $value => $label) {
                    $field .= '<option value="' . esc_attr($value) . '"';
                    if (self::get_value($args['name']) == $value) {
                        $field .= ' selected="selected"';
                    }
                    $field .= '>' . __($label, 'fflcommerce') . '</option>';
                }
                $field .= '</select></p>' . $after;
                break;
            default:
                $field = '<p class="form-row ' . implode(' ', $args['class']) . '">
					<label for="' . esc_attr($args['name']) . '" class="' . implode(' ', $args['label_class']) . '">' . $args['label'] . $required . '</label>
					<input type="' . $args['type'] . '" class="input-text' . esc_attr($input_required) . '" name="' . esc_attr($args['name']) . '" id="' . esc_attr($args['name']) . '" placeholder="' . $args['placeholder'] . '" value="' . self::get_value($args['name']) . '" />
				</p>' . $after;
                break;
        }
        $field = apply_filters('fflcommerce_address_field_types', $field, $args);
        if ($args['return']) {
            return $field;
        } else {
            echo $field;
            return null;
        }
    }
 /**
  * When Options are saved, return the 'fflcommerce_tax_rates' option values
  *
  * @return  mixed  false if not rax rates, array of tax rates otherwise
  * @since  1.3
  */
 function get_updated_tax_classes()
 {
     $tax_rates = array();
     $tax_fields = array('tax_classes' => '', 'tax_country' => '', 'tax_rate' => '', 'tax_label' => '', 'tax_shipping' => '', 'tax_compound' => '');
     /* Save each array key to a variable */
     foreach ($tax_fields as $name => $val) {
         if (isset($_POST[$name])) {
             $tax_fields[$name] = $_POST[$name];
         }
     }
     for ($i = 0; $i < sizeof($tax_fields['tax_classes']); $i++) {
         if (empty($tax_fields['tax_rate'][$i])) {
             continue;
         }
         $countries = $tax_fields['tax_country'][$i];
         $label = trim($tax_fields['tax_label'][$i]);
         $rate = number_format(floatval($tax_fields['tax_rate'][$i]), 4);
         $class = fflcommerce_clean($tax_fields['tax_classes'][$i]);
         $shipping = !empty($tax_fields['tax_shipping'][$i]) ? 'yes' : 'no';
         $compound = !empty($tax_fields['tax_compound'][$i]) ? 'yes' : 'no';
         /* Save the state & country separately from options eg US:OH */
         $whole_countries_processed = array();
         foreach ($countries as $country_code) {
             @(list($country, $state) = explode(':', $country_code, 2));
             if (!in_array($country, $whole_countries_processed)) {
                 if ($state === null && fflcommerce_countries::country_has_states($country)) {
                     $whole_countries_processed[] = $country;
                     foreach (fflcommerce_countries::get_states($country) as $state => $state_name) {
                         $tax_rates[] = array('country' => $country, 'label' => $label, 'state' => $state, 'rate' => $rate, 'shipping' => $shipping, 'class' => $class, 'compound' => $compound, 'is_all_states' => true);
                     }
                 } else {
                     $tax_rates[] = array('country' => $country, 'label' => $label, 'state' => $state, 'rate' => $rate, 'shipping' => $shipping, 'class' => $class, 'compound' => $compound, 'is_all_states' => false);
                 }
             }
         }
     }
     usort($tax_rates, array($this, 'csort_tax_rates'));
     return $tax_rates;
 }