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

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

30.01.2021

210

Поступила нестандартная задача, реализовать акцию 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;
}

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

  • Похожие записи
  • Комментарии
  • Вложения
Трекинг заказа

Трекинг заказа

Рассмотрим такой аспект работы интернет-магазина как трекинг заказа (order tracking), т.е. отслеживание статуса и местоположения заказа. YITH WooCommerce Order Tracking 8000 установок. В бесплатной версии добавляет к заказу (в админке) Читать далее »

«Правильные» похожие товары в woocommerce

«Правильные» похожие товары в woocommerce

Похожие товары реализованы не совсем грамотно: если добавлять товарам метки (присущие большинству товаров, например 33 класс у ламината), то похожие товары будут выводится практически одни и те же. Исправляем данный Читать далее »

Вложить файл в заказ

Вложить файл в заказ

Если необходимо приложить к заказу реквизиты или любой другой файл, к заполняемым полям нужно добавить загрузчик файла. Easy Upload Files During Checkout (1000) Простой но рабочий функционал. В бесплатной версии Читать далее »

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

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

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