简体   繁体   English

在 Woocommerce 3+ 中使用订单项以编程方式创建订单

[英]Create an order programmatically with line items in Woocommerce 3+

I needed to create a Woocommerce order programatically, however using the 'old' Woocommerce made this a very dirty procedure.我需要以编程方式创建 Woocommerce 订单,但是使用“旧”Woocommerce 使这成为一个非常脏的过程。

I had to insert all kind of database records manually, using many update_post_meta calls.我不得不手动插入所有类型的数据库记录,使用许多 update_post_meta 调用。

Looking for a better solution.寻找更好的解决方案。

With latest version of WooCommerce is possible try this as something like使用最新版本的 WooCommerce 可以尝试像这样

$address = array(
            'first_name' => 'Fresher',
            'last_name'  => 'StAcK OvErFloW',
            'company'    => 'stackoverflow',
            'email'      => 'test@test.com',
            'phone'      => '777-777-777-777',
            'address_1'  => '31 Main Street',
            'address_2'  => '', 
            'city'       => 'Chennai',
            'state'      => 'TN',
            'postcode'   => '12345',
            'country'    => 'IN'
        );

        $order = wc_create_order();
        $order->add_product( get_product( '12' ), 2 ); //(get_product with id and next is for quantity)
        $order->set_address( $address, 'billing' );
        $order->set_address( $address, 'shipping' );
        $order->add_coupon('Fresher','10','2'); // accepted param $couponcode, $couponamount,$coupon_tax
        $order->calculate_totals();

Call this above code with your function then it will work accordingly.用你的函数调用上面的代码,然后它就会相应地工作。

Note it not work with old version of WooCommerce like 2.1.12, It works only from 2.2 of WooCommerce.请注意,它不适用于旧版本的 WooCommerce,例如 2.1.12,它仅适用于 WooCommerce 的 2.2。

Hope it helps希望能帮助到你

2017-2021 For WooCommerce 3 and Above 2017-2021 WooCommerce 3 及更高版本

Woocommerce 3 has introduced CRUD objects and there is lot of changes on Order items… Also some WC_Order methods are now deprecated like add_coupon() . Woocommerce 3 引入了 CRUD 对象,并且订单项有很多变化……此外,一些WC_Order方法现在已被弃用,例如add_coupon()

Here is a function that allow creating programmatically an order nicely with all required data in it, including the taxes:这是一个允许以编程方式很好地创建订单的函数,其中包含所有必需的数据,包括税收:

function create_wc_order( $data ){
    $gateways = WC()->payment_gateways->get_available_payment_gateways();
    $order    = new WC_Order();

    // Set Billing and Shipping adresses
    foreach( array('billing_', 'shipping_') as $type ) {
        foreach ( $data['address'] as $key => $value ) {
            if( $type === 'shipping_' && in_array( $key, array( 'email', 'phone' ) ) )
                continue;

            $type_key = $type.$key;

            if ( is_callable( array( $order, "set_{$type_key}" ) ) ) {
                $order->{"set_{$type_key}"}( $value );
            }
        }
    }

    // Set other details
    $order->set_created_via( 'programatically' );
    $order->set_customer_id( $data['user_id'] );
    $order->set_currency( get_woocommerce_currency() );
    $order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
    $order->set_customer_note( isset( $data['order_comments'] ) ? $data['order_comments'] : '' );
    $order->set_payment_method( isset( $gateways[ $data['payment_method'] ] ) ? $gateways[ $data['payment_method'] ] : $data['payment_method'] );

    $calculate_taxes_for = array(
        'country'  => $data['address']['country'],
        'state'    => $data['address']['state'],
        'postcode' => $data['address']['postcode'],
        'city'     => $data['address']['city']
    );

    // Line items
    foreach( $data['line_items'] as $line_item ) {
        $args = $line_item['args'];
        $product = wc_get_product( isset($args['variation_id']) && $args['variation_id'] > 0 ? $$args['variation_id'] : $args['product_id'] );
        $item_id = $order->add_product( $product, $line_item['quantity'], $line_item['args'] );

        $item    = $order->get_item( $item_id, false );

        $item->calculate_taxes($calculate_taxes_for);
        $item->save();
    }

    // Coupon items
    if( isset($data['coupon_items'])){
        foreach( $data['coupon_items'] as $coupon_item ) {
            $order->apply_coupon(sanitize_title($coupon_item['code']));
        }
    }

    // Fee items
    if( isset($data['fee_items'])){
        foreach( $data['fee_items'] as $fee_item ) {
            $item = new WC_Order_Item_Fee();

            $item->set_name( $fee_item['name'] );
            $item->set_total( $fee_item['total'] );
            $tax_class = isset($fee_item['tax_class']) && $fee_item['tax_class'] != 0 ? $fee_item['tax_class'] : 0;
            $item->set_tax_class( $tax_class ); // O if not taxable

            $item->calculate_taxes($calculate_taxes_for);

            $item->save();
            $order->add_item( $item );
        }
    }

    // Set calculated totals
    $order->calculate_totals();
        
    if( isset($data['order_status']) ) {
        // Update order status from pending to your defined status and save data
        $order->update_status($data['order_status']['status'], $data['order_status']['note']);
        $order_id = $order->get_id();
    } else {
        // Save order to database (returns the order ID)
        $order_id = $order->save();
    }
    
    // Returns the order ID
    return $order_id;
}

Code goes in function.php file of your active child theme (or active theme) or in a plugin file.代码位于活动子主题(或活动主题)的 function.php 文件或插件文件中。


USAGE EXAMPLE from a data array:来自数据数组的用法示例

create_wc_order( array(
    'address' => array(
        'first_name' => 'Fresher',
        'last_name'  => 'StAcK OvErFloW',
        'company'    => 'stackoverflow',
        'email'      => 'test1@testoo.com',
        'phone'      => '777-777-777-777',
        'address_1'  => '31 Main Street',
        'address_2'  => '',
        'city'       => 'Chennai',
        'state'      => 'TN',
        'postcode'   => '12345',
        'country'    => 'IN',
    ),
    'user_id'        => '',
    'order_comments' => '',
    'payment_method' => 'bacs',
    'order_status'   => array(
        'status' => 'on-hold',
        'note'   => '',
    ),
    'line_items' => array(
        array(
            'quantity' => 1,
            'args'     => array(
                'product_id'    => 37,
                'variation_id'  => '',
                'variation'     => array(),
            )
        ),
    ),
    'coupon_items' => array(
        array(
            'code'         => 'summer',
        ),
    ),
    'fee_items' => array(
        array(
            'name'      => 'Delivery',
            'total'     => 5,
            'tax_class' => 0, // Not taxable
        ),
    ),
) );

With the new release of WC 2, it's much better.随着 WC 2 的新版本,它变得更好了。

However:然而:

  • I do not want to use the REST API, cause I am doing a call from my own WP plugin directly.我不想使用 REST API,因为我直接从我自己的 WP 插件进行调用。 I see no use in doing a curl to my localhost我认为对我的本地主机做 curl 没有用
  • The ' WooCommerce REST API Client Library ' is not useful for me cause it relay's on the REST API and it doesn't support a Create Order call WooCommerce REST API 客户端库”对我没有用,因为它在 REST API 上中继,并且不支持创建订单调用

To be honest, WooCom's API Docs are limited, maybe they are still in the progress of updating it.老实说,WooCom 的API Docs是有限的,也许他们还在更新它。 They currently don't tell me how to create a new order, which params are required etc.他们目前没有告诉我如何创建新订单,需要哪些参数等。

Any way, I figured out how to create an order with a line order (your product) using the classes and functions used by the REST API and I want to share it!无论如何,我想出了如何使用 REST API 使用的类和函数创建带有行订单(您的产品)的订单,我想分享它!

I created my own PHP class:我创建了自己的 PHP 类:

class WP_MyPlugin_woocommerce
{

public static function init()
{
    // required classes to create an order
    require_once WOOCOMMERCE_API_DIR . 'class-wc-api-exception.php';
    require_once WOOCOMMERCE_API_DIR . 'class-wc-api-server.php';
    require_once WOOCOMMERCE_API_DIR . 'class-wc-api-resource.php';
    require_once WOOCOMMERCE_API_DIR . 'interface-wc-api-handler.php';
    require_once WOOCOMMERCE_API_DIR . 'class-wc-api-json-handler.php';
    require_once WOOCOMMERCE_API_DIR . 'class-wc-api-orders.php';
}

public static function create_order()
{
    global $wp;

    // create order
    $server = new WC_API_Server( $wp->query_vars['wc-api-route'] );
    $order = new WC_API_Orders( $server );

    $order_id = $order->create_order( array
    (
        'order'             => array
        (
           'status'            => 'processing'
        ,  'customer_id'       =>  get_current_user_id()
        // ,   'order_meta'        => array
        //     (
        //        'some order meta'         => 'a value
        //     ,   some more order meta'    => 1
        //     )
        ,   'shipping_address'        => array
            (
                'first_name'          => $firstname
            ,   'last_name'           => $lastname
            ,   'address_1'           => $address
            ,   'address_2'           => $address2
            ,   'city'                => $city
            ,   'postcode'            => $postcode
            ,   'state'               => $state
            ,   'country'             => $country
            )

        ,   'billing_address'        => array(..can be same as shipping )

        ,   'line_items'        => array
            (
                array
                (
                    'product_id'         => 258
                ,   'quantity'           => 1
                )
            )
        )
    ) );
    var_dump($order_id);
    die();
}
}

Important:重要的:

  • The 'WOOCOMMERCE_API_DIR' constant points to '/woocommerce/includes/api/' in your plugin dir. 'WOOCOMMERCE_API_DIR' 常量指向插件目录中的 '/woocommerce/includes/api/'。
  • The order is assigned to a customer, in my case the current logged in user.订单被分配给一个客户,在我的例子中是当前登录的用户。 Make sure your user has a role that has the capability to read, edit, create and delete orders.确保您的用户具有能够读取、编辑、创建和删除订单的角色。 My role looks like this:我的角色是这样的:

     $result = add_role( 'customer' , __( 'Customer' ) , array ( 'read' => true // , 'read_private_posts' => true // , 'read_private_products' => true , 'read_private_shop_orders' => true , 'edit_private_shop_orders' => true , 'delete_private_shop_orders' => true , 'publish_shop_orders' => true // , 'read_private_shop_coupons' => true , 'edit_posts' => false , 'delete_posts' => false , 'show_admin_bar_front' => false ) );
  • If you want to look at the shop manager's rights , check如果您想查看店长的权限,请查看

    var_dump(get_option( 'wp_user_roles')); var_dump(get_option('wp_user_roles'));

My create_order function nicely creates an order, with the lineitem in the order_items tables.我的 create_order 函数很好地创建了一个订单,其中 lineitem 位于 order_items 表中。

Hope I helped you out, it took me a while to get it right.希望我能帮到你,我花了一段时间才弄好。

A lot of answers do you show the best filter(hook) to use.很多答案是否显示了要使用的最佳过滤器(挂钩)。 I searched for days because when I used the 'init' it kept making more orders.我搜索了好几天,因为当我使用“init”时,它不断发出更多订单。 In 2 mins I had 30 orders.在 2 分钟内,我有 30 个订单。 Anyway use this code and 1 order will be created.无论如何使用此代码,将创建 1 个订单。 Also, change $product = wc_get_product( '1001' ) to your product id.Reference is here on line 144: https://github.com/dipolukarov/wordpress/blob/master/wp-content/plugins/woocommerce/classes/class-wc-checkout.php另外,将 $product = wc_get_product( '1001' ) 更改为您的产品 ID。参考在第 144 行: https : //github.com/dipolukarov/wordpress/blob/master/wp-content/plugins/woocommerce/classes/ class-wc-checkout.php

function my_init2() {
    $order    = wc_create_order();
    $order_id = $order->get_id();
    
    $product = wc_get_product( '10001' );
    
    $address = array(
        'first_name' => 'John2',
        'last_name'  => 'Smith1',
        'email'      => 'johnsmith1@gmail.com',
    );
    //$order->date_created(2020-07-21 );
    $order->add_product( $product, 1 );
    $order->set_address( $address, 'billing' );
    $order->set_created_via( 'programatically' );
    $order->calculate_totals();
    $order->set_total( $product->get_price() );
    $order->update_status( 'wc-completed' );
    
    error_log( '$order_id: ' . $order_id );
    
}          
//add_action('admin_init','my_init2');
function my_run_only_once() {
 
    if ( get_option( 'my_run_only_once_20' ) != 'completed' ) {
  my_init2();
        update_option( 'my_run_only_once_20', 'completed' );
    }
}
add_action( 'admin_init', 'my_run_only_once' );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM