Come utilizzare wc_create_order con prodotti in abbonamento

16 set 2015, 17:39:11
Visualizzazioni: 24.8K
Voti: 5

Voglio creare un nuovo ordine programmaticamente.

Questo codice funziona bene con prodotti semplici,

    $product = get_product($product_id);
    $order = wc_create_order();
    $order->add_product( $product , 1 );
    $order->calculate_totals();
    // assegna l'ordine all'utente corrente
    update_post_meta($order->id, '_customer_user', get_current_user_id() );
    // completa il pagamento
    $order->payment_complete();

ma quando lo uso per un prodotto in abbonamento non aggiunge l'abbonamento, aggiunge solo l'ordine.

0
Tutte le risposte alla domanda 3
6
19

Ecco il mio codice per creare un abbonamento - ci sono voluti molti tentativi ed errori per capire tutto. Buona fortuna!

function create_test_sub() {

    $email = 'test@test.com';

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

    $address = array(
        'first_name' => 'Jeremy',
        'last_name'  => 'Test',
        'company'    => '',
        'email'      => $email,
        'phone'      => '777-777-777-777',
        'address_1'  => '31 Main Street',
        'address_2'  => '', 
        'city'       => 'Auckland',
        '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 );

    // Ho usato un prodotto con più varianti

    $parent_product = wc_get_product(22998);

    $args = array(
        'attribute_billing-period' => 'Yearly',
        'attribute_subscription-type' => 'Both'
    );

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

    $product = wc_get_product($product_variation);  

    // Ogni variante ha anche la sua classe di spedizione

    $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();

    // Ho una logica per selezionare quale metodo di spedizione usare; il tuo caso d'uso sarà probabilmente diverso, quindi individua il metodo che ti serve e memorizzalo in $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;

    // Per quanto ne so, devi prima creare l'ordine, poi l'abbonamento

    $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", 'Ordine importato', TRUE);

    // Ordine creato, ora crea l'abbonamento collegato - opzionale se non stai creando un abbonamento

    // Ogni variante ha un periodo di abbonamento diverso

    $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'>Abbonamento creato! Clicca qui per modificare</a>";
}
10 feb 2016 01:07:01
Commenti

Grazie per questo, ma non riesco a farlo funzionare. Qual è la funzione wcs_create_subscription()? Non è definita, e nemmeno wc_create_subscription() se è un errore di battitura.

Pekz0r Pekz0r
24 feb 2016 16:09:55

Avrai bisogno dell'estensione Subscriptions per far funzionare quella parte! (Non dimenticare che puoi cercare i nomi delle funzioni su Google, di solito sono molto facili da trovare perché sono molto specifici.)

Jeremy Warne Jeremy Warne
25 feb 2016 04:26:12

Sì, avevo il plugin Subscriptions, ma sembra che avessi una versione più vecchia (1.5.). L'ho aggiornata alla 2.0. ora e il codice sembra funzionare. Grazie mille!

Pekz0r Pekz0r
25 feb 2016 11:11:20

Ottimo caso d'uso ed esempio di wc_create_order + wcs_create_subscription!

Scott Kingsley Clark Scott Kingsley Clark
21 apr 2016 09:34:52

Continuo a ricevere Call to undefined method WP_Error::add_product() qualche idea?

Kravitz Kravitz
9 set 2019 23:12:22

@Kravitz controlla su quale riga si verifica l'errore e fai if (is_wp_error($order) var_dump($order) o la stessa riga con $sub invece di $order, prima della chiamata a add_product(). Questo ti dirà cosa sta andando storto.

Jeremy Warne Jeremy Warne
10 set 2019 03:03:35
Mostra i restanti 1 commenti
1

Ecco un esempio

     $order_data = array(
        'status'        => 'completato',
        'customer_id'   => 1,
        'customer_note' => '',
        'total'         => '',
    );

    $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // Obbligatorio, altrimenti wc_create_order genera un'eccezione
    $order                  = wc_create_order( $order_data );
25 dic 2015 15:55:44
Commenti

per favore cerca di evitare risposte con solo codice senza spiegare perché risolvono il problema

Mark Kaplun Mark Kaplun
25 dic 2015 17:06:53
0

Sfortunatamente devi gestire manualmente la creazione dell'abbonamento tramite codice, poiché semplicemente aggiungendo un ordine non viene gestito automaticamente.

Ecco la mia funzione personalizzata che ho creato basandomi su tutte le risposte trovate su Stack Overflow e scavando nel codice base di Subscriptions.

Testato con:

  • 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 = '' ){
    // Prima verifica che tutte le funzioni e classi richieste esistano
    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', // Lo stato dovrebbe essere inizialmente impostato su pending per corrispondere al normale processo di checkout
        'billing_period' => WC_Subscriptions_Product::get_period( $product ),
        'billing_interval' => WC_Subscriptions_Product::get_interval( $product )
    ));

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

    // Modellato su WC_Subscriptions_Cart::calculate_subscription_totals()
    $start_date = gmdate( 'Y-m-d H:i:s' );
    // Aggiungi prodotto all'abbonamento
    $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();

    // Aggiorna lo stato dell'ordine con una nota personalizzata
    $note = ! empty( $note ) ? $note : __( 'Ordine e abbonamento aggiunti programmaticamente.' );
    $order->update_status( 'completed', $note, true );

    // Aggiorna anche lo stato dell'abbonamento da pending ad active (e aggiungi nota)
    $sub->update_status( 'active', $note, true );
    return $sub;
}
14 nov 2019 20:41:15