WooCommerce 的 Fees API 包含三個函式,add_fee(), get_fees() 和 calculate_fees() 。我們可以用 add_fee() 向訂單中新增固定費用或者百分比費用,需要注意的是使用哪個 action 新增。

回顧程式碼,發現問題

在之前寫的 WooCommerce 使用程式碼一文中,寫過一段新增手續費的程式碼,用的 action 是 WooCommerce_calculate_totals,最近需要加一個可以應用稅率的手續費,進而發現程式碼中有個邏輯錯誤。

$WooCommerce->cart->add_fee( 'Surcharge', $surcharge, false, '' );
$WooCommerce->cart->fee_total += $surcharge;

第一句話用 Fee API 增加了費用,第二句話把這個費用和總費用相加,add_fee 第三個引數含義為是否應用稅率。

既然 add_fee 可以給費用增加一個稅錢,第二句話中卻沒有稅的蹤影,豈不是要出錯了!

細看 WooCommerce 的 fee api 後發現,正確的 action 是WooCommerce_cart_calculate_fees,第二句話並不需要。

下面是正確的程式碼,這裡允許給費用加稅。

add_action( 'WooCommerce_cart_calculate_fees','WooCommerce_custom_surcharge' );
function WooCommerce_custom_surcharge() {
    global $WooCommerce;
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;
    $percentage = 0.01;
    $surcharge = ( $WooCommerce->cart->cart_contents_total + $WooCommerce->cart->shipping_total ) * $percentage;
    $WooCommerce->cart->add_fee( 'Surcharge', $surcharge,true );
}

WooCommerce Fees API

Fees API 位於 class-wc-cart.php 中

三個函式程式碼如下,供參考

/*-----------------------------------------------------------------------------------*/
/* Fees API to add additonal costs to orders */
/*-----------------------------------------------------------------------------------*/

        /**
         * add_fee function.
         *
         * @param mixed $name
         * @param mixed $amount
         * @param bool $taxable (default: false)
         * @param string $tax_class (default: '')
         */
        public function add_fee( $name, $amount, $taxable = false, $tax_class = '' ) {
                if ( empty( $this->fees ) )
                        $this->fees = array();

                $new_fee 			= new stdClass();
                $new_fee->id 		= sanitize_title( $name );
                $new_fee->name 		= esc_attr( $name );
                $new_fee->amount	= (float) esc_attr( $amount );
                $new_fee->tax_class	= $tax_class;
                $new_fee->taxable	= $taxable ? true : false;
                $new_fee->tax		= 0;

                $this->fees[] 		= $new_fee;
        }

        /**
         * get_fees function.
         *
         * @access public
         * @return void
         */
        public function get_fees() {
                return array_filter( (array) $this->fees );
        }

        /**
         * Calculate fees
         */
        public function calculate_fees() {

                // Fire an action where developers can add their fees
                do_action( 'WooCommerce_cart_calculate_fees', $this );

                // If fees were added, total them and calculate tax
                if ( $fees = $this->get_fees() ) {
                        foreach ( $fees as $fee ) {
                                $this->fee_total += $fee->amount;

                                if ( $fee->taxable ) {
                                        // Get tax rates
                                        $tax_rates = $this->tax->get_rates( $fee->tax_class );
                                        $fee_taxes = $this->tax->calc_tax( $fee->amount, $tax_rates, false );

                                        // Store
                                        $fee->tax  = array_sum( $fee_taxes );

                                        // Tax rows - merge the totals we just got
                                        foreach ( array_keys( $this->taxes + $fee_taxes ) as $key ) {
                                            $this->taxes[ $key ] = ( isset( $fee_taxes[ $key ] ) ? $fee_taxes[ $key ] : 0 ) + ( isset( $this->taxes[ $key ] ) ? $this->taxes[ $key ] : 0 );
                                        }
                                }
                        }
                }
        }