1
votes

What I'm trying to achieve is to charge customers a deposit based on the items they add to the cart. Only specific items require a deposit. For each of these items 1x deposit is added. As an example: Item1, Item2 & Item3 all require a deposit of 10.00 while Item4, Item5 & Item6 don't require a deposit. So if I had the following in the Cart

Product       Qty     Unit Price     Subtotal
Item1          x1     £50.00           £50.00
Item2          x2     £30.00           £60.00
Item4          x1     £5.00             £5.00
Item6          x1     £2.99             £2.99
---------------------------------------------
                              Total:  £117.99
                              Deposit: £30.00
                              Balance: £87.99

I would need to charge a deposit of £30 as there are 3 deposit items. This then leaves a remaining balance which the customer pays on collection of the items.

I've tried various plugins (WooCommerce Deposits, Yith Deposits/Part Payments) and none of them come close to achieving what I need.

I've got somewhere by adding Hooks into my child theme's functions.php file but I'm at a loss how to get it fully functional.

Current Code

add_action( 'woocommerce_cart_calculate_fees', 'tcg_calculate_deposit' );
function tcg_calculate_deposit( $cart_object ) {

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

    // Check if these products are in the cart
    $deposit_items = array( '4359', '4336', '4331', '4320' );

    $deposit = 10.00;

    $matching = false;

    foreach ( $cart_object->get_cart() as $item_values ) {

        if( in_array( $item_values['product_id'], $deposit_items )) {

         // for each item in array deposit + 1
         // so if 3 deposit items deposit = 30.00

         // set cart total to be the deposit amount so I can process this amount as payment through woocommerce
        $cart_subtotal = $cart_object->subtotal_ex_tax;
        $balance = $cart_subtotal - $deposit;

        $cart_object->add_fee( __( 'Balance', 'woocommerce'), $balance, true );

        break;
        }

    }

}

At the minute this makes the Total the sum of the Subtotal + Balance. I need it to be Deposit. I'm not sure if I need to create separate functions to achieve?

1
What you asking is just not clear and maybe something too broad and complex depending on your requirements. Using cart fees, will only set additional fees globally to existing cart subtotal…LoicTheAztec
Edited and undeleted my anwser.Daniël Visser

1 Answers

1
votes

Here is one way to do it:

Firstly: Add a custom field for the deposit price to the products general tab.

    function add_custom_fields() {

        global $woocommerce, $post;

        woocommerce_wp_text_input( 
            array( 
                'id'          => '_deposit_price', 
                'label'       => __( 'Deposit price(€)', 'woocommerce' ), 
                'placeholder' => '10.20',
                'desc_tip'    => 'true',
                'description' => __( 'Enter the custom deposit price here.', 'woocommerce' ) 
            )
        );

    }

    add_action( 'woocommerce_product_options_general_product_data', 'add_custom_fields');


Secondly: Save the value of the custom field as metadata to the product.

    function custom_fields_save( $post_id ){

        $woocommerce_text_field = sanitize_text_field( $_POST['_deposit_price'] );

        if( is_numeric( $woocommerce_text_field ) || empty( $woocommerce_text_field ) ){
            update_post_meta( $post_id, '_deposit_price', esc_attr( $woocommerce_text_field ) );
        }

    }

    add_action( 'woocommerce_process_product_meta', 'custom_fields_save' );


Thirdly: Filter woocommerce_get_price, if the product has a deposit price set we return that instead of the normal product price. If no deposit price was set we return 0.

    function filter_woocommerce_get_price( $price, $product ){

        $product_id = $product->get_id();
        $deposit_price = get_post_meta( $product_id, '_deposit_price', true );

        if( ! empty( $deposit_price )  ) {

            return $deposit_price;
        }

        return 0; 

    }

    add_filter( 'woocommerce_get_price', 'filter_woocommerce_get_price', 10, 2 );


Finally: Filter several values so that the price is set like this €34.50 Deposit: €10.00 in product page and checkout page.

    function filter_woocommerce_get_price_html( $price, $product ){

        $product_id = $product->get_id();
        $deposit_price = get_post_meta( $product_id, '_deposit_price', true );
        $product_price = get_post_meta( $product_id, '_price', true );

        if( ! empty( $deposit_price )  ) {

            return wc_price($product_price) . ' <i>Deposit: ' . wc_price($deposit_price) . '</i>';
        }

        return wc_price( $product_price ); 

    }

    add_filter( 'woocommerce_get_price_html', 'filter_woocommerce_get_price_html', 10, 2 );
    add_filter( 'woocommerce_cart_product_price', 'filter_woocommerce_get_price_html', 10, 2 );



    function filter_woocommerce_cart_product_subtotal( $product_subtotal, $product, $quantity ){

        $product_id = $product->get_id();
        $deposit_price = get_post_meta( $product_id, '_deposit_price', true );
        $product_price = get_post_meta( $product_id, '_price', true );

        if( ! empty( $deposit_price )  ) {

            return wc_price( $product_price * $quantity ) . ' <i>Deposit: ' . wc_price( $deposit_price * $quantity ) . '</i>';
        }

        return wc_price( $product_price * $quantity ); 

    }

    add_filter( 'woocommerce_cart_product_subtotal', 'filter_woocommerce_cart_product_subtotal', 10, 3 );


Now you only need to add the remaining balance to the order as metadata or add it to the cart as a fee.

P.S. Remember to set the deposit price in the products general tab.