Динамический расчет скидок на каждый день в WooCommerce - PullRequest
2 голосов
/ 01 апреля 2019

В настоящее время я работаю над диапазоном сроков аренды продуктов. Для этого я использую Jquery UI Datepicker.

Это позволяет мне выбрать две даты и подсчитать количество дней в диапазоне этих дат.

Вот мой код:

add_action('wp_enqueue_scripts', 'enabling_date_picker');

function enabling_date_picker() {

    // Only on front-end and product page
    if (is_product() && !is_wc_endpoint_url()):

    // Load the Datepicker jQuery-ui plugin script
    wp_enqueue_style('jquery-ui', 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css');
    wp_enqueue_script('jquery-ui-datepicker');

    endif;
}


// The jQuery script
add_action('wp_footer', 'rental_date_jquery_script');

function rental_date_jquery_script() {
    // Only on front-end and product page
    if (is_product() && !is_wc_endpoint_url()):

            ?>
            <script>
jQuery(function($) {
    var from = new Date();
    var to = new Date();
    var dayDiff = 1;
     var dates = $("#from, #to").datepicker({
            defaultDate: "+1w",
            changeMonth: true,
            numberOfMonths: 1,
            dateFormat: "dd.mm.yy",
            minDate: 0,
            maxDate: 14,
            onSelect: function(selectedDate) {
                    var option = this.id == "from" ? "minDate" : "maxDate",
                            instance = $(this).data("datepicker"),
                            date = $.datepicker.parseDate(
                                    instance.settings.dateFormat ||
                                    $.datepicker._defaults.dateFormat,
                                    selectedDate, instance.settings);
                    dates.not(this).datepicker("option", option, date);

                    if (this.id == "from") {
                            from = $(this).datepicker('getDate');
                            if (!(to == "")) {
                                    update_days()
                            }
                    }
                    if (this.id == "to") {
                            to = $(this).datepicker('getDate');
                            update_days()
                    }
            }
    });
    function update_days() {
            dayDiff = Math.ceil((to - from) / (1000 * 60 * 60 * 24));
            $("#days").empty()
            $("#days").append(dayDiff)
    } 
}); 
    </script> 

    <?php

    endif;
}

// Add a custom field before single add to cart
add_action('woocommerce_before_variations_form', 'display_rental_date_custom_fields', 5);

function display_rental_date_custom_fields() {

    echo '<div>
        <h3>From:</h3>
        <input id="from" type="text" name="from" readonly />
    </div>
    <div>
        <h3>To:</h3>
        <input id="to" type="text" name="to" readonly />
    </div>
    <div>
        <span>You have chosen: </span>
        <span id="days">< /span> days.
    </div>';
}

Обновление:

Я хотел бы сделать динамический расчет скидки. Я объясню, что я имею в виду:

  1. Обычная цена на продукты - это стоимость аренды в сутки.
  2. Максимальный срок аренды не ограничен.
  3. Процентная скидка в первый день - 100%
  4. Скидка, начиная со второго дня аренды - 50%.

Например, если клиент арендует продукт стоимостью 100 долларов США в день в течение 5 дней, получается следующее:

Day 1 - $100 (100%)
Day 2 - $50 (50%)
Day 3 - $50 (50%)
Day 4 - $50 (50%)
Day 5 - $50 (50%)

В итоге должно получиться - 300 долларов за 5 дней.

При этом необходимо рассчитать общую стоимость аренды и показать новую цену на странице одного товара. Все продукты являются переменными.

Как сделать такой функционал? Нужна ваша помощь!

Я надеюсь, что многим разработчикам понадобится эта функциональность в будущем.

1 Ответ

2 голосов
/ 07 апреля 2019

Изменения в существующем коде

В коде display_rental_date_custom_fields():

  1. Я изменил поля name и id, чтобы они начинались с rental_period_, потому что to и from слишком общие ...

  2. Я добавил скрытое поле input с именем is_rental, которое указывает, что приобретаемый продукт доступен для аренды .

  3. Я добавил атрибут value к полям даты.

function display_rental_date_custom_fields() {
    ?>
        <div>
            <h3>From:</h3>
            <input id="rental_period_from" type="text" name="rental_period_from" readonly value="<?php echo esc_attr( filter_input( INPUT_POST, 'rental_period_from' ) ); ?>" />
        </div>
        <div>
            <h3>To:</h3>
            <input id="rental_period_to" type="text" name="rental_period_to" readonly value="<?php echo esc_attr( filter_input( INPUT_POST, 'rental_period_to' ) ); ?>" />
        </div>
        <div>
            <span>You have chosen: </span>
            <span id="days">0</span> days.
        </div>
        <input type="hidden" name="is_rental" value="1">
    <?php
}

И вам следует использовать исправленный скрипт выбора даты здесь & mdash; просто посетите страницу, чтобы увидеть изменения.


Новый код, который будет добавлен к существующему коду

(Скопируйте фрагменты ниже и вставьте их под кодом display_rental_date_custom_fields.)

SNIPPET 1: Функция PHP для расчета:

См. Ниже в СНиПЕТЕ № 3.

SNIPPET 2: Обрабатывает отправленный срок аренды (т.е. даты начала и окончания):

add_filter( 'woocommerce_add_cart_item_data', 'my_add_rental_period_data' );
function my_add_rental_period_data( $cart_item_data ) {
    if ( ! empty( $_POST['is_rental'] ) ) {
        // Throwing an Exception will prevent the product from being added to the cart.

        // Validate POSTed values.
        if ( empty( $_POST['rental_period_from'] ) ||
            empty( $_POST['rental_period_to'] ) ) {
            throw new Exception( 'Rental start and end dates must both be specified.' );
        }

        $now = date_create( 'now' );
        $from = date_create( $_POST['rental_period_from'] );
        $to = date_create( $_POST['rental_period_to'] );
        // Validate rental dates.
        if ( ! $from || ! $to || $to < $from ) {
            throw new Exception( 'Invalid rental dates.' );
        }

        $format = 'd.m.Y'; // dd.mm.yyyy
        $rental_days = date_diff( $from, $to )->days;
        $cart_item_data['rental_period'] = [
            'from'    => $from->format( $format ),
            'to'      => $to->format( $format ),
            'days'    => $rental_days,
        ];
    }
    return $cart_item_data;
}

SNIPPET 3: Применяет скидку на аренду продуктов в корзине:

function my_set_rental_product_price( array $cart_item ) {
    if ( ! empty( $cart_item['rental_period'] ) ) {
        $rental_days = $cart_item['rental_period']['days'];
        if ( $rental_days > 1 ) {
            $regular_price = $cart_item['data']->get_regular_price();
            $price = $regular_price / 2 * ( $rental_days - 1 ) + $regular_price;
            $cart_item['data']->set_price( $price );
        }
        // else, no discount given.

        return $cart_item['data'];
    }
}

add_action( 'woocommerce_before_calculate_totals', 'my_apply_discount_to_rental_products' );
function my_apply_discount_to_rental_products() {
    foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
        my_set_rental_product_price( $cart_item );
    }
}

add_filter( 'woocommerce_cart_item_product', 'my_apply_discount_to_rental_product', 10, 2 );
function my_apply_discount_to_rental_product( $product, $cart_item ) {
    if ( $rental_product = my_set_rental_product_price( $cart_item ) ) {
        return $rental_product;
    }
    return $product;
}

SNIPPET 4: Отображает период аренды в главной таблице на странице корзины:

add_filter( 'woocommerce_get_item_data', 'my_add_rental_period_meta', 10, 2 );
function my_add_rental_period_meta( $item_data, $cart_item ) {
    if ( ! empty( $cart_item['rental_period'] ) ) {
        $period =& $cart_item['rental_period'];

        $days = $period['days'] . ' ' . _n( 'day', 'days', $period['days'] );
        $range = ( $period['from'] === $period['to'] ) ? $period['from'] . ' (today)' :
            $days . ' (' . $period['from'] . ' - ' . $period['to'] . ')';

        $item_data[] = [
            'key'   => 'Rental Period',
            'value' => $range,
        ];
    }
    return $item_data;
}

SNIPPET 5: Добавляет период аренды в качестве метаданных продукта в заказе: (это необходимо специально для внутреннего / административного или более позднего доступа)

add_action( 'woocommerce_checkout_create_order_line_item', 'my_add_rental_period_meta2', 10, 3 );
function my_add_rental_period_meta2( $item, $cart_item_key, $cart_item ) {
    if ( ! empty( $cart_item['rental_period'] ) ) {
        $item->add_meta_data( '_rental_period', $cart_item['rental_period'] );
    }
    return $item;
}

SNIPPET 6: Позволяет указанным выше сохраненным метаданным отображаться, например, в таблице «Детали заказа» и в электронном письме администратора «Новый заказ»:

add_filter( 'woocommerce_order_item_get_formatted_meta_data', 'my_add_rental_period_meta3', 10, 2 );
function my_add_rental_period_meta3( $formatted_meta, $item ) {
    if ( $period = $item->get_meta( '_rental_period', true ) ) {
        $days = $period['days'] . ' ' . _n( 'day', 'days', $period['days'] );
        $range = ( $period['from'] === $period['to'] ) ? $period['from'] . ' (today)' :
            $days . ' (' . $period['from'] . ' - ' . $period['to'] . ')';

        $formatted_meta[] = (object) [
            'key'           => 'rental_period',
            'value'         => $period,
            'display_key'   => 'Rental Period',
            'display_value' => $range,
        ];
    }
    return $formatted_meta;
}

Скриншоты

  1. Страница одного товара после добавления (переменного) товара в корзину

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...