When PayPal sends an IPN subscr_payment
update to WooCommerce I'm using this code inside the valid_paypal_standard_ipn_request
action to create new orders from existing orders. Once in a while the shipping info is empty on the new order. I'm not sure what's causing that, but this is new code so it might be buggy.
All the components of a WooCommerce order are here. I created this from the logic in class-cw-checkout.php
create_order, but used an existing order to provide the values.
<?php
add_action( 'valid-paypal-standard-ipn-request', 'sapce_valid_paypal_standard_ipn_request', 10, 1 );
function sapce_valid_paypal_standard_ipn_request($formdata){
if (!empty($formdata['txn_type'])) {
if ($formdata['txn_type'] === "subscr_signup") {
$custom = unserialize(stripslashes($formdata['custom']));
$order_id = $custom[0];
$payment_profile_id = $formdata['subscr_id'];
addPayPalPaymentProfileIdToAutoShipOrder($order_id, $payment_profile_id);
}
if ($formdata['txn_type'] === "subscr_payment" && $formdata['payment_status'] === "Completed") {
$paypal_transaction_id = $formdata['txn_id'];
$custom = unserialize(stripslashes($formdata['custom']));
$original_order_id = $custom[0];
createNewOrderAndRecordPayment($formdata);
}
if ($formdata['txn_type'] === "subscr_cancel") {
customerCanceledAutoShipOrderFromPayPal($order_id, $payment_profile_id);
}
}
}
<?php
include_once ('../../../wp-load.php');
include_once ('../../../wp-blog-header.php');
function createNewOrderAndRecordPayment($formdata) {
global $wpdb;
global $woocommerce;
$paypal_transaction_id = $formdata['txn_id'];
$custom = unserialize(stripslashes($formdata['custom']));
$original_order_id = $custom[0];
$original_order = new WC_Order($original_order_id);
$currentUser = wp_get_current_user();
writeToLog("Attempting to copy original order: $original_order_id");
//1 Create Order
$order_data = array(
'post_type' => 'shop_order',
'post_title' => sprintf( __( 'Auto-Ship Order – %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) ),
'post_status' => 'publish',
'ping_status' => 'closed',
'post_excerpt' => 'Auto-Ship Order based on original order ' . $original_order_id,
'post_author' => $currentUser->ID,
'post_password' => uniqid( 'order_' ) // Protects the post just in case
);
$order_id = wp_insert_post( $order_data, true );
if ( is_wp_error( $order_id ) ){
$msg = "Unable to create order:" . $order_id->get_error_message();;
throw new Exception( $msg );
} else {
$order = new WC_Order($order_id);
//2 Update Order Header
update_post_meta( $order_id, '_order_shipping', get_post_meta($original_order_id, '_order_shipping', true) );
update_post_meta( $order_id, '_order_discount', get_post_meta($original_order_id, '_order_discount', true) );
update_post_meta( $order_id, '_cart_discount', get_post_meta($original_order_id, '_cart_discount', true) );
update_post_meta( $order_id, '_order_tax', get_post_meta($original_order_id, '_order_tax', true) );
update_post_meta( $order_id, '_order_shipping_tax', get_post_meta($original_order_id, '_order_shipping_tax', true) );
update_post_meta( $order_id, '_order_total', get_post_meta($original_order_id, '_order_total', true) );
update_post_meta( $order_id, '_order_key', 'wc_' . apply_filters('woocommerce_generate_order_key', uniqid('order_') ) );
update_post_meta( $order_id, '_customer_user', get_post_meta($original_order_id, '_customer_user', true) );
update_post_meta( $order_id, '_order_currency', get_post_meta($original_order_id, '_order_currency', true) );
update_post_meta( $order_id, '_prices_include_tax', get_post_meta($original_order_id, '_prices_include_tax', true) );
update_post_meta( $order_id, '_customer_ip_address', get_post_meta($original_order_id, '_customer_ip_address', true) );
update_post_meta( $order_id, '_customer_user_agent', get_post_meta($original_order_id, '_customer_user_agent', true) );
writeToLog("Updated order header");
//3 Add Billing Fields
update_post_meta( $order_id, '_billing_city', get_post_meta($original_order_id, '_billing_city', true));
update_post_meta( $order_id, '_billing_state', get_post_meta($original_order_id, '_billing_state', true));
update_post_meta( $order_id, '_billing_postcode', get_post_meta($original_order_id, '_billing_postcode', true));
update_post_meta( $order_id, '_billing_email', get_post_meta($original_order_id, '_billing_email', true));
update_post_meta( $order_id, '_billing_phone', get_post_meta($original_order_id, '_billing_phone', true));
update_post_meta( $order_id, '_billing_address_1', get_post_meta($original_order_id, '_billing_address_1', true));
update_post_meta( $order_id, '_billing_address_2', get_post_meta($original_order_id, '_billing_address_2', true));
update_post_meta( $order_id, '_billing_country', get_post_meta($original_order_id, '_billing_country', true));
update_post_meta( $order_id, '_billing_first_name', get_post_meta($original_order_id, '_billing_first_name', true));
update_post_meta( $order_id, '_billing_last_name', get_post_meta($original_order_id, '_billing_last_name', true));
update_post_meta( $order_id, '_billing_company', get_post_meta($original_order_id, '_billing_company', true));
writeToLog("Updated billing fields");
//4 Add Shipping Fields
update_post_meta( $order_id, '_shipping_country', get_post_meta($original_order_id, '_shipping_country', true));
update_post_meta( $order_id, '_shipping_first_name', get_post_meta($original_order_id, '_shipping_first_name', true));
update_post_meta( $order_id, '_shipping_last_name', get_post_meta($original_order_id, '_shipping_last_name', true));
update_post_meta( $order_id, '_shipping_company', get_post_meta($original_order_id, '_shipping_company', true));
update_post_meta( $order_id, '_shipping_address_1', get_post_meta($original_order_id, '_shipping_address_1', true));
update_post_meta( $order_id, '_shipping_address_2', get_post_meta($original_order_id, '_shipping_address_2', true));
update_post_meta( $order_id, '_shipping_city', get_post_meta($original_order_id, '_shipping_city', true));
update_post_meta( $order_id, '_shipping_state', get_post_meta($original_order_id, '_shipping_state', true));
update_post_meta( $order_id, '_shipping_postcode', get_post_meta($original_order_id, '_shipping_postcode', true));
writeToLog("Updated shipping fields");
//5 Add Line Items
writeToLog("Adding line items.");
foreach($original_order->get_items() as $originalOrderItem){
$itemName = $originalOrderItem['name'];
$qty = $originalOrderItem['qty'];
$lineTotal = $originalOrderItem['line_total'];
$lineTax = $originalOrderItem['line_tax'];
$productID = $originalOrderItem['product_id'];
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $itemName,
'order_item_type' => 'line_item'
) );
wc_add_order_item_meta( $item_id, '_qty', $qty );
//wc_add_order_item_meta( $item_id, '_tax_class', $_product->get_tax_class() );
wc_add_order_item_meta( $item_id, '_product_id', $productID );
//wc_add_order_item_meta( $item_id, '_variation_id', $values['variation_id'] );
wc_add_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( $lineTotal ) );
wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $lineTotal ) );
wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( '0' ) );
wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( '0' ) );
}
writeToLog("Copying shipping items");
//6 Copy shipping items and shipping item meta from original order
$original_order_shipping_items = $original_order->get_items('shipping');
writeToLog(print_r($original_order_shipping_items));
foreach ( $original_order_shipping_items as $original_order_shipping_item ) {
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $original_order_shipping_item['name'],
'order_item_type' => 'shipping'
) );
if ( $item_id ) {
wc_add_order_item_meta( $item_id, 'method_id', $original_order_shipping_item['method_id'] );
wc_add_order_item_meta( $item_id, 'cost', wc_format_decimal( $original_order_shipping_item['cost'] ) );
}
}
writeToLog("Copying store coupons");
// Store coupons
$original_order_coupons = $original_order->get_items('coupon');
foreach ( $original_order_coupons as $original_order_coupon ) {
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $original_order_coupon['name'],
'order_item_type' => 'coupon'
) );
// Add line item meta
if ( $item_id ) {
wc_add_order_item_meta( $item_id, 'discount_amount', $original_order_coupon['discount_amount'] );
}
}
writeToLog("Setting payment info");
//Payment Info
update_post_meta( $order_id, '_payment_method', get_post_meta($original_order_id, '_payment_method', true) );
update_post_meta( $order_id, '_payment_method_title', get_post_meta($original_order_id, '_payment_method_title', true) );
update_post_meta( $order->id, 'Transaction ID', get_post_meta($original_order_id, 'Transaction ID', true) );
$order->payment_complete();
writeToLog("Setting order to processing");
//6 Set Order Status to processing to trigger initial emails to end user and vendor
$updateNote = "This Auto-Ship order was created by SAP Commerce Engine, per PayPal payment installment.";
$order->update_status('processing');
$order->add_order_note($updateNote);
writeToLog("Auto-Ship Order copy complete.");
}
}