WooCommerce: creación de un pedido mediante programación con un producto variable

5 minutos de lectura

Estoy tratando de crear un pedido mediante programación. Usando wc_create_order() Esto es bastante sencillo:

$myProduct = new WC_Product(100);
$order = wc_create_order();
$order->add_product($myProduct, 1);
$order->calculate_totals();

Esto funciona como se esperaba y se crea un pedido para un producto simple con ID 100 por la cantidad correcta.

Sin embargo, si trato de hacer esto con una variación, no parece comportarse correctamente. Después de mucho ensayo y error, lo conseguí. algo así como trabajar de esta manera:

$membershipProduct = new WC_Product_Variable(100);
$theMemberships = $membershipProduct->get_available_variations();

$trueProduct = new WC_Product(100);

$variationsArray = array();

foreach ($theMemberships as $membership) {
    if ($membership['sku'] == $chosenVariation) {
        $variationID = $membership['variation_id'];
        $variationsArray = $membership['attributes'];
    }
}

if ($variationID) {
    $trueProduct->variation_id = $variationID;
}

$order = wc_create_order();
$order->add_product($trueProduct, 1, $variationsArray);
$order->calculate_totals();

Sin embargo, aunque crea el pedido con el producto correcto y el ID de variación correcto, el total del pedido siempre es 0 (que, casualmente, es el precio de la primera variación).

Originalmente estaba intentando $order->add_product() con el objeto creado a partir de new WC_Product_Variable(), pero eso dio como resultado que no se agregaran productos al pedido, lo que me lleva a creer que es un problema con la creación de pedidos mediante programación con productos variables. Sin embargo, siguiendo el código fuente de WooCommerce para estas llamadas, no puedo ver qué estoy haciendo mal.

¿Hay algo que me estoy perdiendo o hay una mejor manera de crear un pedido con un producto variable?

  • No sé la respuesta completa, pero seguro que te falta el tercer parámetro de add_product( $product, $qty = 1, $args = array() ). tienes que pasar $args = array('variation' => $something );. Todavía no estoy seguro de cómo eso $something necesita ser formateado.

    – helgathevikingo

    13 de septiembre de 2015 a las 2:16

  • @helgatheviking Ah, tienes toda la razón: yo estaba pasando una matriz como tercer parámetro (en el segundo ejemplo), pero no me había dado cuenta de que necesitaba el 'variation' llave. he añadido que ($variationsArray['variation'] = $membership['attributes'];) y ahora el artículo aparece ‘correctamente’ en el pedido (es decir, es la variación correcta del producto correcto), pero el precio sigue siendo incorrecto. ¡No tengo idea de lo que me estoy perdiendo!

    – índicedos

    13 de septiembre de 2015 a las 9:42

avatar de usuario
índicedos

Resuelto.

Aunque podría haber jurado que había intentado (y fallado) hacerlo de esta manera, la respuesta fue no agregar el padre producto ($trueProduct en el ejemplo), pero para agregar el producto de variación por su IDENTIFICACIÓN.

Esto puede haber fallado anteriormente porque, como señaló @helgatheviking, mi $variationsArray fue formateado incorrectamente de acuerdo con el fuente; Necesitaba una matriz con un ['variation'] clave para enviar la matriz de variación de atributos correcta.

En total, mi código de trabajo ahora se ve así:

$membershipProduct = new WC_Product_Variable(100);
$theMemberships = $membershipProduct->get_available_variations();

$variationsArray = array();

foreach ($theMemberships as $membership) {
    if ($membership['sku'] == $chosenVariation) {
        $variationID = $membership['variation_id'];
        $variationsArray['variation'] = $membership['attributes'];
    }
}

if ($variationID) {
    $varProduct = new WC_Product_Variation($variationID);

    $order = wc_create_order();
    $order->add_product($varProduct, 1, $variationsArray);
    $order->calculate_totals();
}

  • Está bien que te hayas dado cuenta. Recuerdo haber pedido que el agregado regular al carrito admitiera la adición directa por identificación de variación y fue derribado, por lo que nunca hubiera pensado en hacer esto.

    – helgathevikingo

    15 de septiembre de 2015 a las 11:16

  • @helgatheviking De hecho, tuve que hacer esto de diferentes maneras para un par de proyectos diferentes, incluida la adición de una variación directamente a través de AJAX (similar a la forma en que mencionaste). Necesito marcar esto, o definitivamente olvidaré cómo hacerlo la próxima vez.

    – índice dos

    15 de septiembre de 2015 a las 12:29

  • Esta es la tercera vez que esta respuesta exacta me ha sido útil. Si tan solo pudiera votar tu respuesta de nuevo.

    – tejón gato

    21 de febrero de 2020 a las 2:43

avatar de usuario
abhinav penmetsa

si ya tienes elvariation_id puedes hacer esto

$product_variation = new WC_Product_Variation($variation_id);
$order = wc_create_order();
$args=array();
foreach($product_variation->get_variation_attributes() as $attribute=>$attribute_value){
        $args['variation'][$attribute]=$attribute_value;
}
$order->add_product($product_variation, $product['quantity'], $args);

Aquí está la solución que funcionó para mí:

function add_item_to_order( $order_id, $prod_id ) {

    $order      = wc_get_order( $order_id );
    $_product   = wc_get_product( $prod_id ); 

    // Set values
    $item = array();
    $item['product_id']        = $_product->id;
    $item['variation_id']      = isset( $_product->variation_id ) ? $_product->variation_id : '';
    $item['variation_data']    = $item['variation_id'] ? $_product->get_variation_attributes() : '';
    $item['name']              = $_product->get_title();
    $item['tax_class']         = $_product->get_tax_class();
    $item['qty']               = 1;
    $item['line_subtotal']     = wc_format_decimal( $_product->get_price_excluding_tax() );
    $item['line_subtotal_tax'] = '';
    $item['line_total']        = wc_format_decimal( $_product->get_price_excluding_tax() );
    $item['line_tax']          = '';
    $item['type']              = 'line_item';

    // Add line item
    $item_id = wc_add_order_item( $order_id, array(
        'order_item_name'       => $item['name'],
        'order_item_type'       => 'line_item'
    ) );

    // Add line item meta
    if ( $item_id ) {
        wc_add_order_item_meta( $item_id, '_qty', $item['qty'] );
        wc_add_order_item_meta( $item_id, '_tax_class', $item['tax_class'] );
        wc_add_order_item_meta( $item_id, '_product_id', $item['product_id'] );
        wc_add_order_item_meta( $item_id, '_variation_id', $item['variation_id'] );
        wc_add_order_item_meta( $item_id, '_line_subtotal', $item['line_subtotal'] );
        wc_add_order_item_meta( $item_id, '_line_subtotal_tax', $item['line_subtotal_tax'] );
        wc_add_order_item_meta( $item_id, '_line_total', $item['line_total'] );
        wc_add_order_item_meta( $item_id, '_line_tax', $item['line_tax'] );
        wc_add_order_item_meta( $item_id, '_line_tax_data', array( 
                                                                    'total' => array(), 
                                                                    'subtotal' => array() ) 
                                                                 );
        // Store variation data in meta
        if ( $item['variation_data'] && is_array( $item['variation_data'] ) ) {
            foreach ( $item['variation_data'] as $key => $value ) {
                wc_add_order_item_meta( $item_id, str_replace( 'attribute_', '', $key ), $value );
            }
        }

    }

    $item['item_meta']       = $order->get_item_meta( $item_id );
    $item['item_meta_array'] = $order->get_item_meta_array( $item_id );
    $item                    = $order->expand_item_meta( $item );
    $order->calculate_totals();
}

  • Hola @Tyler me da error que Fatal error: Call to a member function get_title() on a non-object. ¿pueden ayudarme a resolver este problema?

    – kuldip makadiya

    20 de abril de 2018 a las 12:09

¿Ha sido útil esta solución?