types = Array(
'percent_total_amount' => 'Percentage of cart total amount',
'percent_product_price' => 'Percentage of product price',
'fixed_product_price' => 'Fixed price of product price',
'fixed_cart_amount' => 'Fixed price of cart total amount',
);
}
/**
*
* Ensures only one instance of AWDP is loaded or can be loaded.
*
* @since 1.0.0
* @static
* @see WordPress_Plugin_Template()
* @return Main AWDP instance
*/
public static function instance($file = '', $version = '1.0.0')
{
if (is_null(self::$_instance)) {
self::$_instance = new self($file, $version);
}
return self::$_instance;
}
/**
* @return bool
*/
public function isActive()
{
return $this->_active;
}
public function cart_discount_items( $item_price, $cart_item )
{
$prod_ID = $cart_item['data']->get_data()['slug'];
$discounted_price = abs(wc_remove_number_precision($this->discounted_price[$prod_ID]));
$actual_price = $cart_item['data']->get_data()['price'];
$quantity = $cart_item['quantity'];
if( $discounted_price > 0.0000000001 && ( $discounted_price < $actual_price ) ) {
$item_price = '';
$item_price .= '';
$item_price .= ''.wc_price($actual_price).'';
$item_price .= ''. wc_price($discounted_price).'';
} else if( $discounted_price > $actual_price ) {
$item_price = '';
$item_price .= '';
$item_price .= ''.wc_price($actual_price).'';
$item_price .= ''. wc_price($discounted_price).'';
}
return $item_price;
}
public function get_product_price_html($item_price, $product)
{
// $latest_price = $product->get_data()['price'] - wc_remove_number_precision($_discounts[$product->get_data()['slug']]);
$prod_ID = $product->get_data()['slug'];
$latest_price = abs(wc_remove_number_precision($this->discounted_price[$prod_ID]));
$actual_price = $product->get_data()['price'];
if( $latest_price > 0.0000000001 && ( $latest_price < $actual_price ) ) {
$item_price = '';
$item_price .= '';
$item_price .= ''.wc_price($actual_price).'';
$item_price .= ''. wc_price($latest_price).'';
} else if( $latest_price > $actual_price ) {
$item_price = '';
$item_price .= '';
$item_price .= ''.wc_price($actual_price).'';
$item_price .= ''. wc_price($latest_price).'';
}
return $item_price;
}
public function get_product_price($price, $product)
{
if($product) {
$id = $product->get_id();
if (isset($this->product_lists[$id])) {
return $this->product_lists[$id]['price'];
}
return $this->calculate_discount($price, $product);
}
}
public function calculate_discount( $price, $product )
{
$this->load_rules();
$products_with_discount = [];
global $woocommerce;
$this->discounted_price[$product->get_data()['slug']] = -0.0000000001;
foreach ($this->discount_rules as $k => $rule) {
//validate cart based rules
if (!$this->validate_discount_rules($product, $rule, ['cart_total_amount', 'cart_items', 'cust_prev_order_count'])) {
continue;
}
if(!$this->get_items_to_apply_discount($product, $rule)){
continue;
}
if (!isset($this->discounts[$rule['id']])) {
$this->discounts[$rule['id']] = ['label' => $rule['label'], 'discount_type' => $rule['type'], 'discount_remainder' => -1];
}
// calculating discount
if('percent_product_price' == $rule['type'])
$this->apply_discount_percent_product_price($rule, $product);
else if('fixed_product_price' == $rule['type'])
$this->apply_discount_fixed_product_price($rule, $product);
else if ('percent_total_amount' == $rule['type'])
$this->apply_discount_percent_total_amount($rule, $product);
else if ('fixed_cart_amount' == $rule['type'])
$this->apply_discount_fixed_price_total_amount($rule, $product);
}
$_discounts = array();
foreach ($this->discounts as $discounts) {
if($discounts['discount_type'] == 'percent_product_price' || $discounts['discount_type'] == 'fixed_product_price'){
foreach ($discounts['discounts'] as $key => $discount) {
if (!isset($_discounts[$key])) {
$_discounts[$key] = 0.0;
}
$_discounts[$key] += $discount;
}
}
}
if($product->get_data()['price'] >= wc_remove_number_precision($_discounts[$product->get_data()['slug']]))
$latest_price = $product->get_data()['price'] - wc_remove_number_precision($_discounts[$product->get_data()['slug']]);
else
$latest_price = 0;
return $latest_price;
}
public function load_rules()
{
if ($this->discount_rules === false) {
$datenow = date("Y-m-d");
$awdp_discount_args = array(
'post_type' => AWDP_POST_TYPE,
'post_status' => 'publish',
'posts_per_page' => -1,
'meta_key' => 'discount_priority', //setting the meta_key which will be used to order
'orderby' => 'meta_value_num', //if the meta_key (population) is numeric use meta_value_num instead
'order' => 'ASC', //setting order direction
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'discount_status',
'value' => 1,
'compare' => '=',
'type' => 'NUMERIC'
),
array(
'key' => 'discount_start_date',
'value' => $datenow,
'compare' => '<=',
'type' => 'DATE'
),
array(
'relation' => 'OR',
array(
'key' => 'discount_end_date',
'value' => $datenow,
'compare' => '>=',
'type' => 'DATE'
),
array(
'key' => 'discount_end_date',
'compare' => 'NOT EXISTS',
),
array(
'key' => 'discount_end_date',
'value' => '',
'compare' => '=',
),
)
)
);
$awdp_discount_rules = get_posts($awdp_discount_args);
$discount_rules = array();
foreach ($awdp_discount_rules as $rule) {
$rule_type = get_post_meta($rule->ID, 'discount_type', true);
$discount_config = get_post_meta($rule->ID, 'discount_config', true);
$discount_rules[] = array(
'id' => $rule->ID,
'label' => ($discount_config['label'] != '') ? $discount_config['label'] : $rule->post_title,
'discount' => get_post_meta($rule->ID, 'discount_value', true),
'inc_tax' => $discount_config['inc_tax'],
'disable_on_sale' => $discount_config['disable_on_sale'],
'sequentially' => $discount_config['sequentially'],
'product_list' => get_post_meta($rule->ID, 'discount_product_list', true),
'rules' => unserialize(base64_decode($discount_config['rules'])),
'type' => $rule_type,
);
}
$this->discount_rules = $discount_rules;
}
}
public function validate_discount_rules($cart_obj, $rule, $rules_to_validate = array(), $item = false)
{
$evel_str = '';
// $rules_to_validate = ['cart_total_amount', 'cart_items', 'cust_prev_order_count'];
$result = true;// if no rules, the validation must be true
if (isset($rule['rules']) && is_array($rule['rules']) && !empty($rule['rules'])) {
foreach ($rule['rules'] as $val) {
if (is_array($val['rules']) && count($val['rules']) && !empty($val['rules'])) {
// echo 'rule';
$evel_str .= '(';
foreach ($val['rules'] as $rul) {
$evel_str .= '(';
if (in_array($rul['rule']['item'], $rules_to_validate)) {
if ($this->eval_rule($rul['rule'], $cart_obj, $item)) {
$evel_str .= ' true ';
} else {
$evel_str .= ' false ';
}
} else {
$evel_str .= ' true ';
}
$evel_str .= ') ' . (($rul['operator'] !== false) ? $rul['operator'] : '') . ' ';
}
if (count($val['rules']) > 0 && !empty($val['rules'])) {
preg_match_all('/\(.*\)/', $evel_str, $match);
$evel_str = $match[0][0] . ' ';
}
$evel_str .= ') ' . (($val['operator'] !== false) ? $val['operator'] : '') . ' ';
}
}
if (count($rule['rules']) > 0 && !empty($rule['rules']) && $evel_str != '') {
preg_match_all('/\(.*\)/', $evel_str, $match);
$evel_str = $match[0][0] . ' ';
}
$evel_str = str_replace(['and', 'or'], ['&&', '||'], $evel_str);
if ($evel_str !== '') {
$result = eval('return ' . $evel_str . ';');
}
}
return $result;
}
public function eval_rule($rule, $cart_obj, $item = false)
{
if ('cart_total_amount' == $rule['item']) {
// $item_val = $cart_obj->get_total();
$item_val = (float)WC()->cart->total;
$rel_val = (float)$rule['value'];
} else if ('product_price' == $rule['item']) {
// $item_val = $item['data']->get_price('edit');
$item_val = (float)$item->get_data()['price'];
$rel_val = (float)$rule['value'];
} else {
return false;
}
switch ($rule['condition']) {
case 'equal_to':
if (@abs(($item_val - $rel_val) / $item_val) < 0.00001) {
return true;
}
break;
case 'less_than':
if ($item_val < $rel_val) {
return true;
}
break;
case 'less_than_eq':
if ($item_val < $rel_val || abs(($item_val - $rel_val) / $item_val) < 0.0001) {
return true;
}
break;
case 'greater_than':
if ($item_val > $rel_val) {
return true;
}
break;
case 'greater_than_eq':
if ($item_val > $rel_val || abs(($item_val - $rel_val) / $item_val) < 0.0001) {
return true;
}
break;
}
return false;
}
public function get_items_to_apply_discount($product, $rule)
{
$items = array();
global $woocommerce;
//validate with $rule
if (!$this->check_in_product_list($product, $rule)) {
return false;
}
if (!$this->validate_discount_rules($product, $rule, ['product_price'], $product)) {
return false;
}
if (isset($rule['disable_on_sale']) && $rule['disable_on_sale'] && $product->is_on_sale('edit')) {
return true;
}
return true;
}
public function check_in_product_list($product, $rule)
{
if (0 == $rule['product_list']) {
return true;
} else {
$this->set_product_list();
$pro_id = $product->get_data()['parent']; // in case of variation
if ($pro_id == 0) {
$pro_id = $product->get_id();
}
return isset($this->product_lists[$rule['product_list']]) &&
in_array($pro_id, $this->product_lists[$rule['product_list']]);
}
}
public function set_product_list()
{
if (false == $this->product_lists) {
if (false === ($product_lists = get_transient(AWDP_PRODUCTS_TRANSIENT_KEY))) {
$post_type = AWDP_PRODUCT_LIST;
global $wpdb;
$product_lists = array();
$lists = $wpdb->get_col($wpdb->prepare("
SELECT pm.meta_value FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = '%s'
AND p.post_status = '%s'
AND p.post_type = '%s'
", 'discount_product_list', 'publish', AWDP_POST_TYPE));
$post_ids = get_posts(
array(
'fields' => 'ids',
'post_type' => AWDP_PRODUCT_LIST,
'post__in' => $lists,
'posts_per_page' => -1,hu
)
);
foreach ($post_ids as $id) {
$list_type = get_post_meta($id, 'list_type', true);
$other_config = get_post_meta($id, 'product_list_config', true);
// $other_config = array(
// 'selectedProducts' => serialize($data['selectedProducts']),
// 'productAuthor' => serialize($data['productAuthor']),
// 'excludedProducts' => serialize($data['excludedProducts']),
// 'taxRelation' => serialize($data['taxRelation']),
// 'rules' => serialize($data['rules']),
// );
$product_lists[$id] = array();
if ('products_selection' == $list_type) {
$product_lists[$id] = ($other_config['selectedProducts']);
} else {
$tax_rules = ($other_config['rules']);
$tax_rules = ($tax_rules && is_array($tax_rules) && !empty($tax_rules)) ? $tax_rules : false;
$excludedProducts = ($other_config['excludedProducts']);
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
'post__not_in' => $excludedProducts
);
if (false !== $tax_rules) {
if (isset($tax_rules[0]['rules']) && is_array($tax_rules[0]['rules'])) {
$tax_query = array(
'relation' => ('or' == strtolower($other_config['taxRelation'])) ? 'OR' : 'AND'
);
foreach ($tax_rules[0]['rules'] as $tr) {
$tax_query[] = array(
'taxonomy' => $tr['rule']['item'],
'field' => 'term_id',
'terms' => $tr['rule']['value'],
);
}
$args['tax_query'] = $tax_query;
}
}
$query = new WP_Query($args);
$product_lists[$id] = wp_list_pluck($query->posts, 'ID');
}
}
set_transient(AWDP_PRODUCTS_TRANSIENT_KEY, $product_lists, 7 * 24 * HOUR_IN_SECONDS);
}
$this->product_lists = $product_lists;
}
}
// public function validate_product_rules($cart_obj, $item, $rule)
// {
// $evel_str = '';
// $rules_to_validate = ['product_price'];
// $result = true;// if no rules, the validation must be true
// if (isset($rule['rules']) && is_array($rule['rules'])) {
// foreach ($rule['rules'] as $val) {
// $evel_str .= '(';
// if (is_array($val['rules']) && count($val['rules'])) {
// foreach ($val['rules'] as $rul) {
// $evel_str .= '(';
// if (in_array($rul['rule']['item'], $rules_to_validate)) {
// if ($this->eval_rule($rul['rule'], $cart_obj, $item)) {
// $evel_str .= ' true ';
// } else {
// $evel_str .= ' false ';
// }
// } else {
// $evel_str .= ' true ';
// }
//
// $evel_str .= ') ' . (($rul['operator'] !== false) ? $rul['operator'] : '') . ' ';
// }
//
// if (count($val['rules']) > 0) {
// preg_match_all('/\(.*\)/', $evel_str, $match);
// $evel_str = $match[0][0] . ' ';
// }
//
// $evel_str .= ') ' . (($val['operator'] !== false) ? $val['operator'] : '') . ' ';
// }
// }
//
// if (count($val['rules']) > 0) {
// preg_match_all('/\(.*\)/', $evel_str, $match);
// $evel_str = $match[0][0] . ' ';
// }
//
// $evel_str = str_replace(['and', 'or'], ['&&', '||'], $evel_str);
// $result = eval('return ' . $evel_str . ';');
// }
// return $result;
// }
// Cart Total Discount ///////////////////////////////
public function apply_discount_percent_total_amount($rule, $item)
{
$total_discount = 0;
$cart_total = 0;
$prod_ID = $item->get_data()['slug']; //var_dump($item->get_data()['slug']);
if($this->discounted_price[$prod_ID] != '' && $this->discounted_price[$prod_ID] >= 0) {
$price_to_discount = $this->discounted_price[$prod_ID];
} else {
// Find out how much price is available to discount for the item.
// $discounted_price = $this->get_discounted_price_in_cents($item, $rule['inc_tax'], true);
// $actual_price = $this->get_discounted_price_in_cents($item, $rule['inc_tax'], false);
// $price_to_discount = ($rule['sequentially']) ? $discounted_price : $actual_price; // check if apply_ sequential
$price_to_discount = wc_add_number_precision($item->get_data()['price']);
}
$discount = $price_to_discount * ((int)$rule['discount'] / 100);
$discount = min($price_to_discount, $discount);
// Store code and discount amount per item.
$cart_total = $cart_total + $price_to_discount;
$total_discount = $total_discount + $discount;
// $prod_ID = $item->get_data()['slug'];
if(!$this->discounts[$rule['id']]['discount_applied'][$prod_ID]) {
$this->discounts[$rule['id']]['discounts'][$prod_ID] += $discount;
$this->discounts[$rule['id']]['discount_applied'][$prod_ID] = true;
}
// $cart_total_discount = wc_round_discount($cart_total * ($rule['discount'] / 100), 0);
// if ($total_discount < $cart_total_discount) {
// $this->apply_discount_remainder($rule, $items_to_apply, $cart_total_discount - $total_discount);
// }
}
public function apply_discount_fixed_price_total_amount($rule, $item)
{
$total_discount = 0;
$cart_total = 0;
$prod_ID = $item->get_data()['slug'];
if($this->discounted_price[$prod_ID] != '' && $this->discounted_price[$prod_ID] >= 0) {
$price_to_discount = $this->discounted_price[$prod_ID];
} else {
// $price_to_discount = wc_add_number_precision($this->get_discounted_price_in_cents($item, $rule['inc_tax'], false));
$price_to_discount = wc_add_number_precision($item->get_data()['price']);
}
$discount = wc_add_number_precision($rule['discount']);
if($this->discounts[$rule['id']]['discount_remainder'] >= 0){
$discount = $this->discounts[$rule['id']]['discount_remainder'];
}
if(intval($price_to_discount) >= $discount && $discount > 0) {
$discounted_price = $price_to_discount - $discount;
$product_discount = $discount;
$this->discounts[$rule['id']]['discount_remainder'] = 0;
} else if(intval($price_to_discount) < $discount && $discount > 0){
$discounted_price = $price_to_discount;
$product_discount = $discounted_price;
$this->discounts[$rule['id']]['discount_remainder'] = $discount - $price_to_discount;
} else {
$product_discount = 0;
}
if(!$this->discounts[$rule['id']]['discount_applied'][$prod_ID]) {
$this->discounts[$rule['id']]['discounts'][$prod_ID] += $product_discount;
$this->discounts[$rule['id']]['discount_applied'][$prod_ID] = true;
}
}
// Product Based Discounts ////////////////////////////////
public function apply_discount_fixed_product_price($rule, $item)
{
// $total_discount = 0;
// $cart_total = 0;
// $single_discount_amount = 0;
// global $woocommerce;
$prod_ID = $item->get_data()['slug'];
if($this->discounted_price[$prod_ID] != '' && $this->discounted_price[$prod_ID] >= 0) {
$product_original_price = $this->discounted_price[$prod_ID];
} else {
// $product_original_price = $this->get_individual_discounted_price_in_cents($item, $rule['inc_tax'], false);]
// $product_original_price = wc_add_number_precision($item->get_data()['price']);
$product_original_price = wc_add_number_precision($item->get_data()['price']);
}
$discount_amount = wc_add_number_precision($rule['discount']);
if($product_original_price >= $discount_amount) {
$updated_product_price = $product_original_price - $discount_amount;
$single_discount_amount = $discount_amount;
} else {
$updated_product_price = 0;
$single_discount_amount = $product_original_price;
}
if(!$this->discounts[$rule['id']]['discount_applied'][$prod_ID]) {
$this->discounts[$rule['id']]['discounts'][$prod_ID] += $single_discount_amount;
$this->discounts[$rule['id']]['discount_applied'][$prod_ID] = true;
}
$this->discounted_price[$prod_ID] = $updated_product_price;
// $cart_total = $cart_total + $discounted_price;
}
public function apply_discount_percent_product_price($rule, $item)
{
$total_discount = 0;
$cart_total = 0;
global $woocommerce;
$prod_ID = $item->get_data()['slug'];
if($this->discounted_price[$prod_ID] != '' && $this->discounted_price[$prod_ID] >= 0) {
$product_original_price = $this->discounted_price[$prod_ID];
} else {
// Find out how much price is available to discount for the item.
// $discounted_price = $this->get_individual_discounted_price_in_cents($item, $rule['inc_tax'], true);
// $actual_price = $this->get_individual_discounted_price_in_cents($item, $rule['inc_tax'], false); // sequential
// $product_original_price = ($rule['sequentially']) ? $discounted_price : $actual_price; // check if apply_ sequential
$product_original_price = wc_add_number_precision($item->get_data()['price']);
}
$discount = floor($product_original_price * ($rule['discount'] / 100));
// $discount = min($discounted_price, $discount);
if($product_original_price >=$discount)
$updated_product_price = $product_original_price - $discount;
else
$updated_product_price = 0;
if(!$this->discounts[$rule['id']]['discount_applied'][$prod_ID]) {
$this->discounts[$rule['id']]['discounts'][$prod_ID] += $discount;
$this->discounts[$rule['id']]['discount_applied'][$prod_ID] = true;
}
$this->discounted_price[$prod_ID] = $updated_product_price;
}
/////////////////////////////
public function get_discounted_price_in_cents($item, $include_tax = true, $sequential = false)
{
$actual_price = $item->get_data()['price'];
if ($include_tax) {
$price = wc_get_price_including_tax($item, array(
'price' => $actual_price,
));
} else {
$price = wc_get_price_excluding_tax($item, array(
'price' => $actual_price,
));
}
if($sequential)
return absint(round($price - wc_remove_number_precision($this->get_discount($item->get_id(), true))));
else
return $price;
}
public function get_individual_discounted_price_in_cents($item, $include_tax = true, $sequential = false)
{
$latest_price = '';
if ($include_tax) {
$price = wc_get_price_including_tax($item, array(
'price' => $item->get_data()['price'],
));
} else {
$price = wc_get_price_excluding_tax($item, array(
'price' => $item->get_data()['price'],
));
}
if($sequential)
return absint(round($price - $this->get_discount($item->get_id(), true)));
else
return $price;
}
public function get_discount($key, $in_cents = false)
{
$item_discount_totals = $this->get_discounts_by_item($in_cents);
return isset($item_discount_totals[$key]) ? $item_discount_totals[$key] : 0;
}
public function get_discounts_by_item($in_cents = false)
{
$discounts = $this->discounts;
$item_discount_totals = array();
foreach ($discounts as $item_discounts) {
if($item_discounts['discounts']){
foreach ($item_discounts['discounts'] as $item_key => $item_discount) {
if (!isset($item_discount_totals[$item_key])) {
$item_discount_totals[$item_key] = 0.0;
}
$item_discount_totals[$item_key] += $item_discount;
}
}
}
return $in_cents ? $item_discount_totals : $item_discount_totals;
}
protected function apply_discount_remainder($rule, $items_to_apply, $amount)
{
$total_discount = 0;
foreach ($items_to_apply as $item) {
for ($i = 0; $i < $item->quantity; $i++) {
// Find out how much price is available to discount for the item.
$discounted_price = $this->get_discounted_price_in_cents($item);
// $price_to_discount = (false) ? $discounted_price : $item->price;// check if apply_ sequential
$discount = min($discounted_price, 1);
// Store totals.
$total_discount += $discount;
// Store code and discount amount per item.
$this->discounts[$rule['id']]['discounts'][$item->key] += $discount;
if ($total_discount >= $amount) {
break 2;
}
}
if ($total_discount >= $amount) {
break;
}
}
return $total_discount;
}
public function show_discounts($cart_obj)
{
if (is_admin() && !defined('DOING_AJAX'))
return;
$cart_contents = $cart_obj->get_cart();
$prod_QNT = [];
foreach($cart_contents as $cart_content){
$prod_QNT[$cart_content['data']->get_data()['slug']] = $cart_content['quantity'];
}
global $woocommerce;
$_discounts = array();
foreach ($this->discounts as $discounts) {
if($discounts['discount_type'] == 'percent_total_amount' || $discounts['discount_type'] == 'fixed_cart_amount'){
$total = 0;
foreach ($discounts['discounts'] as $key => $discount) {
$total = $total + ( wc_remove_number_precision($discount) * $prod_QNT[$key] );
}
if ( $total > 0 ) {
$woocommerce->cart->add_fee($discounts['label'], $total * -1);
}
}
}
}
/**
* Cloning is forbidden.
*
* @since 1.0.0
*/
public function __clone()
{
_doing_it_wrong(__FUNCTION__, __('Cheatin’ huh?'), $this->_version);
}
/**
* Unserializing instances of this class is forbidden.
*
* @since 1.0.0
*/
public function __wakeup()
{
_doing_it_wrong(__FUNCTION__, __('Cheatin’ huh?'), $this->_version);
}
}