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

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

HIT

30.01.2021

1010

Поступила нестандартная задача, реализовать акцию 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;
}
[site-socialshare]
  • Похожие записи
  • Комментарии
  • Вложения
Настройка адресов Woocommerce

Настройка адресов Woocommerce

В woocommerce существует 2 типа адресов: billing (адрес плательщика) и shipping (адрес доставки). Поля в обоих типах адресов дублируются. Для нашей страны более характерно использовать billing для данных клиента (без Читать далее »

Пользовательский метод доставки

Пользовательский метод доставки

Создадим пользовательский метод доставки для Woocommerce 3.0. Метод создадим в виде плагина. Создадим для пользовательского метода уведомление при превышении веса (лимит установлен на 0): т.е. если у нас будет в Читать далее »

Обзор плагинов по созданию скидок

Обзор плагинов по созданию скидок

Рассмотрим различные плагины по созданию функционала скидок. Рассматриваться будут плагины которые предоставляют возможность комплексного формирования скидок на состав корзины. Практически все плагины в обзоре могут в бесплатной версии предоставить простой Читать далее »

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

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

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