/ Плагины / Акция 20% на каждый 3 и 30% на каждый 4 товар

Акция 20% на каждый 3 и 30% на каждый 4 товар

30.01.2021

345

Поступила нестандартная задача, реализовать акцию 20% на каждый 3 и 30% на каждый 4 товар. Сложность заключалась в том что скидки 20% и 30% должны были действовать на товары начиная с самого дешевого, т.е. первая скидка (20% за 3 товар) на самый дешевый, далее (30% за 4 товар) на второй товар с конца и т.д. Причем в расчете товаров для акции нужно было учитывать каждую единицу позиций (и количество каждой позиции и количество наименований) в пределах определенной категории.

Основной расчет акции (первая версия)

add_action( 'woocommerce_cart_calculate_fees','wc_custom_surcharge', 10, 1 );
function wc_custom_surcharge( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;
		
	foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
		
		// Условие категории
		
		$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
		
		if ( $_product->get_type() == 'simple' ) {
			
			$terms = get_the_terms( $_product->get_ID(), 'product_cat' );
			
		} elseif ( $_product->get_type() == 'variation' ) {
			
			$variation = wc_get_product($_product->get_ID());
			$varproduct = wc_get_product( $variation->get_parent_id() );
			$terms = get_the_terms( $varproduct->get_ID(), 'product_cat' );
			
		}
		
		if ($terms[0]->slug == 'compact-disc') { // если категория
		
			$prices[] = array(
				'cust_id' => $_product->get_ID(), 
				'cust_price' => $_product->get_price(),
				'cust_quantity' => $cart_item['quantity']
			);
			
			$action_quantity[] = $cart_item['quantity'];
		
		}
		
	}

	//asort($prices); // сортировка массива с сохранением ключей
	//sort($prices); // сортировка массива без сохранения ключей	
	
	// сортировка 2-х мерного массива по ключу
	usort($prices, function($a, $b) {
		return $a['cust_price'] <=> $b['cust_price'];
	});

	$fee_descript = '';
	$fee = 0;

	if (array_sum($action_quantity) == 3 ) {
		
		$fee = $prices[0]['cust_price'] * 0.2;
		$fee_descript = 'Скидка 20% на третий товар';
		
	} elseif (array_sum($action_quantity) >= 4) { 
	
		if (count($prices) == 1) {
			
			$fee = ($prices[0]['cust_price'] * 0.2) + ($prices[0]['cust_price'] * 0.3);
			$fee_descript = 'Скидка 20% на третий и 30% на четвертый товары';
			
		} else {
			
			if ($prices[0]['cust_quantity'] == 1) {
				
				$fee = ($prices[0]['cust_price'] * 0.2) + ($prices[1]['cust_price'] * 0.3);
				$fee_descript = 'Скидка 20% на третий и 30% на четвертый товары';
				
			} else {
				
				$fee = ($prices[0]['cust_price'] * 0.2) + ($prices[0]['cust_price'] * 0.3);
				$fee_descript = 'Скидка 20% на третий и 30% на четвертый товары';
				
			}
			
		}
		
	}

	$cart->add_fee( __($fee_descript, 'woocommerce'), -$fee, true );
}
Различные варианты сортировки:

asort($prices); // сортировка массива с сохранением ключей
sort($prices); // сортировка массива без сохранения ключей	

usort($prices, function($a, $b) { //сортировка 2-х мерного массива по ключу
	return $a['cust_price'] <=> $b['cust_price'];
});

Вывод уведомление о сумме скидки в корзине (первая версия)

В некоторых шаблонах данный вывод не нужен, т.к. в первой функции есть вывод общей суммы скидки, но выводится он в шаблоне Оформление.

add_action( 'woocommerce_before_cart_totals','print_message_wc_custom_surcharge', 7, 1 );

function print_message_wc_custom_surcharge() {
	
	foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
		
		$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );		
		
		if ( $_product->get_type() == 'simple' ) {
			
			$terms = get_the_terms( $_product->get_ID(), 'product_cat' );
			
		} elseif ( $_product->get_type() == 'variation' ) {
			
			$variation = wc_get_product($_product->get_ID());
			$varproduct = wc_get_product( $variation->get_parent_id() );
			$terms = get_the_terms( $varproduct->get_ID(), 'product_cat' );
			
		}
		
		if ($terms[0]->slug == 'compact-disc') { // если категория
			
			$prices[] = array(
				'cust_id' => $_product->get_ID(), 
				'cust_price' => $_product->get_price(),
				'cust_quantity' => $cart_item['quantity']
			);
			
			$action_quantity[] = $cart_item['quantity'];
		
		}
		
	}

	//asort($prices); // сортировка массива с сохранением ключей
	//sort($prices); // сортировка массива без сохранения ключей	
	
	// сортировка 2-х мерного массива по ключу
	usort($prices, function($a, $b) {
		return $a['cust_price'] <=> $b['cust_price'];
	});
	
	$symbol = get_woocommerce_currency_symbol('RUB');
	
	echo '<div class="discount-message">';

	if (array_sum($action_quantity) == 3 ) {
		
		$skidka = $prices[0]['cust_price'] * 0.2;
		echo '<p>скидка 20% на третий товар: <strong>'.round($skidka, 2).' '.$symbol.'</strong></p>';
		
	} elseif (array_sum($action_quantity) >= 4) { 

		if (count($prices) == 1) {
			
			$skidka = $prices[0]['cust_price'] * 0.2;
			$skidka_2 = $prices[0]['cust_price'] * 0.3;
			echo '<p>скидка 20% на третий товар: <strong>'.round($skidka, 2).' '.$symbol.'</strong></p>';
			echo '<p>скидка 30% на четвертый товар: <strong>'.round($skidka_2, 2).' '.$symbol.'</strong></p>';
			
		} else {
			
			if ($prices[0]['cust_quantity'] == 1) {
				
				$skidka = $prices[0]['cust_price'] * 0.2;
				$skidka_2 = $prices[1]['cust_price'] * 0.3;
				echo '<p>скидка 20% на третий товар: <strong>'.round($skidka, 2).' '.$symbol.'</strong></p>';
				echo '<p>скидка 30% на четвертый товар: <strong>'.round($skidka_2, 2).' '.$symbol.'</strong></p>';
				
			} else {
				
				$skidka = $prices[0]['cust_price'] * 0.2;
				$skidka_2 = $prices[0]['cust_price'] * 0.3;
				echo '<p>скидка 20% на третий товар: <strong>'.round($skidka, 2).' '.$symbol.'</strong></p>';
				echo '<p>скидка 30% на четвертый товар: <strong>'.round($skidka_2, 2).' '.$symbol.'</strong></p>';
				
			}
			
		}
		
	}
	
	echo '</div>';

}

После этого задача была дополнена тем, что нужно было отобразить скидки в каждой строке товара к которому она применяется в виде старой и новой цены. Из-за этого пришлось частично изменить алгоритм.

Также, и что более важно, первая версия функции работала только с 3-м и 4-м товарами, а не с каждым 3 и каждым 4 товаром.

Основной расчет акции (вторая версия)

add_action( 'woocommerce_cart_calculate_fees','wc_custom_surcharge', 10, 1 );
function wc_custom_surcharge( $cart ) {
	
	if ( is_admin() && ! defined( 'DOING_AJAX' ) )
	return;
	
	foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
		
		$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
		
		if ( $_product->get_type() == 'simple' ) {
			
			$terms = get_the_terms( $_product->get_ID(), 'product_cat' );
			
		} elseif ( $_product->get_type() == 'variation' ) {
			
			$variation = wc_get_product($_product->get_ID());
			$varproduct = wc_get_product( $variation->get_parent_id() );
			$terms = get_the_terms( $varproduct->get_ID(), 'product_cat' );
			
		}
		
		if ($terms[0]->slug == 'compact-disc') { // если категория
		
			// создаем столько цен сколько единиц товара
			$prices[] = array_fill(0, $cart_item['quantity'], $_product->get_price());
		
		}
		
	}	
	
	// объединяем в один массив цен
	$all_prices = array();
	foreach ($prices as $child) {
		$all_prices = array_merge($all_prices, $child);
	}	
	
	sort($all_prices);
	
	$action_20_count = floor(count($all_prices) / 3 );
	$action_30_count = floor(count($all_prices) / 4 );
	$actions_count = $action_20_count + $action_30_count;
	
	// Убием каждую 7 скидку т.к. они дублируются на одном товаре (12, 24, 36 и т.д.)
	if ($actions_count % 7 == 0) {
		$actions_count = $actions_count - ($actions_count / 7);
	}
	
	if ( count($all_prices) >= 3 ) {
		
		$fee_descript = 'Скидка 20% за каждый третий и 30% за каждый четвертый товары';
		$fee = 0;

		$i = 0;	
		
		foreach ($all_prices as $cus_price) {
			
			$i++;
			
			if ($i <= $actions_count) { // соответствует количеству примененных скидок
			
				if ($i % 2 != 0) { // нечетные
				
					$all_actions_price[] = $cus_price * 0.2;
					
				} else {
					
					$all_actions_price[] = $cus_price * 0.3;
					
				}
			
			}
			
		}
		
		$fee = round(array_sum($all_actions_price), 2);
		
		$cart->add_fee( __($fee_descript, 'woocommerce'), -$fee, true );

	}
	
}

В данном случае функция работает на каждый 3 и 4 товары. Также внесена корректировка на каждое 7 срабатывание скидки, т.к. в этот момент происходит дублирование из-за того что каждый 12 товар является и третьи и четвертым (12 шт, 24 шт, 36 и т.д.).

Вывод уведомление о сумме скидки в корзине (вторая версия)

// Вывести информацию о скидке в корзине перед Итого
add_action( 'woocommerce_before_cart_totals','print_message_wc_custom_surcharge', 7, 1 );

function print_message_wc_custom_surcharge() {
	
	foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
		
		$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
		
		if ( $_product->get_type() == 'simple' ) {
			
			$terms = get_the_terms( $_product->get_ID(), 'product_cat' );
			
		} elseif ( $_product->get_type() == 'variation' ) {
			
			$variation = wc_get_product($_product->get_ID());
			$varproduct = wc_get_product( $variation->get_parent_id() );
			$terms = get_the_terms( $varproduct->get_ID(), 'product_cat' );
			
		}
		
		if ($terms[0]->slug == 'compact-disc') { // если категория
		
			// создаем столько цен сколько единиц товара
			$prices[] = array_fill(0, $cart_item['quantity'], $_product->get_price());
		
		}
		
	}	
	
	// объединяем в один массив цен
	$all_prices = array();
	foreach ($prices as $child) {
		$all_prices = array_merge($all_prices, $child);
	}	
	
	sort($all_prices);
	
	$action_20_count = floor(count($all_prices) / 3 );
	$action_30_count = floor(count($all_prices) / 4 );
	$actions_count = $action_20_count + $action_30_count;
	
	// Убием каждую 7 скидку т.к. они дублируются на одном товаре (12, 24, 36 и т.д.)
	if ($actions_count % 7 == 0) {
		$actions_count = $actions_count - ($actions_count / 7);
	}	
	
	$symbol = get_woocommerce_currency_symbol('RUB');
	
	if ( count($all_prices) >= 3 ) {
		
		echo '<div class="discount-message">';

		$i = 0;	
		
		foreach ($all_prices as $cus_price) {
			
			$i++;
			
			if ($i <= $actions_count) { // соответствует количеству примененных скидок
			
				if ($i % 2 != 0) { // нечетные
				
					$all_actions_price[] = $cus_price * 0.2;
					
				} else {
					
					$all_actions_price[] = $cus_price * 0.3;
					
				}
			
			}
			
		}
		
		$skidka = round(array_sum($all_actions_price), 2);
		
		echo '<p>Скидка 20% за каждый третий и 30% за каждый четвертый товары: <strong><bdi>'.$skidka.' '.$symbol.'</bdi></strong></p>';
	
		echo '</div>';

	}

}
Заполнение массива значениями:

$prices[] = array_fill(0, $cart_item['quantity'], $_product->get_price());

Изменение итоговой суммы по позициям участвующих в акции

add_filter( 'woocommerce_cart_item_subtotal', 'bbloomer_if_coupon_slash_item_subtotal', 99, 3 );
 
function bbloomer_if_coupon_slash_item_subtotal( $subtotal, $cart_item_cus ){
	
	foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
		
		$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
		
		if ( $_product->get_type() == 'simple' ) {
			
			$terms = get_the_terms( $_product->get_ID(), 'product_cat' );
			
		} elseif ( $_product->get_type() == 'variation' ) {
			
			$variation = wc_get_product($_product->get_ID());
			$varproduct = wc_get_product( $variation->get_parent_id() );
			$terms = get_the_terms( $varproduct->get_ID(), 'product_cat' );
			
		}
		
		if ($terms[0]->slug == 'compact-disc') { // если категория
		
			// создаем столько цен сколько единиц товаров
			
			for ($i = 1; $i <= $cart_item['quantity']; $i++) {
				$prices[] = array(
					'cust_id' => $_product->get_ID(), 
					'cust_price' => $_product->get_price()
				);
			}
		
		}
		
	}
	
	// сортировка 2-х мерного массива по ключу
	usort($prices, function($a, $b) {
		return $a['cust_price'] <=> $b['cust_price'];
	});

	$action_20_count = floor(count($prices) / 3 );
	$action_30_count = floor(count($prices) / 4 );
	$actions_count = $action_20_count + $action_30_count;
	
	// Убием каждую 7 скидку т.к. они дублируются на одном товаре (12, 24, 36 и т.д.)
	if ($actions_count % 7 == 0) {
		$actions_count = $actions_count - ($actions_count / 7);
	}
	
	if ( count($prices) >= 3 ) {

		$i = 0;	
		
		foreach ($prices as $cust_price) {
			
			$i++;
			
			if ($i <= $actions_count) { // соответствует количеству примененных скидок
			
				if ($i % 2 != 0) { // нечетные
				
					$all_actions_price[] = array (
						'cust_id' => $cust_price['cust_id'], 
						'cust_action' => $cust_price['cust_price'] * 0.2						
					);
					
				} else {
					
					$all_actions_price[] = array (
						'cust_id' => $cust_price['cust_id'], 
						'cust_action' => $cust_price['cust_price'] * 0.3						
					);
					
				}
			
			}
			
		}

	}	
	
	foreach ($all_actions_price as $row) {
		
		if ( !isset( $results[$row['cust_id']] ) ) {
			$results[$row['cust_id']] = $row;
		} else {
			$results[$row['cust_id']]['cust_action'] .= ',' . $row['cust_action'];
		}
		
	}
	
	foreach ($results as $result) {

		//количество применений акции к каждой позиции
		//$action_quantity = substr_count($result['cust_action'], ',') + 1;
		
		// можно собрать красивый массив
		//$product_action[$result['cust_id']] = array_sum( explode( ',', $result['cust_action'] ) );
		
		$line_total_discount = array_sum( explode( ',', $result['cust_action'] ) );
		
		if ( $cart_item_cus['data']->get_ID() == $result['cust_id'] ) {
			
			$line_total = $cart_item_cus['data']->get_price() * $cart_item_cus['quantity'];
			
			$newsubtotal = wc_price( $line_total - $line_total_discount ); 
			$subtotal = sprintf( '<del>%s</del> %s', $subtotal, $newsubtotal ); 
		}
		
	}

	return $subtotal;
}

Данная функция создана на основе решения Rodolfo Melogli об предварительном показе цены со скидкой (купоном) и не влияющем на сумму корзины:

add_filter( 'woocommerce_cart_item_subtotal', 'bbloomer_if_coupon_slash_item_subtotal', 99, 3 );
 
function bbloomer_if_coupon_slash_item_subtotal( $subtotal, $cart_item, $cart_item_key ){
	global $woocommerce;
	 
	// Note: use your own coupon code here
	$coupon_code = 'barmada'; 
	 
	if ( $woocommerce->cart->has_discount( $coupon_code )) {
	 
		// Note: apply your own coupon discount multiplier here
		// In this case, it's a 99% discount, hence I multiply by 0.01
		$newsubtotal = wc_price( $cart_item['data']->get_price() * 0.01 * $cart_item['quantity'] ); 
		 
		$subtotal = sprintf( '<s>%s</s> %s', $subtotal, $newsubtotal ); 
	}
	 
	return $subtotal;
}

Поделиться в соц. сетях:

  • Похожие записи
  • Комментарии
  • Вложения
Upgrade WC

Upgrade WC

Очередная серия улучшений (upgrade) плагина WC. Буду добавлять по мере изучения новые решения. Поиск по SKU (артикулу) Из коробки WC не ищет по артикулам (SKU). Но достаточно установить плагин Search Читать далее »

/
Модификация Woocommerce

Модификация Woocommerce

Продолжаем серию модификаций модуля интернет коммерции Woocommerce. Скрыть колонки редактирования товаров add_filter( 'manage_edit-product_columns', 'change_columns_filter',10, 1 ); function change_columns_filter( $columns ) { unset($columns['product_tag']); unset($columns['sku']); unset($columns['featured']); return $columns; } Тоже самое можно Читать далее »

/ /
Фильтр по наличию

Фильтр по наличию

Оказывается в последних версиях Woocommerce есть встроенная функция фильтрации по наличию. Через добавление в url параметра filter_stock_status. Можно её использовать для создания фильтра: Функция вывода списка: Функция с условиями вывода Читать далее »

Добавить комментарий

Пока нет комментариев. Будь первым!

Акция 20% на каждый 3 и 30% на каждый 4 товар Акция 20% на каждый 3 и 30% на каждый 4 товар
Даты создания CMS
Рекомендации для васДаты создания CMSOpttour.ru
Спасибо! Наш менеджер свяжется с Вами в течении 5 минут.