как использовать wc_create_order с подписочным продуктом

16 сент. 2015 г., 17:39:11
Просмотры: 24.8K
Голосов: 5

Я хочу программно создать новый заказ.

Этот код хорошо работает с простым продуктом,

    $product = get_product($product_id);
    $order = wc_create_order();
    $order->add_product( $product , 1 );
    $order->calculate_totals();
    // назначаем заказ текущему пользователю
    update_post_meta($order->id, '_customer_user', get_current_user_id() );
    // завершение оплаты
    $order->payment_complete();

но когда я использую его для подписочного продукта, он не добавляет подписку, а создает только заказ.

0
Все ответы на вопрос 3
6
19

Вот мой код для создания подписки — потребовалось много проб и ошибок, чтобы во всем разобраться. Удачи!

function create_test_sub() {

    $email = 'test@test.com';

    $start_date = '2015-01-01 00:00:00';

    $address = array(
        'first_name' => 'Джереми',
        'last_name'  => 'Тест',
        'company'    => '',
        'email'      => $email,
        'phone'      => '777-777-777-777',
        'address_1'  => '31 Main Street',
        'address_2'  => '', 
        'city'       => 'Окленд',
        'state'      => 'AKL',
        'postcode'   => '12345',
        'country'    => 'AU'
    );

    $default_password = wp_generate_password();

    if (!$user = get_user_by('login', $email)) $user = wp_create_user( $email, $default_password, $email );

    // Я использовал один товар с несколькими вариациями

    $parent_product = wc_get_product(22998);

    $args = array(
        'attribute_billing-period' => 'Ежегодно',
        'attribute_subscription-type' => 'Оба'
    );

    $product_variation = $parent_product->get_matching_variation($args);

    $product = wc_get_product($product_variation);  

    // Каждая вариация также имеет свой собственный класс доставки

    $shipping_class = get_term_by('slug', $product->get_shipping_class(), 'product_shipping_class');

    WC()->shipping->load_shipping_methods();
    $shipping_methods = WC()->shipping->get_shipping_methods();

    // У меня есть логика для выбора способа доставки; ваш случай, скорее всего, будет другим, поэтому определите нужный метод и сохраните его в $selected_shipping_method

    $selected_shipping_method = $shipping_methods['free_shipping'];

    $class_cost = $selected_shipping_method->get_option('class_cost_' . $shipping_class->term_id);

    $quantity = 1;

    // Насколько я понимаю, сначала нужно создать заказ, затем подписку

    $order = wc_create_order(array('customer_id' => $user->id));

    $order->add_product( $product, $quantity, $args);
    $order->set_address( $address, 'billing' );
    $order->set_address( $address, 'shipping' );

    $order->add_shipping((object)array (
        'id' => $selected_shipping_method->id,
        'label'    => $selected_shipping_method->title,
        'cost'     => (float)$class_cost,
        'taxes'    => array(),
        'calc_tax'  => 'per_order'
    ));

    $order->calculate_totals();

    $order->update_status("completed", 'Импортированный заказ', TRUE);

    // Заказ создан, теперь создаем подписку, привязанную к нему — опционально, если вы не создаете подписку

    // Каждая вариация имеет разный период подписки

    $period = WC_Subscriptions_Product::get_period( $product );
    $interval = WC_Subscriptions_Product::get_interval( $product );

    $sub = wcs_create_subscription(array('order_id' => $order->id, 'billing_period' => $period, 'billing_interval' => $interval, 'start_date' => $start_date));

    $sub->add_product( $product, $quantity, $args);
    $sub->set_address( $address, 'billing' );
    $sub->set_address( $address, 'shipping' );

    $sub->add_shipping((object)array (
        'id' => $selected_shipping_method->id,
        'label'    => $selected_shipping_method->title,
        'cost'     => (float)$class_cost,
        'taxes'    => array(),
        'calc_tax'  => 'per_order'
    ));

    $sub->calculate_totals();

    WC_Subscriptions_Manager::activate_subscriptions_for_order($order);

    print "<a href='/wp-admin/post.php?post=" . $sub->id . "&action=edit'>Подписка создана! Нажмите здесь для редактирования</a>";
}
10 февр. 2016 г. 01:07:01
Комментарии

Спасибо за это, но у меня не получается заставить это работать. Что это за функция wcs_create_subscription()? Она не определена, как и wc_create_subscription(), если это опечатка.

Pekz0r Pekz0r
24 февр. 2016 г. 16:09:55

Для работы этой части вам понадобится расширение Subscriptions! (Не забывайте, что вы можете погуглить названия функций - их обычно очень легко найти, потому что они очень специфичны.)

Jeremy Warne Jeremy Warne
25 февр. 2016 г. 04:26:12

Да, у меня был плагин Subscriptions, но, похоже, у меня была старая версия (1.5.). Я обновился до 2.0., и теперь код, кажется, работает. Большое спасибо!

Pekz0r Pekz0r
25 февр. 2016 г. 11:11:20

Отличный пример использования wc_create_order + wcs_create_subscription!

Scott Kingsley Clark Scott Kingsley Clark
21 апр. 2016 г. 09:34:52

У меня постоянно возникает ошибка Call to undefined method WP_Error::add_product(), есть идеи в чем дело?

Kravitz Kravitz
9 сент. 2019 г. 23:12:22

@Kravitz проверьте, на какой строке возникает ошибка, и добавьте перед вызовом add_product() строку if (is_wp_error($order) var_dump($order) или аналогичную с $sub вместо $order. Это поможет понять в чем проблема.

Jeremy Warne Jeremy Warne
10 сент. 2019 г. 03:03:35
Показать остальные 1 комментариев
1

Вот пример:

     $order_data = array(
        'status'        => 'completed', // Статус заказа
        'customer_id'   => 1,         // ID покупателя
        'customer_note' => '',         // Примечание покупателя
        'total'         => '',         // Общая сумма
    );

    $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // Обязательно, иначе wc_create_order выбросит исключение
    $order                  = wc_create_order( $order_data ); // Создание заказа
25 дек. 2015 г. 15:55:44
Комментарии

пожалуйста, старайтесь избегать ответов, содержащих только код, без объяснения, почему они решают проблему

Mark Kaplun Mark Kaplun
25 дек. 2015 г. 17:06:53
0

К сожалению, вам придется вручную обрабатывать создание подписки через код, так как простое добавление заказа не обрабатывает это автоматически.

Вот моя пользовательская функция, которую я создал на основе всех ответов, найденных на Stack Overflow, и изучения кодовой базы подписок.

Протестировано с:

  • WordPress 5.2.5
  • WooCommerce 3.8.0
  • WooCommerce Subscriptions 2.6.1

https://gist.github.com/tripflex/a3123052f36daf18f7cb05391d752223

function give_user_subscription( $product, $user_id, $note = '' ){
    // Сначала проверяем существование всех необходимых функций и классов
    if( ! function_exists( 'wc_create_order' ) || ! function_exists( 'wcs_create_subscription' ) || ! class_exists( 'WC_Subscriptions_Product' ) ){
        return false;
    }

    $order = wc_create_order( array( 'customer_id' => $user_id ) );
    if( is_wp_error( $order ) ){
        return false;
    }

    $user = get_user_by( 'ID', $user_id );

    $fname     = $user->first_name;
    $lname     = $user->last_name;
    $email     = $user->user_email;
    $address_1 = get_user_meta( $user_id, 'billing_address_1', true );
    $address_2 = get_user_meta( $user_id, 'billing_address_2', true );
    $city      = get_user_meta( $user_id, 'billing_city', true );
    $postcode  = get_user_meta( $user_id, 'billing_postcode', true );
    $country   = get_user_meta( $user_id, 'billing_country', true );
    $state     = get_user_meta( $user_id, 'billing_state', true );
    $address         = array(
        'first_name' => $fname,
        'last_name'  => $lname,
        'email'      => $email,
        'address_1'  => $address_1,
        'address_2'  => $address_2,
        'city'       => $city,
        'state'      => $state,
        'postcode'   => $postcode,
        'country'    => $country,
    );

    $order->set_address( $address, 'billing' );
    $order->set_address( $address, 'shipping' );
    $order->add_product( $product, 1 );

    $sub = wcs_create_subscription(array(
        'order_id' => $order->get_id(),
        'status' => 'pending', // Статус должен быть изначально установлен в pending, чтобы соответствовать обычному процессу оформления заказа
        'billing_period' => WC_Subscriptions_Product::get_period( $product ),
        'billing_interval' => WC_Subscriptions_Product::get_interval( $product )
    ));

    if( is_wp_error( $sub ) ){
        return false;
    }

    // Смоделировано по WC_Subscriptions_Cart::calculate_subscription_totals()
    $start_date = gmdate( 'Y-m-d H:i:s' );
    // Добавляем продукт в подписку
    $sub->add_product( $product, 1 );

    $dates = array(
        'trial_end'    => WC_Subscriptions_Product::get_trial_expiration_date( $product, $start_date ),
        'next_payment' => WC_Subscriptions_Product::get_first_renewal_payment_date( $product, $start_date ),
        'end'          => WC_Subscriptions_Product::get_expiration_date( $product, $start_date ),
    );

    $sub->update_dates( $dates );
    $sub->calculate_totals();

    // Обновляем статус заказа с пользовательской заметкой
    $note = ! empty( $note ) ? $note : __( 'Заказ и подписка добавлены программно.' );
    $order->update_status( 'completed', $note, true );

    // Также обновляем статус подписки с pending на active (и добавляем заметку)
    $sub->update_status( 'active', $note, true );
    return $sub;
}
14 нояб. 2019 г. 20:41:15