Cambiar el precio del carrito de WooCommerce después de aplicar el código de cupón

7 minutos de lectura

avatar de usuario
Archana

Creé un producto en WooCommerce y agregué dos opciones en la página de detalles del producto usando el gancho woocommerce_before_add_to_cart_button. Ahora, cuando los clientes agregan un producto al carrito desde la página de detalles del producto, tienen dos opciones. Pueden elegir una opción de estas dos opciones.

Luego almacené el valor seleccionado por el usuario en el carrito meta usando el gancho de woocommerce woocommerce_add_cart_item_data.

Estoy usando el código de esta respuesta: Guarde el valor del botón de radio del campo personalizado del producto en el carrito y muéstrelo en la página del carrito

Este es mi código:

// single Product Page options  
add_action("woocommerce_before_add_to_cart_button", "options_on_single_product");
function options_on_single_product(){
    $dp_product_id = get_the_ID(); 
    $product_url = get_permalink($dp_product_id);

    ?>
        <input type="radio" name="custom_options" checked="checked" value="option1"> option1<br />
        <input type="radio" name="custom_options" value="option2"> option2
    <?php
}


//Store the custom field
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_data_with_add_to_cart', 10, 2 );
function save_custom_data_with_add_to_cart( $cart_item_meta, $product_id ) {
    global $woocommerce;
    $cart_item_meta['custom_options'] = $_POST['custom_options'];
    return $cart_item_meta; 
}

Y esto es lo que he probado:

add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price( $cart_obj ) {

    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    foreach ( $cart_obj->get_cart() as $key => $value ) {
        $product_id = $value['product_id'];
        $custom_options = $value['custom_options'];
        $coupon_code = $value['coupon_code'];
        if($custom_options == 'option2')
        {
            if($coupon_code !='')
            {
                global $woocommerce;
                if ( WC()->cart->has_discount( $coupon_code ) ) return;
                (WC()->cart->add_discount( $coupon_code ))

            //code for second discount
            }
            else{
                $percentage = get_post_meta( $product_id , 'percentage', true );
                //print_r($value);
                $old_price = $value['data']->regular_price;
                $new_price = ($percentage / 100) * $old_price;
                $value['data']->set_price( $new_price );
            }
        } 
    }
}

Ahora, lo que estoy tratando de obtener con ese último fragmento es:

  • Si el cliente selecciona la Opción 1, se ejecuta el proceso regular de woocommerce.
  • Si se selecciona la Opción 2, primero se aplica el código de cupón al carrito (si el cliente ingresó el código) y luego el precio se divide por algún porcentaje (almacenado en la meta del producto) se aplica despues.

Pero no está funcionando como se esperaba porque el precio del producto modificado se aplica antes y el descuento del cupón se aplica después de este precio modificado.

Lo que me gustaría es que el descuento del cupón se aplique primero al precio normal del producto y luego cambie este precio con el descuento de mi producto personalizado.

es posible? ¿Cómo puedo lograr eso?

Gracias.

avatar de usuario
LoicTheAztec

esto no es realmente posible … ¿Por qué? … Porque (la lógica):

  1. Tienes el precio del producto
  2. Luego se aplica el cupón de descuento a ese precio (después)
    ==> si cambia el precio del producto, el cupón se aplicará a ese precio modificado

Lo que puedes hacer en su lugar:

  1. No cambias el precio del producto.
  2. si se ingresa se aplica el cupón y…
  3. Si se agrega el producto “opción 2” al carrito:
  4. Aplique un descuento personalizado (una tarifa negativa) basado en el precio del producto agregado después de usar WC_cart add_fee() método…

Para este último caso tendrás que afinar tu descuento adicional.
Si el cupón no se ha aplicado o se elimina, no hay descuento adicional.

Su función personalizada se conectará woocommerce_cart_calculate_fees gancho de acción en su lugar:

add_action( 'woocommerce_cart_calculate_fees', 'option2_additional_discount', 10, 1 );
function option2_additional_discount( $cart_obj ) {

    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    $discount = 0;
    $applied_coupons = $cart_obj->get_applied_coupons();

    foreach ( $cart_obj->get_cart() as $item_values ) {
        if( 'option2' == $item_values['custom_options'] && !empty($applied_coupons) ){
            $product_id = $item_values['product_id'];
            $percentage = get_post_meta( $product_id , 'percentage', true );
            $quantity = $item_values['quantity'];
            $product_reg_price = $item_values['data']->regular_price;
            $line_total = $item_values['line_total'];
            $line_subtotal = $item_values['line_subtotal'];
            $percentage = 90;

            ## ----- CALCULATIONS (To Fine tune) ----- ##

            $item_discounted_price = ($percentage / 100) *  $product_reg_price * $item_values['quantity'];
            // Or Besed on line item subtotal
            $discounted_price = ($percentage / 100) * $line_subtotal;

            $discount += $product_reg_price - $item_discounted_price;
        }
    }
    if($discount != 0)
        $cart_obj->add_fee( __( 'Option2 discount', 'woocommerce' ) , - $discount );
}

El código va en el archivo function.php de su tema secundario activo (o tema) o también en cualquier archivo de complemento.

Este código está probado y funciona.

Agregar una tarifa negativa usando el WC_Cart->add_fee() el método no estaba funcionando para mí. Cuando reviso la clase WC Cart, incluso dice que no puede usar una cantidad negativa.

Ver los documentos.

Hice lo siguiente:

  • crear un cupón de marcador de posición con un código ‘seguro’, por ejemplo, custom_discount_fjgndfl28. Establezca una cantidad de descuento de 0, de modo que cuando alguien (de alguna manera) use este cupón fuera de su programa, el descuento siga siendo 0.
  • Usar filtro woocommerce_get_shop_coupon_datay configure todos los datos de cupón que desea para ese cupón/sesión.
  • enganchar en woocommerce_before_calculate_totals y configura tu cupón personalizado en el carrito.
  • En este punto, el Carro debería calcular todo correctamente. Y cuando se convierte en un pedido, también tiene la cantidad de descuento correcta.
  • Nota: el código de cupón también se usa como etiqueta en algunas plantillas. Usar filtro woocommerce_cart_totals_coupon_label para cambiarlo

Funciones de ejemplo:

/**
 * NOTE: All the hooks and filters below have to be called from your own
 * does_it_need_custom_discount() function. I used the 'wp' hook for mine.
 * Do not copy/paste this to your functions.php.
**/

add_filter('woocommerce_get_shop_coupon_data', 'addVirtualCoupon', 10, 2);
function addVirtualCoupon($unknown_param, $curr_coupon_code) {

    if($curr_coupon_code == 'custom_discount_fjgndfl28') {

      // possible types are: 'fixed_cart', 'percent', 'fixed_product' or 'percent_product.
      $discount_type="fixed_cart"; 

      // how you calculate the ammount and where you get the data from is totally up to you.
      $amount = $get_or_calculate_the_coupon_ammount;

      if(!$discount_type || !$amount) return false;

        $coupon = array(
            'id' => 9999999999 . rand(2,9),
            'amount' => $amount,
            'individual_use' => false,
            'product_ids' => array(),
            'exclude_product_ids' => array(),
            'usage_limit' => '',
            'usage_limit_per_user' => '',
            'limit_usage_to_x_items' => '',
            'usage_count' => '',
            'expiry_date' => '',
            'apply_before_tax' => 'yes',
            'free_shipping' => false,
            'product_categories' => array(),
            'exclude_product_categories' => array(),
            'exclude_sale_items' => false,
            'minimum_amount' => '',
            'maximum_amount' => '',
            'customer_email' => '',
            'discount_type' => $discount_type,
        );

        return $coupon;
    }
}

add_action('woocommerce_before_calculate_totals', 'applyFakeCoupons');
function applyFakeCoupons() {
  global $woocommerce;
  // $woocommerce->cart->remove_coupons(); remove existing coupons if needed.
  $woocommerce->cart->applied_coupons[] = $this->coupon_code; 
}

add_filter( 'woocommerce_cart_totals_coupon_label', 'cart_totals_coupon_label', 100, 2 );
function cart_totals_coupon_label($label, $coupon) {

    if($coupon) {
      $code = $coupon->get_code();
      if($code == 'custom_discount_fjgndfl28') {
        return 'Your custom coupon label';
      }
    }

    return $label;
}

Tenga en cuenta: Copié estas funciones de una clase que maneja mucho más, es solo para ayudarlo a comenzar.

  • Hola, ¿puede explicar “Todos los ganchos y filtros a continuación deben llamarse desde su propia función does_it_need_custom_discount()”, gracias?

    – Darko

    26 de marzo de 2020 a las 17:37

  • Siempre creo una clase virtual_coupon en mi aplicación. Cuando se necesita un descuento, llamo a la clase y configuro la información del descuento en un public $discounts = array();. La acción virtual_coupon y los ganchos de filtro solo se ejecutan si $this->discounts se establecen. Me doy cuenta de que esta no es información muy detallada, pero realmente depende de lo que esté tratando de lograr y de cómo esté estructurada su aplicación/complemento.

    – Björn

    18 de abril de 2020 a las 18:26


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad