File "class.calculate-rates.php"

Full Path: /home/siazco/grocery.siazco.se/wp-content/plugins/woocommerce-table-rate-shipping/inc/class.calculate-rates.php
File size: 30.95 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/*
 * Table Rate Shipping Method Extender Class
 */

if ( ! defined( 'ABSPATH' ) )
	exit;

// Check if WooCommerce is active
if ( class_exists( 'WooCommerce' ) ) {

	if ( class_exists( 'BE_Table_Rate_Calculate' ) ) return;

	class BE_Table_Rate_Calculate {

		/*
		 * Shipping Package Information
		 */
		private $method;

		/*
		 * Table Rates from Database
		 */
		private $table_rates;

		/**
		 * Cloning is forbidden. Will deactivate prior 'instances' users are running
		 *
		 * @since 4.0
		 */
		public function __clone() {
			_doing_it_wrong( __FUNCTION__, esc_html__( 'Cloning this class could cause catastrophic disasters!', 'be-table-ship' ), '4.0' );
		}

		/**
		 * Unserializing instances of this class is forbidden.
		 *
		 * @since 4.0
		 */
		public function __wakeup() {
			_doing_it_wrong( __FUNCTION__, esc_html__( 'Unserializing is forbidden!', 'be-table-ship' ), '4.0' );
		}

		/**
		 * __construct function.
		 *
		 * @access public
		 * @return void
		 */
		function __construct( $method, $table_rates ) {

			$this->method 		= $method;
			$this->table_rates 	= $table_rates;
		}


		/**
		 * calculate_shipping function.
		 *
		 * @access public
		 * @param array $package (default: array())
		 * @return array
		 */
		function calculate_shipping( $package = array() ) {
			global $betrs_shipping;

			if( is_array( $package ) && ! empty( $package ) && isset( $package['contents'] ) ) {
				// calculate cart statistics for processing table rates
				$cart_data = array();

				switch( $this->method->condition ) {
					case 'per-order':
						$cart_data = array( 'per-order' => $this->calculate_totals_order( $package['contents'] ) );
						break;

					case 'per-item':
						$cart_data = $this->calculate_totals_item( $package['contents'] );
						break;

					case 'per-line-item':
						$cart_data = $this->calculate_totals_item( $package['contents'], true );
						break;
					
					case 'per-class':
						$cart_data = $this->calculate_totals_class( $package['contents'] );
						break;
					
					default:
						$cart_data = apply_filters( 'betrs_calculate_method_totals', $cart_data, $this->method->condition, $package, $this->method );
						break;
				}

				// send to calculator for processing
				$contents_cost = 0;
				if( ! empty( $cart_data ) ) {
					$rates = array();
					foreach( $cart_data as $key => $data ) {
						$rates[ $key ] = $this->process_table_rates( $data );
						$contents_cost += $data['subtotal'];
					}
				}
				$shipping_options = $first_option = array();

				// ensure that all rates cover all items in the cart
				if( is_array( $rates ) && count( $rates ) > 0 ) {
					$n = 0;
					foreach( $rates as $key => $rate ) {
						if( $n == 0 ) {
							$option_ids = array_keys( $rate );
							$n++;
							continue;
						}
						$option_ids = array_intersect( $option_ids, array_keys( $rate ) );
					}
					// remove invalid options from $rates
					foreach( $rates as $key => $rate ) {
						$rates[$key] = array_intersect_key( $rate, array_flip( $option_ids ) );
					}
				}

				// Adjust for single class only if necessary
				if( $this->method->condition == 'per-class' ) {
					switch( $this->method->single_class ) {
						case 'priority':
							$highest_key = $highest_priority = 0;
							foreach( $rates as $class_key => $options ) {
								$get_priority = get_term_meta( $class_key, 'priority', true );

								if( $get_priority >= $highest_priority ) {
									$highest_priority = $get_priority;
									$highest_key = $class_key;
								}

							}

							// add contents cost for subtotal shortcode
							foreach( $rates[ $highest_key ] as $op_id => $op_val ) {
								$rates[ $highest_key ][ $op_id ]['contents_cost'] = $cart_data[ $highest_key ]['subtotal'];
							}

							return $rates[ $highest_key ];
							break;
						
						case 'cost_high':
						case 'cost_low':
							$options_for_return = array();
							$op_class = false;

							foreach( $rates as $class_key => $options ) {

								foreach( $options as $op_key => $option ) {

									if( ! isset( $options_for_return[ $op_key] ) ) {
										// initialize an option for this ID
										$options_for_return[ $op_key ] = $option;

									} else {
										// determine if this is the option to be returned based on cost
										if( $this->method->single_class == 'cost_low' ) {
											if( $option['cost'] < $options_for_return[ $op_key ]['cost'] ) {
												$options_for_return[ $op_key ] = $option;
												$op_class = $class_key;
											}
										} else {
											if( $option['cost'] > $options_for_return[ $op_key ]['cost'] ) {
												$options_for_return[ $op_key ] = $option;
												$op_class = $class_key;
											}
										}
									}
								}

							}

							// add contents cost for subtotal shortcode
							foreach( $options_for_return as $op_id => $op_val ) {
								$options_for_return[ $op_id ]['contents_cost'] = $cart_data[ $class_key ]['subtotal'];
							}

							return $options_for_return;
							break;

						case 'disabled':
							break;
						
						default:
							return apply_filters( 'betrs_condition_single_class_' . $this->method->single_class, $rates );
							break;
					}
				}

				// compile for return (combine Per Item and Per Class data to one price)
				$shipping_options = array();
				foreach( $rates as $key => $rate ) {
					foreach( $rate as $op_key => $op ) {
						if( ! isset( $shipping_options[ $op_key ] ) ) {
							$shipping_options[ $op_key ] = $op;
							$shipping_options[ $op_key ]['contents_cost'] = $contents_cost;

							// Set title to Method Title when left empty
							if( $shipping_options[ $op_key ]['label'] == '' ) 
								$shipping_options[ $op_key ]['label'] = $this->method->method_title;

							// setup option's default description
							$shipping_options[ $op_key ]['description'] = ( isset( $op['description_op'] ) ) ? wp_kses( $op['description_op'], $betrs_shipping->allowedtags ) : "";

						} else {

							$shipping_options[ $op_key ]['cost'] += $op['cost'];
							$shipping_options[ $op_key ]['row_id'] = $op['row_id'];

						}

						// update description if given
						if( ! empty( $op['description'] ) ) {
							if( $op['combine_desc'] === 'on' ) {
								$shipping_options[ $op_key ]['description'] = $shipping_options[ $op_key ]['description'] . ' ' . $op['description'];
							} else {
								$shipping_options[ $op_key ]['description'] = $op['description'];
							}
						}
					}
				}

				return apply_filters( 'betrs_calculated_shipping_options', $shipping_options, $rates );
			}

		}


		/**
		 * calculate order totals (Per Order).
		 *
		 * @access public
		 * @param array $package (default: array())
		 * @return array
		 */
		function calculate_totals_order( $items ) {
			// setup initialized variables
			$subtotal = $quantity = $weight = $height = $width = $length = $area = $volume = 0;
			$products = $shipping_classes = $categories = $status = array();

			// cycle through cart items
			foreach( $items as $item_ar ) {

				// only count the ones that apply to shipping
				if( isset( $item_ar['data'] ) && $item_ar['data']->needs_shipping() ) {
					$item = $item_ar['data'];

					// manage measurement calculations
					$t_height = (float) apply_filters( 'betrs_calculated_item-height', $item->get_height(), $item_ar );
					$t_width = (float) apply_filters( 'betrs_calculated_item-width', $item->get_width(), $item_ar );
					$t_length = (float) apply_filters( 'betrs_calculated_item-length', $item->get_length(), $item_ar );
					$t_area = array_filter( array( $t_height, $t_width ) );
					$t_area = ( empty( $t_area ) ) ? 0 : array_product( $t_area );
					$t_volume = array_filter( array( $t_height, $t_width, $t_length ) );
					$t_volume = ( empty( $t_volume ) ) ? 0 : array_product( $t_volume );

					$height += $t_height * $item_ar['quantity'];
					$width += $t_width * $item_ar['quantity'];
					$length += $t_length * $item_ar['quantity'];
					$area += $t_area * $item_ar['quantity'];
					$volume += $t_volume * $item_ar['quantity'];

					// adjust number data
					$subtotal += $this->get_line_item_price( $item_ar );
					$quantity += $item_ar['quantity'];
					$weight += $this->get_line_item_weight( $item_ar ) * $item_ar['quantity'];

					// add additional product information
					if( $item->get_type() == 'variation' )
						$parent_id = ( version_compare( WC_VERSION, '3.0', ">=" ) ) ? $item->get_parent_id(): $item->parent->id;

					$products[] = ( $item->get_type() == 'variation' ) ? $parent_id : $item->get_id();
					$shipping_classes[] = apply_filters( 'betrs_settings_shipping_class', $item->get_shipping_class_id() );
					$status[] = $item->get_stock_status();
					$get_categories = ( $item->get_type() == 'variation' ) ? get_the_terms( $parent_id, 'product_cat' ) : get_the_terms( $item->get_id(), 'product_cat' );
					if( $get_categories ) {
						foreach( $get_categories as $cat ){
						   $categories[] = $cat->term_id;
						}
					}
				}

			}

			$shipping_classes = array_unique( $shipping_classes );
			$categories = array_unique( $categories );
			$weight = ( $this->method->round_weight === 'yes' ) ? ceil( $weight ) : $weight;

			// setup outgoing data for return
			$data = array(
				'subtotal' 			=> $subtotal,
				'quantity' 			=> $quantity,
				'weight' 			=> $weight,
				'height' 			=> $height,
				'width' 			=> $width,
				'length' 			=> $length,
				'area' 				=> $area,
				'volume' 			=> $volume,
				'products' 			=> $products,
				'shipping_classes' 	=> $shipping_classes,
				'categories' 		=> $categories,
				'status'			=> $status,
				);

			return apply_filters( 'betrs_calculated_totals-per_order', $data, $items );

		}


		/**
		 * calculate order totals (Per Item and Per Line Item).
		 *
		 * @access public
		 * @param array $package (default: array())
		 * @return array
		 */
		function calculate_totals_item( $items, $per_line = false ) {
			// setup initialized variables
			$data = array();

			// cycle through cart items
			foreach( $items as $item_ar ) {

				// only count the ones that apply to shipping
				if( isset( $item_ar['data'] ) && $item_ar['data']->needs_shipping() ) {
					$item = $item_ar['data'];
					$categories = $status = array();

					// add additional product information
					if( $item->get_type() == 'variation' )
						$parent_id = ( version_compare( WC_VERSION, '3.0', ">=" ) ) ? $item->get_parent_id(): $item->parent->id;

					// manage measurement calculations
					$t_height = (float) apply_filters( 'betrs_calculated_item-height', $item->get_height(), $item_ar );
					$t_width = (float) apply_filters( 'betrs_calculated_item-width', $item->get_width(), $item_ar );
					$t_length = (float) apply_filters( 'betrs_calculated_item-length', $item->get_length(), $item_ar );
					$t_area = array_filter( array( $t_height, $t_width ) );
					$t_area = ( empty( $t_area ) ) ? 0 : array_product( $t_area );
					$t_volume = array_filter( array( $t_height, $t_width, $t_length ) );
					$t_volume = ( empty( $t_volume ) ) ? 0 : array_product( $t_volume );

					// add additional product information
					$get_categories = ( $item->get_type() == 'variation' ) ? get_the_terms( $parent_id, 'product_cat' ) : get_the_terms( $item->get_id(), 'product_cat' );
					if( $get_categories ) {
						foreach( $get_categories as $cat ){
						   $categories[] = $cat->term_id;
						}
					}
					$status[] = $item->get_stock_status();

					// get proper product ID
					$product_id = $item->get_id();
					if( $item->get_type() == 'variation' ) {
						$product_id = ( version_compare( WC_VERSION, '3.0', ">=" ) ) ? $item->get_parent_id(): $item->parent->id;
					}

					// adjust numbers if Per Line Item is the selected condition
					if( $per_line === true ) {
						$weight = $this->get_line_item_weight( $item_ar ) * $item_ar['quantity'];
						$weight = ( $this->method->round_weight === 'yes' ) ? ceil( $weight ) : $weight;

						// setup outgoing data for return
						$temp_ar = array(
							'subtotal' 			=> $this->get_line_item_price( $item_ar ),
							'quantity' 			=> $item_ar['quantity'],
							'weight' 			=> $weight,
							'height' 			=> $t_height * $item_ar['quantity'],
							'width' 			=> $t_width * $item_ar['quantity'],
							'length' 			=> $t_length * $item_ar['quantity'],
							'area' 				=> $t_area * $item_ar['quantity'],
							'volume' 			=> $t_volume * $item_ar['quantity'],
							'products' 			=> array( $product_id ),
							'shipping_classes' 	=> apply_filters( 'betrs_settings_shipping_class', array( $item->get_shipping_class_id() ) ),
							'categories' 		=> $categories,
							'status' 			=> $status,
							);

						if( isset( $data[ $item->get_id() ] ) ) {
							$data[ $item->get_id() ] += $temp_ar;
						} else {
							$data[ $item->get_id() ] = $temp_ar;
						}
					} else {
						$weight = $this->get_line_item_weight( $item_ar );
						$weight = ( $this->method->round_weight === 'yes' ) ? ceil( $weight ) : $weight;

						// setup outgoing data for return
						$temp_ar = array(
							'subtotal' 			=> $this->get_line_item_price( $item_ar ) / $item_ar['quantity'],
							'quantity' 			=> $item_ar['quantity'],
							'weight' 			=> $weight,
							'height' 			=> $t_height,
							'width' 			=> $t_width,
							'length' 			=> $t_length,
							'area' 				=> $t_area,
							'volume' 			=> $t_volume,
							'products' 			=> array( $product_id ),
							'shipping_classes' 	=> apply_filters( 'betrs_settings_shipping_class', array( $item->get_shipping_class_id() ) ),
							'categories' 		=> $categories,
							'status' 			=> $status,
							);

						if( isset( $data[ $item->get_id() ] ) ) {
							$data[ $item->get_id() ] = $this->array_add( $data[ $item->get_id() ], $temp_ar );
						} else {
							$data[ $item->get_id() ] = $temp_ar;
						}
					}

				}

			}

			return apply_filters( 'betrs_calculated_totals-per_item', $data, $items );

		}


		/**
		 * calculate order totals.
		 *
		 * @access public
		 * @param array $package (default: array())
		 * @return array
		 */
		function calculate_totals_class( $items ) {
			// setup empty return value
			$data = array();

			// cycle through cart items
			foreach( $items as $item_ar ) {

				// only count the ones that apply to shipping
				if( isset( $item_ar['data'] ) && $item_ar['data']->needs_shipping() ) {
					// initialize necessary variables
					$item = $item_ar['data'];
					$shipping_class_id = apply_filters( 'betrs_settings_shipping_class', $item->get_shipping_class_id() );

					// add additional product information
					if( $item->get_type() == 'variation' )
						$parent_id = ( version_compare( WC_VERSION, '3.0', ">=" ) ) ? $item->get_parent_id(): $item->parent->id;

					if( ! isset( $data[ $shipping_class_id ] ) ) {

						$data[ $shipping_class_id ] = array(
							'subtotal' 			=> 0,
							'quantity' 			=> 0,
							'weight' 			=> 0,
							'height' 			=> 0,
							'width' 			=> 0,
							'length' 			=> 0,
							'area' 				=> 0,
							'volume' 			=> 0,
							'products' 			=> array(),
							'shipping_classes' 	=> array( $shipping_class_id ),
							'categories' 		=> array(),
							'status'			=> array(),
							);
					}

					// manage measurement calculations
					$t_height = (float) apply_filters( 'betrs_calculated_item-height', $item->get_height(), $item_ar );
					$t_width = (float) apply_filters( 'betrs_calculated_item-width', $item->get_width(), $item_ar );
					$t_length = (float) apply_filters( 'betrs_calculated_item-length', $item->get_length(), $item_ar );
					$t_area = array_filter( array( $t_height, $t_width ) );
					$t_area = ( empty( $t_area ) ) ? 0 : array_product( $t_area );
					$t_volume = array_filter( array( $t_height, $t_width, $t_length ) );
					$t_volume = ( empty( $t_volume ) ) ? 0 : array_product( $t_volume );

					// add additional product information
					$get_categories = ( $item->get_type() == 'variation' ) ? get_the_terms( $parent_id, 'product_cat' ) : get_the_terms( $item->get_id(), 'product_cat' );
					if( $get_categories ) {
						foreach( $get_categories as $cat ){
						   $data[ $shipping_class_id ]['categories'][] = $cat->term_id;
						}
					}
					$data[ $shipping_class_id ]['status'][] = $item->get_stock_status();

					// calculate product weight based on settings
					$weight = $this->get_line_item_weight( $item_ar ) * $item_ar['quantity'];
					$weight = ( $this->method->round_weight === 'yes' ) ? ceil( $weight ) : $weight;

					// retrieve correct product ID
					$product_id = $item->get_id();
					if( $item->get_type() == 'variation' )
						$product_id = ( version_compare( WC_VERSION, '3.0', ">=" ) ) ? $item->get_parent_id(): $item->parent->id;

					// setup outgoing data for return
					$data[ $shipping_class_id ][ 'subtotal' ]		+= $this->get_line_item_price( $item_ar );
					$data[ $shipping_class_id ][ 'quantity' ]		+= $item_ar['quantity'];
					$data[ $shipping_class_id ][ 'weight' ]			+= $weight;
					$data[ $shipping_class_id ][ 'height' ]			+= $t_height * $item_ar['quantity'];
					$data[ $shipping_class_id ][ 'width' ]			+= $t_width * $item_ar['quantity'];
					$data[ $shipping_class_id ][ 'length' ]			+= $t_length * $item_ar['quantity'];
					$data[ $shipping_class_id ][ 'area' ]			+= $t_area * $item_ar['quantity'];
					$data[ $shipping_class_id ][ 'volume' ]			+= $t_volume * $item_ar['quantity'];
					$data[ $shipping_class_id ][ 'products' ][]		= $product_id;

				}

			}

			// clear out unnecessary data
			foreach( $data as $key => $value ) {
				$data[ $key ]['categories'] = array_unique( $value['categories'] );
			}

			return apply_filters( 'betrs_calculated_totals-per_class', $data, $items );
		}


		/**
		 * Find valid options for calculated cart data.
		 *
		 * @access public
		 * @param array $package (default: array())
		 * @return array
		 */
		function process_table_rates( $cart_data ) {
			global $betrs_shipping;
			
			// setup necessary variables
			$rates = array();
			if( ! empty( $cart_data ) && ! empty( $this->table_rates ) ) {
				// step through each table rate row
				foreach( $this->table_rates['settings'] as $o_key => $option ) {
					$cost = false;
					$description = "";
					$description_op = ( isset( $option['description'] ) && ! empty( $option['description'] ) ) ? wp_kses( $option['description'], $betrs_shipping->allowedtags ) : "";

					// skip processing if option is disabled
					if( isset( $option['disable_op'] ) && $option['disable_op'] === 'on' ) continue;

					foreach( $option['rows'] as $r_key => $row ) {

						if( ! empty( $row['conditions'] ) ) {
							$qualifies = false;
							$results = array();

							foreach( $row['conditions'] as $cond ) {
								$results[] = $this->determine_condition_result( $cond, $cart_data );
							}

							if( in_array( true, $results ) && !in_array( false, $results ) )
								$qualifies = true;

							if( $qualifies === true ) {

								// calculate costs for qualifying row
								$cost = $this->calculate_shipping_costs( $row['costs'], $cart_data );
								$description = $row['description'];
								$row_id = $r_key;

							}
						} else {
							$cost = $this->calculate_shipping_costs( $row['costs'], $cart_data );
							$description = $row['description'];
							$row_id = $r_key;
						}

					}

					// setup defaults for new fields
					$option_combine_desc = ( isset( $option['combine_desc'] ) ) ? sanitize_title( $option['combine_desc'] ) : 'no';

					// setup shipping option if cart qualifies
					if( $cost !== false ) {
						$option_id = $this->generate_option_id( $option['option_id'] );
						$processed_rate = array(
							'id'        		=> $option_id,
							'label'     		=> stripslashes( $option['title'] ),
							'cost'      		=> $cost,
							'description' 		=> $description,
							'description_op'	=> $description_op,
							'default'	 		=> $option['default'],
							'hide_ops'	 		=> $option['hide_ops'],
							'combine_desc'		=> $option_combine_desc,
							'row_id'			=> $row_id,
							);
						$rates[ $option['option_id'] ] = apply_filters( 'betrs_processed_rate', $processed_rate, $option, $o_key, $row_id );
					}
				}
			}

			return $rates;
		}


		/**
		 * Determine if cart information qualifies for given condition.
		 *
		 * @access public
		 * @param array $cond, array $cart_data
		 * @return bool
		 */
		function determine_condition_result( $cond, $cart_data ) {

			if( is_array( $cond ) && isset( $cond['cond_type'] ) ) {
				$cond_type = sanitize_title( $cond['cond_type'] );

				// perform the correct check based on condition type
				if( in_array( $cond_type, array( 'subtotal', 'quantity', 'weight', 'height', 'width', 'length', 'area', 'volume' ) ) ) {
					// allow third party plugins to adjust numbers conversion
					$cond_tertiary = (float) apply_filters( 'betrs_condition_tertiary_' . $cond_type, wc_format_decimal( $cond['cond_tertiary'] ), $cond );
					
					$epsilon = 0.001;

					if( isset( $cart_data[ $cond_type ] ) )
						$comparison = (float) $cart_data[ $cond_type ];
					else
						return false;

					switch( $cond['cond_secondary'] ) {
						case 'greater_than':
							if( $comparison >= $cond_tertiary || abs($cond_tertiary - $comparison) < $epsilon )
								return true;
							break;
						case 'less_than':
							if( $comparison < $cond_tertiary || abs($cond_tertiary - $comparison) < $epsilon )
								return true;
							break;
						case 'equal_to':
							if( abs($cond_tertiary - $comparison) < $epsilon )
								return true;
							break;
						
						default:
							return apply_filters( 'betrs_condition_secondary_numbers', false, $cond, $cart_data );
							break;
					}

				} elseif( in_array( $cond_type, array( 's_class', 'product', 'category', 'status' ) ) ) {
					$cond_tertiary = apply_filters( 'betrs_condition_tertiary_' . $cond_type, $cond['cond_tertiary'], $cond );
					
					switch( $cond_type ) {
						case 's_class':
							$comparison = apply_filters( 'betrs_comparison_tertiary_' . $cond_type, $cart_data['shipping_classes'], $cond );
							break;
						case 'product':
							$comparison = apply_filters( 'betrs_comparison_tertiary_' . $cond_type, $cart_data['products'], $cond );
							break;
						case 'category':
							$comparison = apply_filters( 'betrs_comparison_tertiary_' . $cond_type, $cart_data['categories'], $cond );
							break;
						case 'status':
							$comparison = apply_filters( 'betrs_comparison_tertiary_' . $cond_type, $cart_data['status'], $cond );
							break;
						
						default:
							return apply_filters( 'betrs_condition_secondary_classes', false, $cond, $cart_data );
							break;
					}

					if( is_array( $comparison ) ) {
						if( is_array( $cond_tertiary ) ) {
							if( $cond['cond_secondary'] === 'includes' ) {
								foreach( $comparison as $comp ) {
									if( in_array( $comp, $cond_tertiary ) )
										return true;
								}
							}

							if( $cond['cond_secondary'] === 'excludes' ) {
								$temp = true;
								foreach( $comparison as $comp ) {
									if( in_array( $comp, $cond_tertiary ) )
										$temp = false;
								}

								return $temp;
							}

						} else {

							if( $cond['cond_secondary'] === 'includes' && in_array( $cond_tertiary, $comparison ) )
								return true;

							if( $cond['cond_secondary'] === 'excludes' && ! in_array( $cond_tertiary, $comparison ) )
								return true;
							
						}
					}

				} elseif( $cond_type == 'dates' ) {
					$dates = json_decode( stripslashes( $cond['cond_secondary'] ) );

					if( isset( $dates->start ) && isset( $dates->end ) ) {
						// convert dates to timestamps
						$start_date = strtotime( $dates->start );
						$end_date = strtotime( $dates->end );
						$now = current_time('timestamp');

						// Check that user date is between start & end
						return ( ( $now >= $start_date ) && ( $now <= $end_date ) );
					}

				} elseif( $cond_type == 'times' ) {
					
					$time_current = current_time('timestamp');
					$time_conditional = strtotime( sanitize_text_field( $cond['cond_tertiary'] ) );

					switch( sanitize_title( $cond['cond_secondary'] ) ) {
						case 'after':
							if( $time_current > $time_conditional )
								return true;
							break;
						case 'before':
						default:
							if( $time_current < $time_conditional )
								return true;
							break;
					}

					return false;

				} elseif( $cond_type == 'dayweek' ) {
					
					if( sanitize_title( $cond['cond_secondary'] ) == date( 'w' ) )
						return true;

				} elseif( $cond_type == 'coupon' ) {

					if( $cond['cond_secondary'] == 'betrs_free_ship' ) {
						// check if free shipping is enabled
						$applied_coupons = WC()->cart->get_applied_coupons();
						foreach( $applied_coupons as $cp ) {
							$c = new WC_Coupon( $cp );
							if( $c->get_free_shipping() )
								return true;
						}
					} else {
						// check for custom coupon code entered
						$coupon = WC()->cart->has_discount( $cond['cond_tertiary'] );
						if( ( $cond['cond_secondary'] === 'excludes' && ! $coupon ) ||
							( $cond['cond_secondary'] === 'includes' && $coupon ) )
							return true;
					}

					return false;

				} else {

					return apply_filters( 'betrs_determine_condition_result', false, $cond, $cart_data );
				}

			}

			return false;
		}


		/**
		 * Determine if cart information qualifies for given condition.
		 *
		 * @access public
		 * @param array $cond, array $cart_data
		 * @return float
		 */
		function calculate_shipping_costs( $costs, $cart_data ) {
			if( ! is_array( $costs ) ) return 0;

			// cycle through the different cost options
	        $cost_ops = apply_filters( 'betrs_shipping_cost_options', array(
	                ''          => get_woocommerce_currency_symbol(),
	                '%'         => '%',
	                'x'         => esc_html__( 'multiplied by', 'be-table-ship' ),
	                'every'     => esc_html__( 'for every', 'be-table-ship' ),
	            ) );
	        $calcs = array();

	        foreach( $costs as $cost ) {

		        switch ( $cost['cost_type'] ) {
		        	case '':
		        		$calcs[] = $cost['cost_value'];
		        		break;
		        	case '%':
		        		$calcs[] = $cart_data['subtotal'] * ( $cost['cost_value'] / 100 );
		        		break;
		        	case 'x':
		        		$calcs[] = $cost['cost_value'] * $cart_data[ $cost['cost_op_extra'] ];
		        		break;
		        	case 'every':
		        		if( $cost['cost_op_extra'] === 'dimensions' ) {
		        			// determine which dimensional value to multiply by
		        			if( isset( $cart_data[ $cost['cost_op_extra_secondary'] ] ) ) {
		        				$calcs[] = ceil( $cart_data[ $cost['cost_op_extra_secondary'] ] / $cost['cost_op_extra_val'] ) * $cost['cost_value'];
		        			}
		        		} else {
		        			// calculate the value based on select data
		        			if( isset( $cart_data[ $cost['cost_op_extra'] ] ) ) {
		        				$calcs[] = ceil( $cart_data[ $cost['cost_op_extra'] ] / $cost['cost_op_extra_val'] ) * $cost['cost_value'];
		        			}
		        		}
		        		break;
		        	
		        	default:
		        		$calcs[] = (float) apply_filters( 'betrs_determine_cost_result', $cost['cost_value'], $cost['cost_type'], $cost );
		        		break;
		        }

	        }

	        return array_sum( array_map( 'floatval', $calcs ) );
		}


		/**
		 * determine item price based on TRS tax and coupon settings.
		 *
		 * @access public
		 * @param array $item
		 * @return float
		 */
		function get_line_item_price( $item ) {
			$return_cost = 0;

			if( $this->method->include_coupons === 'yes' ) {
				if( $this->method->includetax === 'yes' ) {
					$return_cost = $item['line_total'] + $item['line_tax'];
				} else {
					$return_cost = $item['line_total'];
				}
			} else {
				if( $this->method->includetax === 'yes' ) {
					$return_cost = $item['line_subtotal'] + $item['line_subtotal_tax'];
				} else {
					$return_cost = $item['line_subtotal'];
				}
			}

			return wc_format_decimal( apply_filters( 'betrs_calculated_item-price', $return_cost, $item, $this->method ), wc_get_price_decimals() );
		}


		/**
		 * determine item weight based on TRS volumetric settings.
		 *
		 * @access public
		 * @param array $item
		 * @return float
		 */
		function get_line_item_weight( $item_ar ) {
			// setup item
			$item = $item_ar['data'];

			// set default weight
			$weight = $item->get_weight();

			if( isset( $this->method->volumetric_number ) && is_numeric( $this->method->volumetric_number ) && $this->method->volumetric_number > 0 ) {
				// allow third party plugin overrides when necessary
				$t_height = (float) apply_filters( 'betrs_calculated_item-height', $item->get_height(), $item_ar );
				$t_width = (float) apply_filters( 'betrs_calculated_item-width', $item->get_width(), $item_ar );
				$t_length = (float) apply_filters( 'betrs_calculated_item-length', $item->get_length(), $item_ar );

				// dimensional check
				if( isset( $this->method->volumetric_dim_rec ) && $this->method->volumetric_dim_rec == 'yes' ) {
					if( $t_height === '' && $t_width === '' && $t_length === '' ) {
						return (float) apply_filters( 'betrs_calculated_item-weight', $weight, $item_ar );
					}
				}

				// manage measurement calculations
				$t_volume = array_filter( array( $t_height, $t_width, $t_length ) );
				$volume = ( empty( $t_volume ) ) ? 0 : array_product( $t_volume );

				if( $this->method->volumetric_operand === 'multiply' ) {
					$volumetric = $volume * $this->method->volumetric_number;
				} elseif( $volume > 0 ) {
					$volumetric = $volume / $this->method->volumetric_number;
				} else {
					$volumetric = 0;
				}

				if( $this->method->volumetric_exclude == 'yes' || $volumetric > $item->get_weight() )
					$weight = $volumetric;

			}

			return (float) apply_filters( 'betrs_calculated_item-weight', $weight, $item_ar );
		}


		/**
		 * Combine numeric values of array.
		 *
		 * @access public
		 * @param array $array_1, array $array_2
		 * @return array
		 */
		function array_add( $array_1, $array_2 ) {
			// cycle through array 1 keys
			if( is_array( $array_1 ) && is_array( $array_2 ) ) {
				foreach( $array_1 as $key => $value ) {
					if( isset( $array_2[ $key ] ) && is_numeric( $array_1[ $key ] ) && is_numeric( $array_2[ $key ] ) ) {
						$array_1[ $key ] += $array_2[ $key ];
					}
				}
			}

			return $array_1;
		}


		/**
		 * Setup shipping option ID tag.
		 *
		 * @access public
		 * @param int $option_id
		 * @return string
		 */
		function generate_option_id( $option_id ) {
			$option_id = (int) $option_id;

			return $this->method->id . ':' . $this->method->instance_id . '-' . $option_id;
		}

	}

}

?>