class-wcs-upgrade-1-2.php
13.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
<?php
/**
* Update Subscriptions to 1.2.0
*
* Version 1.2 introduced a massive change to the order meta data schema. This goes through
* and upgrades the existing data on all orders to the new schema.
*
* The upgrade process is timeout safe as it keeps a record of the orders upgraded and only
* deletes this record once all orders have been upgraded successfully. If operating on a huge
* number of orders and the upgrade process times out, only the orders not already upgraded
* will be upgraded in future requests that trigger this function.
*
* @author Prospress
* @category Admin
* @package WooCommerce Subscriptions/Admin/Upgrades
* @version 1.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class WCS_Upgrade_1_2 {
public function init() {
global $wpdb;
// Get IDs only and use a direct DB query for efficiency
$orders_to_upgrade = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_type = 'shop_order' AND post_parent = 0" );
$upgraded_orders = get_option( 'wcs_1_2_upgraded_order_ids', array() );
// Transition deprecated subscription status if we aren't in the middle of updating orders
if ( empty( $upgraded_orders ) ) {
$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->usermeta SET meta_value = replace( meta_value, 's:9:\"suspended\"', 's:7:\"on-hold\"' ) WHERE meta_key LIKE %s", '%_woocommerce_subscriptions' ) );
$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->usermeta SET meta_value = replace( meta_value, 's:6:\"failed\"', 's:9:\"cancelled\"' ) WHERE meta_key LIKE %s", '%_woocommerce_subscriptions' ) );
}
$orders_to_upgrade = array_diff( $orders_to_upgrade, $upgraded_orders );
// Upgrade all _sign_up_{field} order meta to new order data format
foreach ( $orders_to_upgrade as $order_id ) {
$order = new WC_Order( $order_id );
// Manually check if a product in an order is a subscription, we can't use wcs_order_contains_subscription( $order ) because it relies on the new data structure
$contains_subscription = false;
foreach ( $order->get_items() as $order_item ) {
if ( WC_Subscriptions_Product::is_subscription( WC_Subscriptions_Order::get_items_product_id( $order_item ) ) ) {
$contains_subscription = true;
break;
}
}
if ( ! $contains_subscription ) {
continue;
}
$trial_lengths = WC_Subscriptions_Order::get_meta( $order, '_order_subscription_trial_lengths', array() );
$trial_length = array_pop( $trial_lengths );
$has_trial = ( ! empty( $trial_length ) && $trial_length > 0 ) ? true : false ;
$sign_up_fee_total = WC_Subscriptions_Order::get_meta( $order, '_sign_up_fee_total', 0 );
// Create recurring_* meta data from existing cart totals
$cart_discount = $order->get_cart_discount();
update_post_meta( $order_id, '_order_recurring_discount_cart', $cart_discount );
$order_discount = $order->get_order_discount();
update_post_meta( $order_id, '_order_recurring_discount_total', $order_discount );
$order_shipping_tax = get_post_meta( $order_id, '_order_shipping_tax', true );
update_post_meta( $order_id, '_order_recurring_shipping_tax_total', $order_shipping_tax );
$order_tax = get_post_meta( $order_id, '_order_tax', true ); // $order->get_total_tax() includes shipping tax
update_post_meta( $order_id, '_order_recurring_tax_total', $order_tax );
$order_total = $order->get_total();
update_post_meta( $order_id, '_order_recurring_total', $order_total );
// Set order totals to include sign up fee fields, if there was a sign up fee on the order and a trial period (other wise, the recurring totals are correct)
if ( $sign_up_fee_total > 0 ) {
// Order totals need to be changed to be equal to sign up fee totals
if ( $has_trial ) {
$cart_discount = WC_Subscriptions_Order::get_meta( $order, '_sign_up_fee_discount_cart', 0 );
$order_discount = WC_Subscriptions_Order::get_meta( $order, '_sign_up_fee_discount_total', 0 );
$order_tax = WC_Subscriptions_Order::get_meta( $order, '_sign_up_fee_tax_total', 0 );
$order_total = $sign_up_fee_total;
} else { // No trial, sign up fees need to be added to order totals
$cart_discount += WC_Subscriptions_Order::get_meta( $order, '_sign_up_fee_discount_cart', 0 );
$order_discount += WC_Subscriptions_Order::get_meta( $order, '_sign_up_fee_discount_total', 0 );
$order_tax += WC_Subscriptions_Order::get_meta( $order, '_sign_up_fee_tax_total', 0 );
$order_total += $sign_up_fee_total;
}
update_post_meta( $order_id, '_order_total', $order_total );
update_post_meta( $order_id, '_cart_discount', $cart_discount );
update_post_meta( $order_id, '_order_discount', $order_discount );
update_post_meta( $order_id, '_order_tax', $order_tax );
}
// Make sure we get order taxes in WC 1.x format
if ( false == WC_Subscriptions_Upgrader::$is_wc_version_2 ) {
$order_taxes = $order->get_taxes();
} else {
$order_tax_row = $wpdb->get_row( $wpdb->prepare( "
SELECT * FROM {$wpdb->postmeta}
WHERE meta_key = '_order_taxes_old'
AND post_id = %s
", $order_id )
);
$order_taxes = (array) maybe_unserialize( $order_tax_row->meta_value );
}
// Set recurring taxes to order taxes, if using WC 2.0, this will be migrated to the new format in @see WC_Subscriptions_Upgrader::upgrade_to_latest_wc()
update_post_meta( $order_id, '_order_recurring_taxes', $order_taxes );
$sign_up_fee_taxes = WC_Subscriptions_Order::get_meta( $order, '_sign_up_fee_taxes', array() );
// Update order taxes to include sign up fee taxes
foreach ( $sign_up_fee_taxes as $index => $sign_up_tax ) {
if ( $has_trial && $sign_up_fee_total > 0 ) { // Order taxes need to be set to the same as the sign up fee taxes
if ( isset( $sign_up_tax['cart_tax'] ) && $sign_up_tax['cart_tax'] > 0 ) {
$order_taxes[ $index ]['cart_tax'] = $sign_up_tax['cart_tax'];
}
} elseif ( ! $has_trial && $sign_up_fee_total > 0 ) { // Sign up fee taxes need to be added to order taxes
if ( isset( $sign_up_tax['cart_tax'] ) && $sign_up_tax['cart_tax'] > 0 ) {
$order_taxes[ $index ]['cart_tax'] += $sign_up_tax['cart_tax'];
}
}
}
if ( false == WC_Subscriptions_Upgrader::$is_wc_version_2 ) { // Doing it right: updated Subs *before* updating WooCommerce, the WooCommerce updater will take care of data migration
update_post_meta( $order_id, '_order_taxes', $order_taxes );
} else { // Doing it wrong: updated Subs *after* updating WooCommerce, need to store in WC2.0 tax structure
$index = 0;
$new_order_taxes = $order->get_taxes();
foreach ( $new_order_taxes as $item_id => $order_tax ) {
$index = $index + 1;
if ( ! isset( $order_taxes[ $index ]['label'] ) || ! isset( $order_taxes[ $index ]['cart_tax'] ) || ! isset( $order_taxes[ $index ]['shipping_tax'] ) ) {
continue;
}
// Add line item meta
if ( $item_id ) {
wc_update_order_item_meta( $item_id, 'compound', absint( isset( $order_taxes[ $index ]['compound'] ) ? $order_taxes[ $index ]['compound'] : 0 ) );
wc_update_order_item_meta( $item_id, 'tax_amount', wc_format_decimal( $order_taxes[ $index ]['cart_tax'] ) );
wc_update_order_item_meta( $item_id, 'shipping_tax_amount', wc_format_decimal( $order_taxes[ $index ]['shipping_tax'] ) );
}
}
}
/* Upgrade each order item to use new Item Meta schema */
$order_subscription_periods = WC_Subscriptions_Order::get_meta( $order_id, '_order_subscription_periods', array() );
$order_subscription_intervals = WC_Subscriptions_Order::get_meta( $order_id, '_order_subscription_intervals', array() );
$order_subscription_lengths = WC_Subscriptions_Order::get_meta( $order_id, '_order_subscription_lengths', array() );
$order_subscription_trial_lengths = WC_Subscriptions_Order::get_meta( $order_id, '_order_subscription_trial_lengths', array() );
$order_items = $order->get_items();
foreach ( $order_items as $index => $order_item ) {
$product_id = WC_Subscriptions_Order::get_items_product_id( $order_item );
$item_meta = new WC_Order_Item_Meta( $order_item['item_meta'] );
$subscription_interval = ( isset( $order_subscription_intervals[ $product_id ] ) ) ? $order_subscription_intervals[ $product_id ] : 1;
$subscription_length = ( isset( $order_subscription_lengths[ $product_id ] ) ) ? $order_subscription_lengths[ $product_id ] : 0;
$subscription_trial_length = ( isset( $order_subscription_trial_lengths[ $product_id ] ) ) ? $order_subscription_trial_lengths[ $product_id ] : 0;
$subscription_sign_up_fee = WC_Subscriptions_Order::get_meta( $order, '_cart_contents_sign_up_fee_total', 0 );
if ( $sign_up_fee_total > 0 ) {
// Discounted price * Quantity
$sign_up_fee_line_total = WC_Subscriptions_Order::get_meta( $order, '_cart_contents_sign_up_fee_total', 0 );
$sign_up_fee_line_tax = WC_Subscriptions_Order::get_meta( $order, '_sign_up_fee_tax_total', 0 );
// Base price * Quantity
$sign_up_fee_line_subtotal = WC_Subscriptions_Order::get_meta( $order, '_cart_contents_sign_up_fee_total', 0 ) + WC_Subscriptions_Order::get_meta( $order, '_sign_up_fee_discount_cart', 0 );
$sign_up_fee_propotion = ( $sign_up_fee_line_total > 0 ) ? $sign_up_fee_line_subtotal / $sign_up_fee_line_total : 0;
$sign_up_fee_line_subtotal_tax = WC_Subscriptions_Manager::get_amount_from_proportion( WC_Subscriptions_Order::get_meta( $order, '_sign_up_fee_tax_total', 0 ), $sign_up_fee_propotion );
if ( $has_trial ) { // Set line item totals equal to sign up fee totals
$order_item['line_subtotal'] = $sign_up_fee_line_subtotal;
$order_item['line_subtotal_tax'] = $sign_up_fee_line_subtotal_tax;
$order_item['line_total'] = $sign_up_fee_line_total;
$order_item['line_tax'] = $sign_up_fee_line_tax;
} else { // No trial period, sign up fees need to be added to order totals
$order_item['line_subtotal'] += $sign_up_fee_line_subtotal;
$order_item['line_subtotal_tax'] += $sign_up_fee_line_subtotal_tax;
$order_item['line_total'] += $sign_up_fee_line_total;
$order_item['line_tax'] += $sign_up_fee_line_tax;
}
}
// Upgrading with WC 1.x
if ( method_exists( $item_meta, 'add' ) ) {
$item_meta->add( '_subscription_period', $order_subscription_periods[ $product_id ] );
$item_meta->add( '_subscription_interval', $subscription_interval );
$item_meta->add( '_subscription_length', $subscription_length );
$item_meta->add( '_subscription_trial_length', $subscription_trial_length );
$item_meta->add( '_subscription_recurring_amount', $order_item['line_subtotal'] ); // WC_Subscriptions_Product::get_price() would return a price without filters applied
$item_meta->add( '_subscription_sign_up_fee', $subscription_sign_up_fee );
// Set recurring amounts for the item
$item_meta->add( '_recurring_line_total', $order_item['line_total'] );
$item_meta->add( '_recurring_line_tax', $order_item['line_tax'] );
$item_meta->add( '_recurring_line_subtotal', $order_item['line_subtotal'] );
$item_meta->add( '_recurring_line_subtotal_tax', $order_item['line_subtotal_tax'] );
$order_item['item_meta'] = $item_meta->meta;
$order_items[ $index ] = $order_item;
} else { // Ignoring all advice, upgrading 4 months after version 1.2 was released, and doing it with WC 2.0 installed
wc_add_order_item_meta( $index, '_subscription_period', $order_subscription_periods[ $product_id ] );
wc_add_order_item_meta( $index, '_subscription_interval', $subscription_interval );
wc_add_order_item_meta( $index, '_subscription_length', $subscription_length );
wc_add_order_item_meta( $index, '_subscription_trial_length', $subscription_trial_length );
wc_add_order_item_meta( $index, '_subscription_trial_period', $order_subscription_periods[ $product_id ] );
wc_add_order_item_meta( $index, '_subscription_recurring_amount', $order_item['line_subtotal'] );
wc_add_order_item_meta( $index, '_subscription_sign_up_fee', $subscription_sign_up_fee );
// Calculated recurring amounts for the item
wc_add_order_item_meta( $index, '_recurring_line_total', $order_item['line_total'] );
wc_add_order_item_meta( $index, '_recurring_line_tax', $order_item['line_tax'] );
wc_add_order_item_meta( $index, '_recurring_line_subtotal', $order_item['line_subtotal'] );
wc_add_order_item_meta( $index, '_recurring_line_subtotal_tax', $order_item['line_subtotal_tax'] );
if ( $sign_up_fee_total > 0 ) { // Order totals have changed
wc_update_order_item_meta( $index, '_line_subtotal', wc_format_decimalw( $order_item['line_subtotal'] ) );
wc_update_order_item_meta( $index, '_line_subtotal_tax', wc_format_decimal( $order_item['line_subtotal_tax'] ) );
wc_update_order_item_meta( $index, '_line_total', wc_format_decimal( $order_item['line_total'] ) );
wc_update_order_item_meta( $index, '_line_tax', wc_format_decimal( $order_item['line_tax'] ) );
}
}
}
// Save the new meta on the order items for WC 1.x (the API functions already saved the data for WC2.x)
if ( false == WC_Subscriptions_Upgrader::$is_wc_version_2 ) {
update_post_meta( $order_id, '_order_items', $order_items );
}
$upgraded_orders[] = $order_id;
update_option( 'wcs_1_2_upgraded_order_ids', $upgraded_orders );
}
}
}
WCS_Upgrade_1_2::init();