Completed
Push — master ( 1c592b...3f9388 )
by Mike
15:22
created

WC_Order::create()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 38
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 34
nc 2
nop 0
dl 0
loc 38
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
if ( ! defined( 'ABSPATH' ) ) {
4
	exit;
5
}
6
7
/**
8
 * Order Class.
9
 *
10
 * These are regular WooCommerce orders, which extend the abstract order class.
11
 *
12
 * @class    WC_Order
13
 * @version  2.2.0
14
 * @package  WooCommerce/Classes
15
 * @category Class
16
 * @author   WooThemes
17
 */
18
class WC_Order extends WC_Abstract_Order {
19
20
	/**
21
	 * Data stored in meta keys, but not considered "meta" for an order.
22
	 * @since 2.7.0
23
	 * @var array
24
	 */
25
	protected $_internal_meta_keys = array(
26
		'_customer_user', '_order_key', '_order_currency', '_billing_first_name',
27
		'_billing_last_name', '_billing_company', '_billing_address_1', '_billing_address_2',
28
		'_billing_city', '_billing_state', '_billing_postcode', '_billing_country',
29
		'_billing_email', '_billing_phone', '_shipping_first_name', '_shipping_last_name',
30
		'_shipping_company', '_shipping_address_1', '_shipping_address_2', '_shipping_city',
31
		'_shipping_state', '_shipping_postcode', '_shipping_country', '_completed_date',
32
		'_paid_date', '_edit_lock', '_edit_last', '_cart_discount', '_cart_discount_tax',
33
		'_order_shipping', '_order_shipping_tax', '_order_tax', '_order_total', '_order_total',
34
		'_payment_method', '_payment_method_title', '_transaction_id', '_customer_ip_address',
35
		'_customer_user_agent', '_created_via', '_order_version', '_prices_include_tax',
36
		'_customer_note', '_date_completed', '_date_paid', '_payment_tokens',
37
	);
38
39
	/**
40
	 * Stores data about status changes so relevant hooks can be fired.
41
	 * @var bool|array
42
	 */
43
	protected $_status_transition = false;
44
45
	/**
46
	 * Extend the abstract _data properties and then read the order object.
47
	 *
48
	 * @param  int|object|WC_Order $order Order to init.
49
	 */
50
	public function __construct( $order = 0 ) {
51
		$this->_data = array_merge( $this->_data, array(
52
			'billing'              => array(
53
				'first_name'       => '',
54
				'last_name'        => '',
55
				'company'          => '',
56
				'address_1'        => '',
57
				'address_2'        => '',
58
				'city'             => '',
59
				'state'            => '',
60
				'postcode'         => '',
61
				'country'          => '',
62
				'email'            => '',
63
				'phone'            => '',
64
			),
65
			'shipping'             => array(
66
				'first_name'       => '',
67
				'last_name'        => '',
68
				'company'          => '',
69
				'address_1'        => '',
70
				'address_2'        => '',
71
				'city'             => '',
72
				'state'            => '',
73
				'postcode'         => '',
74
				'country'          => '',
75
			),
76
			'payment_method'       => '',
77
			'payment_method_title' => '',
78
			'transaction_id'       => '',
79
			'customer_ip_address'  => '',
80
			'customer_user_agent'  => '',
81
			'created_via'          => '',
82
			'customer_note'        => '',
83
			'date_completed'       => '',
84
			'date_paid'            => '',
85
			'cart_hash'            => '',
86
		) );
87
		parent::__construct( $order );
88
	}
89
90
	/**
91
	 * When a payment is complete this function is called.
92
	 *
93
	 * Most of the time this should mark an order as 'processing' so that admin can process/post the items.
94
	 * If the cart contains only downloadable items then the order is 'completed' since the admin needs to take no action.
95
	 * Stock levels are reduced at this point.
96
	 * Sales are also recorded for products.
97
	 * Finally, record the date of payment.
98
	 *
99
	 * Order must exist.
100
	 *
101
	 * @param string $transaction_id Optional transaction id to store in post meta.
102
	 * @return bool success
103
	 */
104
	public function payment_complete( $transaction_id = '' ) {
105
		if ( ! $this->get_id() ) {
106
			return false;
107
		}
108
109
		do_action( 'woocommerce_pre_payment_complete', $this->get_id() );
110
111
		if ( ! empty( WC()->session ) ) {
112
			WC()->session->set( 'order_awaiting_payment', false );
113
		}
114
115
		if ( $this->has_status( apply_filters( 'woocommerce_valid_order_statuses_for_payment_complete', array( 'on-hold', 'pending', 'failed', 'cancelled' ), $this ) ) ) {
116
			$order_needs_processing = false;
117
118
			if ( sizeof( $this->get_items() ) > 0 ) {
119
				foreach ( $this->get_items() as $item ) {
120
					if ( $item->is_type( 'line_item' ) && ( $product = $item->get_product() ) ) {
121
						$virtual_downloadable_item = $product->is_downloadable() && $product->is_virtual();
122
123
						if ( apply_filters( 'woocommerce_order_item_needs_processing', ! $virtual_downloadable_item, $product, $this->get_id() ) ) {
124
							$order_needs_processing = true;
125
							break;
126
						}
127
					}
128
				}
129
			}
130
131
			if ( ! empty( $transaction_id ) ) {
132
				$this->set_transaction_id( $transaction_id );
133
			}
134
135
			$this->set_status( apply_filters( 'woocommerce_payment_complete_order_status', $order_needs_processing ? 'processing' : 'completed', $this->get_id() ) );
136
			$this->set_date_paid( current_time( 'timestamp' ) );
137
			$this->save();
138
139
			do_action( 'woocommerce_payment_complete', $this->get_id() );
140
		} else {
141
			do_action( 'woocommerce_payment_complete_order_status_' . $this->get_status(), $this->get_id() );
142
		}
143
144
		return true;
145
	}
146
147
	/**
148
	 * Gets order total - formatted for display.
149
	 * @return string
150
	 */
151
	public function get_formatted_order_total( $tax_display = '', $display_refunded = true ) {
152
		$formatted_total = wc_price( $this->get_total(), array( 'currency' => $this->get_currency() ) );
153
		$order_total    = $this->get_total();
154
		$total_refunded = $this->get_total_refunded();
155
		$tax_string     = '';
156
157
		// Tax for inclusive prices
158
		if ( wc_tax_enabled() && 'incl' == $tax_display ) {
159
			$tax_string_array = array();
160
161
			if ( 'itemized' == get_option( 'woocommerce_tax_total_display' ) ) {
162
				foreach ( $this->get_tax_totals() as $code => $tax ) {
163
					$tax_amount         = ( $total_refunded && $display_refunded ) ? wc_price( WC_Tax::round( $tax->amount - $this->get_total_tax_refunded_by_rate_id( $tax->rate_id ) ), array( 'currency' => $this->get_currency() ) ) : $tax->formatted_amount;
164
					$tax_string_array[] = sprintf( '%s %s', $tax_amount, $tax->label );
165
				}
166
			} else {
167
				$tax_amount         = ( $total_refunded && $display_refunded ) ? $this->get_total_tax() - $this->get_total_tax_refunded() : $this->get_total_tax();
168
				$tax_string_array[] = sprintf( '%s %s', wc_price( $tax_amount, array( 'currency' => $this->get_currency() ) ), WC()->countries->tax_or_vat() );
169
			}
170
			if ( ! empty( $tax_string_array ) ) {
171
				$tax_string = ' ' . sprintf( __( '(includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) );
172
			}
173
		}
174
175
		if ( $total_refunded && $display_refunded ) {
176
			$formatted_total = '<del>' . strip_tags( $formatted_total ) . '</del> <ins>' . wc_price( $order_total - $total_refunded, array( 'currency' => $this->get_currency() ) ) . $tax_string . '</ins>';
177
		} else {
178
			$formatted_total .= $tax_string;
179
		}
180
181
		return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this );
182
	}
183
184
	/*
185
	|--------------------------------------------------------------------------
186
	| CRUD methods
187
	|--------------------------------------------------------------------------
188
	|
189
	| Methods which create, read, update and delete orders from the database.
190
	| Written in abstract fashion so that the way orders are stored can be
191
	| changed more easily in the future.
192
	|
193
	| A save method is included for convenience (chooses update or create based
194
	| on if the order exists yet).
195
	|
196
	*/
197
198
	/**
199
	 * Insert data into the database.
200
	 * @since 2.7.0
201
	 */
202
	public function create() {
203
		parent::create();
204
205
		// Store additonal order data
206
		if ( $this->get_id() ) {
207
			$this->update_post_meta( '_billing_first_name', $this->get_billing_first_name() );
208
			$this->update_post_meta( '_billing_last_name', $this->get_billing_last_name() );
209
			$this->update_post_meta( '_billing_company', $this->get_billing_company() );
210
			$this->update_post_meta( '_billing_address_1', $this->get_billing_address_1() );
211
			$this->update_post_meta( '_billing_address_2', $this->get_billing_address_2() );
212
			$this->update_post_meta( '_billing_city', $this->get_billing_city() );
213
			$this->update_post_meta( '_billing_state', $this->get_billing_state() );
214
			$this->update_post_meta( '_billing_postcode', $this->get_billing_postcode() );
215
			$this->update_post_meta( '_billing_country', $this->get_billing_country() );
216
			$this->update_post_meta( '_billing_email', $this->get_billing_email() );
217
			$this->update_post_meta( '_billing_phone', $this->get_billing_phone() );
218
			$this->update_post_meta( '_shipping_first_name', $this->get_shipping_first_name() );
219
			$this->update_post_meta( '_shipping_last_name', $this->get_shipping_last_name() );
220
			$this->update_post_meta( '_shipping_company', $this->get_shipping_company() );
221
			$this->update_post_meta( '_shipping_address_1', $this->get_shipping_address_1() );
222
			$this->update_post_meta( '_shipping_address_2', $this->get_shipping_address_2() );
223
			$this->update_post_meta( '_shipping_city', $this->get_shipping_city() );
224
			$this->update_post_meta( '_shipping_state', $this->get_shipping_state() );
225
			$this->update_post_meta( '_shipping_postcode', $this->get_shipping_postcode() );
226
			$this->update_post_meta( '_shipping_country', $this->get_shipping_country() );
227
			$this->update_post_meta( '_payment_method', $this->get_payment_method() );
228
			$this->update_post_meta( '_payment_method_title', $this->get_payment_method_title() );
229
			$this->update_post_meta( '_transaction_id', $this->get_transaction_id() );
230
			$this->update_post_meta( '_customer_ip_address', $this->get_customer_ip_address() );
231
			$this->update_post_meta( '_customer_user_agent', $this->get_customer_user_agent() );
232
			$this->update_post_meta( '_created_via', $this->get_created_via() );
233
			$this->update_post_meta( '_customer_note', $this->get_customer_note() );
234
			$this->update_post_meta( '_date_completed', $this->get_date_completed() );
235
			$this->update_post_meta( '_date_paid', $this->get_date_paid() );
236
			$this->update_post_meta( '_cart_hash', $this->get_cart_hash() );
237
			do_action( 'woocommerce_new_order', $this->get_id() );
238
		}
239
	}
240
241
	/**
242
	 * Read from the database.
243
	 * @since 2.7.0
244
	 * @param int $id ID of object to read.
245
	 */
246
	public function read( $id ) {
247
		parent::read( $id );
248
249
		// Read additonal order data
250
		if ( $order_id = $this->get_id() ) {
251
			$post_object = get_post( $this->get_id() );
252
			$this->set_billing_first_name( get_post_meta( $order_id, '_billing_first_name', true ) );
253
			$this->set_billing_last_name( get_post_meta( $order_id, '_billing_last_name', true ) );
254
			$this->set_billing_company( get_post_meta( $order_id, '_billing_company', true ) );
255
			$this->set_billing_address_1( get_post_meta( $order_id, '_billing_address_1', true ) );
256
			$this->set_billing_address_2( get_post_meta( $order_id, '_billing_address_2', true ) );
257
			$this->set_billing_city( get_post_meta( $order_id, '_billing_city', true ) );
258
			$this->set_billing_state( get_post_meta( $order_id, '_billing_state', true ) );
259
			$this->set_billing_postcode( get_post_meta( $order_id, '_billing_postcode', true ) );
260
			$this->set_billing_country( get_post_meta( $order_id, '_billing_country', true ) );
261
			$this->set_billing_email( get_post_meta( $order_id, '_billing_email', true ) );
262
			$this->set_billing_phone( get_post_meta( $order_id, '_billing_phone', true ) );
263
			$this->set_shipping_first_name( get_post_meta( $order_id, '_shipping_first_name', true ) );
264
			$this->set_shipping_last_name( get_post_meta( $order_id, '_shipping_last_name', true ) );
265
			$this->set_shipping_company( get_post_meta( $order_id, '_shipping_company', true ) );
266
			$this->set_shipping_address_1( get_post_meta( $order_id, '_shipping_address_1', true ) );
267
			$this->set_shipping_address_2( get_post_meta( $order_id, '_shipping_address_2', true ) );
268
			$this->set_shipping_city( get_post_meta( $order_id, '_shipping_city', true ) );
269
			$this->set_shipping_state( get_post_meta( $order_id, '_shipping_state', true ) );
270
			$this->set_shipping_postcode( get_post_meta( $order_id, '_shipping_postcode', true ) );
271
			$this->set_shipping_country( get_post_meta( $order_id, '_shipping_country', true ) );
272
			$this->set_payment_method( get_post_meta( $order_id, '_payment_method', true ) );
273
			$this->set_payment_method_title( get_post_meta( $order_id, '_payment_method_title', true ) );
274
			$this->set_transaction_id( get_post_meta( $order_id, '_transaction_id', true ) );
275
			$this->set_customer_ip_address( get_post_meta( $order_id, '_customer_ip_address', true ) );
276
			$this->set_customer_user_agent( get_post_meta( $order_id, '_customer_user_agent', true ) );
277
			$this->set_created_via( get_post_meta( $order_id, '_created_via', true ) );
278
			$this->set_customer_note( get_post_meta( $order_id, '_customer_note', true ) );
279
			$this->set_date_completed( get_post_meta( $order_id, '_completed_date', true ) );
280
			$this->set_date_paid( get_post_meta( $order_id, '_paid_date', true ) );
281
			$this->set_cart_hash( get_post_meta( $order_id, '_cart_hash', true ) );
282
			$this->set_customer_note( $post_object->post_excerpt );
283
284
			// Map user data
285
			if ( ! $this->get_billing_email() && ( $user = $this->get_user() ) ) {
286
				$this->set_billing_email( $user->user_email );
287
			}
288
		}
289
	}
290
291
	/**
292
	 * Update data in the database.
293
	 * @since 2.7.0
294
	 */
295
	public function update() {
296
		// Store additonal order data
297
		$this->update_post_meta( '_billing_first_name', $this->get_billing_first_name() );
298
		$this->update_post_meta( '_billing_last_name', $this->get_billing_last_name() );
299
		$this->update_post_meta( '_billing_company', $this->get_billing_company() );
300
		$this->update_post_meta( '_billing_address_1', $this->get_billing_address_1() );
301
		$this->update_post_meta( '_billing_address_2', $this->get_billing_address_2() );
302
		$this->update_post_meta( '_billing_city', $this->get_billing_city() );
303
		$this->update_post_meta( '_billing_state', $this->get_billing_state() );
304
		$this->update_post_meta( '_billing_postcode', $this->get_billing_postcode() );
305
		$this->update_post_meta( '_billing_country', $this->get_billing_country() );
306
		$this->update_post_meta( '_billing_email', $this->get_billing_email() );
307
		$this->update_post_meta( '_billing_phone', $this->get_billing_phone() );
308
		$this->update_post_meta( '_shipping_first_name', $this->get_shipping_first_name() );
309
		$this->update_post_meta( '_shipping_last_name', $this->get_shipping_last_name() );
310
		$this->update_post_meta( '_shipping_company', $this->get_shipping_company() );
311
		$this->update_post_meta( '_shipping_address_1', $this->get_shipping_address_1() );
312
		$this->update_post_meta( '_shipping_address_2', $this->get_shipping_address_2() );
313
		$this->update_post_meta( '_shipping_city', $this->get_shipping_city() );
314
		$this->update_post_meta( '_shipping_state', $this->get_shipping_state() );
315
		$this->update_post_meta( '_shipping_postcode', $this->get_shipping_postcode() );
316
		$this->update_post_meta( '_shipping_country', $this->get_shipping_country() );
317
		$this->update_post_meta( '_payment_method', $this->get_payment_method() );
318
		$this->update_post_meta( '_payment_method_title', $this->get_payment_method_title() );
319
		$this->update_post_meta( '_transaction_id', $this->get_transaction_id() );
320
		$this->update_post_meta( '_customer_ip_address', $this->get_customer_ip_address() );
321
		$this->update_post_meta( '_customer_user_agent', $this->get_customer_user_agent() );
322
		$this->update_post_meta( '_created_via', $this->get_created_via() );
323
		$this->update_post_meta( '_customer_note', $this->get_customer_note() );
324
		$this->update_post_meta( '_date_completed', $this->get_date_completed() );
325
		$this->update_post_meta( '_date_paid', $this->get_date_paid() );
326
		$this->update_post_meta( '_cart_hash', $this->get_cart_hash() );
327
328
		$customer_changed = $this->update_post_meta( '_customer_user', $this->get_customer_id() );
329
330
		// Update parent
331
		parent::update();
332
333
		// If customer changed, update any downloadable permissions
334
		if ( $customer_changed ) {
335
			$wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions",
336
				array(
337
					'user_id'    => $this->get_customer_id(),
338
					'user_email' => $this->get_billing_email(),
339
				),
340
				array(
341
					'order_id'   => $this->get_id(),
342
				),
343
				array(
344
					'%d',
345
					'%s',
346
				),
347
				array(
348
					'%d',
349
				)
350
			);
351
		}
352
353
		// Handle status change
354
		$this->status_transition();
355
	}
356
357
	/**
358
	 * Set order status.
359
	 * @since 2.7.0
360
	 * @param string $new_status Status to change the order to. No internal wc- prefix is required.
361
	 * @param string $note (default: '') Optional note to add.
362
	 * @param bool $manual_update is this a manual order status change?
363
	 * @param array details of change
364
	 */
365
	public function set_status( $new_status, $note = '', $manual_update = false ) {
366
		$result = parent::set_status( $new_status );
367
368
		if ( ! empty( $result['from'] ) && $result['from'] !== $result['to'] ) {
369
			$this->_status_transition = array(
370
				'from'   => ! empty( $this->_status_transition['from'] ) ? $this->_status_transition['from'] : $result['from'],
371
				'to'     => $result['to'],
372
				'note'   => $note,
373
				'manual' => (bool) $manual_update,
374
			);
375
376
			if ( 'pending' === $result['from'] && ! $manual_update ) {
377
				$this->set_date_paid( current_time( 'timestamp' ) );
378
			}
379
380
			if ( 'completed' === $result['to'] ) {
381
				$this->set_date_completed( current_time( 'timestamp' ) );
382
			}
383
		}
384
385
		return $result;
386
	}
387
388
	/**
389
	 * Updates status of order immediately. Order must exist.
390
	 * @uses WC_Order::set_status()
391
	 */
392
	public function update_status( $new_status, $note = '', $manual = false ) {
393
		if ( ! $this->get_id() ) {
394
			return false;
395
		}
396
		$this->set_status( $new_status, $note, $manual );
397
		$this->save();
398
		return true;
399
	}
400
401
	/**
402
	 * Handle the status transition.
403
	 */
404
	protected function status_transition() {
405
		if ( $this->_status_transition ) {
406
			if ( ! empty( $this->_status_transition['from'] ) ) {
407
				$transition_note = sprintf( __( 'Order status changed from %s to %s.', 'woocommerce' ), wc_get_order_status_name( $this->_status_transition['from'] ), wc_get_order_status_name( $this->_status_transition['to'] ) );
408
409
				do_action( 'woocommerce_order_status_' . $this->_status_transition['from'] . '_to_' . $this->_status_transition['to'], $this->get_id() );
410
				do_action( 'woocommerce_order_status_changed', $this->get_id(), $this->_status_transition['from'], $this->_status_transition['to'] );
411
			} else {
412
				$transition_note = sprintf( __( 'Order status set to %s.', 'woocommerce' ), wc_get_order_status_name( $this->_status_transition['to'] ) );
413
			}
414
415
			do_action( 'woocommerce_order_status_' . $this->_status_transition['to'], $this->get_id() );
416
417
			// Note the transition occured
418
			$this->add_order_note( trim( $this->_status_transition['note'] . ' ' . $transition_note ), 0, $this->_status_transition['manual'] );
419
420
			// This has ran, so reset status transition variable
421
			$this->_status_transition = false;
422
		}
423
	}
424
425
	/*
426
	|--------------------------------------------------------------------------
427
	| Getters
428
	|--------------------------------------------------------------------------
429
	|
430
	| Methods for getting data from the order object.
431
	|
432
	*/
433
434
	/**
435
	 * Get billing_first_name
436
	 * @return string
437
	 */
438
	public function get_billing_first_name() {
439
		return $this->_data['billing']['first_name'];
440
	}
441
442
	/**
443
	 * Get billing_last_name
444
	 * @return string
445
	 */
446
	public function get_billing_last_name() {
447
		return $this->_data['billing']['last_name'];
448
	}
449
450
	/**
451
	 * Get billing_company
452
	 * @return string
453
	 */
454
	public function get_billing_company() {
455
		return $this->_data['billing']['company'];
456
	}
457
458
	/**
459
	 * Get billing_address_1
460
	 * @return string
461
	 */
462
	public function get_billing_address_1() {
463
		return $this->_data['billing']['address_1'];
464
	}
465
466
	/**
467
	 * Get billing_address_2
468
	 * @return string $value
469
	 */
470
	public function get_billing_address_2() {
471
		return $this->_data['billing']['address_2'];
472
	}
473
474
	/**
475
	 * Get billing_city
476
	 * @return string $value
477
	 */
478
	public function get_billing_city() {
479
		return $this->_data['billing']['city'];
480
	}
481
482
	/**
483
	 * Get billing_state
484
	 * @return string
485
	 */
486
	public function get_billing_state() {
487
		return $this->_data['billing']['state'];
488
	}
489
490
	/**
491
	 * Get billing_postcode
492
	 * @return string
493
	 */
494
	public function get_billing_postcode() {
495
		return $this->_data['billing']['postcode'];
496
	}
497
498
	/**
499
	 * Get billing_country
500
	 * @return string
501
	 */
502
	public function get_billing_country() {
503
		return $this->_data['billing']['country'];
504
	}
505
506
	/**
507
	 * Get billing_email
508
	 * @return string
509
	 */
510
	public function get_billing_email() {
511
		return $this->_data['billing']['email'];
512
	}
513
514
	/**
515
	 * Get billing_phone
516
	 * @return string
517
	 */
518
	public function get_billing_phone() {
519
		return $this->_data['billing']['phone'];
520
	}
521
522
	/**
523
	 * Get shipping_first_name
524
	 * @return string
525
	 */
526
	public function get_shipping_first_name() {
527
		return $this->_data['shipping']['first_name'];
528
	}
529
530
	/**
531
	 * Get shipping_last_name
532
	 * @return string
533
	 */
534
	public function get_shipping_last_name() {
535
		 return $this->_data['shipping']['last_name'];
536
	}
537
538
	/**
539
	 * Get shipping_company
540
	 * @return string
541
	 */
542
	public function get_shipping_company() {
543
		return $this->_data['shipping']['company'];
544
	}
545
546
	/**
547
	 * Get shipping_address_1
548
	 * @return string
549
	 */
550
	public function get_shipping_address_1() {
551
		return $this->_data['shipping']['address_1'];
552
	}
553
554
	/**
555
	 * Get shipping_address_2
556
	 * @return string
557
	 */
558
	public function get_shipping_address_2() {
559
		return $this->_data['shipping']['address_2'];
560
	}
561
562
	/**
563
	 * Get shipping_city
564
	 * @return string
565
	 */
566
	public function get_shipping_city() {
567
		return $this->_data['shipping']['city'];
568
	}
569
570
	/**
571
	 * Get shipping_state
572
	 * @return string
573
	 */
574
	public function get_shipping_state() {
575
		return $this->_data['shipping']['state'];
576
	}
577
578
	/**
579
	 * Get shipping_postcode
580
	 * @return string
581
	 */
582
	public function get_shipping_postcode() {
583
		return $this->_data['shipping']['postcode'];
584
	}
585
586
	/**
587
	 * Get shipping_country
588
	 * @return string
589
	 */
590
	public function get_shipping_country() {
591
		return $this->_data['shipping']['country'];
592
	}
593
594
	/**
595
	 * Get the payment method.
596
	 * @return string
597
	 */
598
	public function get_payment_method() {
599
		return $this->_data['payment_method'];
600
	}
601
602
	/**
603
	 * Get payment_method_title
604
	 * @return string
605
	 */
606
	public function get_payment_method_title() {
607
		return $this->_data['payment_method_title'];
608
	}
609
610
	/**
611
	 * Get transaction_id
612
	 * @return string
613
	 */
614
	public function get_transaction_id() {
615
		return $this->_data['transaction_id'];
616
	}
617
618
	/**
619
	 * Get customer_ip_address
620
	 * @return string
621
	 */
622
	public function get_customer_ip_address() {
623
		return $this->_data['customer_ip_address'];
624
	}
625
626
	/**
627
	 * Get customer_user_agent
628
	 * @return string
629
	 */
630
	public function get_customer_user_agent() {
631
		return $this->_data['customer_user_agent'];
632
	}
633
634
	/**
635
	 * Get created_via
636
	 * @return string
637
	 */
638
	public function get_created_via() {
639
		return $this->_data['created_via'];
640
	}
641
642
	/**
643
	 * Get customer_note
644
	 * @return string
645
	 */
646
	public function get_customer_note() {
647
		return $this->_data['customer_note'];
648
	}
649
650
	/**
651
	 * Get date_completed
652
	 * @return int
653
	 */
654
	public function get_date_completed() {
655
		return absint( $this->_data['date_completed'] );
656
	}
657
658
	/**
659
	 * Get date_paid
660
	 * @return int
661
	 */
662
	public function get_date_paid() {
663
		return absint( $this->_data['date_paid'] );
664
	}
665
666
	/**
667
	 * Returns the requested address in raw, non-formatted way.
668
	 * @since  2.4.0
669
	 * @param  string $type Billing or shipping. Anything else besides 'billing' will return shipping address.
670
	 * @return array The stored address after filter.
671
	 */
672
	public function get_address( $type = 'billing' ) {
673
		return apply_filters( 'woocommerce_get_order_address', isset( $this->_data[ $type ] ) ? $this->_data[ $type ] : array(), $type, $this );
674
	}
675
676
	/**
677
	 * Get a formatted shipping address for the order.
678
	 *
679
	 * @return string
680
	 */
681
	public function get_shipping_address_map_url() {
682
		$address = apply_filters( 'woocommerce_shipping_address_map_url_parts', $this->get_address( 'shipping' ), $this );
683
		return apply_filters( 'woocommerce_shipping_address_map_url', 'http://maps.google.com/maps?&q=' . urlencode( implode( ', ', $address ) ) . '&z=16', $this );
684
	}
685
686
	/**
687
	 * Get a formatted billing full name.
688
	 * @return string
689
	 */
690
	public function get_formatted_billing_full_name() {
691
		return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $this->get_billing_first_name(), $this->get_billing_last_name() );
692
	}
693
694
	/**
695
	 * Get a formatted shipping full name.
696
	 * @return string
697
	 */
698
	public function get_formatted_shipping_full_name() {
699
		return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $this->get_shipping_first_name(), $this->get_shipping_last_name() );
700
	}
701
702
	/**
703
	 * Get a formatted billing address for the order.
704
	 * @return string
705
	 */
706
	public function get_formatted_billing_address() {
707
		return WC()->countries->get_formatted_address( apply_filters( 'woocommerce_order_formatted_billing_address', $this->get_address( 'billing' ), $this ) );
708
	}
709
710
	/**
711
	 * Get a formatted shipping address for the order.
712
	 * @return string
713
	 */
714
	public function get_formatted_shipping_address() {
715
		if ( $this->get_shipping_address_1() || $this->get_shipping_address_2() ) {
716
			return WC()->countries->get_formatted_address( apply_filters( 'woocommerce_order_formatted_shipping_address', $this->get_address( 'shipping' ), $this ) );
717
		} else {
718
			return '';
719
		}
720
	}
721
722
	/**
723
	 * Get cart hash
724
	 * @return string
725
	 */
726
	public function get_cart_hash() {
727
		return $this->_data['cart_hash'];
728
	}
729
730
	/*
731
	|--------------------------------------------------------------------------
732
	| Setters
733
	|--------------------------------------------------------------------------
734
	|
735
	| Functions for setting order data. These should not update anything in the
736
	| database itself and should only change what is stored in the class
737
	| object. However, for backwards compatibility pre 2.7.0 some of these
738
	| setters may handle both.
739
	|
740
	*/
741
742
	/**
743
	 * Set billing_first_name
744
	 * @param string $value
745
	 */
746
	public function set_billing_first_name( $value ) {
747
		$this->_data['billing']['first_name'] = $value;
748
	}
749
750
	/**
751
	 * Set billing_last_name
752
	 * @param string $value
753
	 */
754
	public function set_billing_last_name( $value ) {
755
		$this->_data['billing']['last_name'] = $value;
756
	}
757
758
	/**
759
	 * Set billing_company
760
	 * @param string $value
761
	 */
762
	public function set_billing_company( $value ) {
763
		$this->_data['billing']['company'] = $value;
764
	}
765
766
	/**
767
	 * Set billing_address_1
768
	 * @param string $value
769
	 */
770
	public function set_billing_address_1( $value ) {
771
		$this->_data['billing']['address_1'] = $value;
772
	}
773
774
	/**
775
	 * Set billing_address_2
776
	 * @param string $value
777
	 */
778
	public function set_billing_address_2( $value ) {
779
		$this->_data['billing']['address_2'] = $value;
780
	}
781
782
	/**
783
	 * Set billing_city
784
	 * @param string $value
785
	 */
786
	public function set_billing_city( $value ) {
787
		$this->_data['billing']['city'] = $value;
788
	}
789
790
	/**
791
	 * Set billing_state
792
	 * @param string $value
793
	 */
794
	public function set_billing_state( $value ) {
795
		$this->_data['billing']['state'] = $value;
796
	}
797
798
	/**
799
	 * Set billing_postcode
800
	 * @param string $value
801
	 */
802
	public function set_billing_postcode( $value ) {
803
		$this->_data['billing']['postcode'] = $value;
804
	}
805
806
	/**
807
	 * Set billing_country
808
	 * @param string $value
809
	 */
810
	public function set_billing_country( $value ) {
811
		$this->_data['billing']['country'] = $value;
812
	}
813
814
	/**
815
	 * Set billing_email
816
	 * @param string $value
817
	 */
818
	public function set_billing_email( $value ) {
819
		$value = sanitize_email( $value );
820
		$this->_data['billing']['email'] = is_email( $value ) ? $value : '';
821
	}
822
823
	/**
824
	 * Set billing_phone
825
	 * @param string $value
826
	 */
827
	public function set_billing_phone( $value ) {
828
		$this->_data['billing']['phone'] = $value;
829
	}
830
831
	/**
832
	 * Set shipping_first_name
833
	 * @param string $value
834
	 */
835
	public function set_shipping_first_name( $value ) {
836
		$this->_data['shipping']['first_name'] = $value;
837
	}
838
839
	/**
840
	 * Set shipping_last_name
841
	 * @param string $value
842
	 */
843
	public function set_shipping_last_name( $value ) {
844
		$this->_data['shipping']['last_name'] = $value;
845
	}
846
847
	/**
848
	 * Set shipping_company
849
	 * @param string $value
850
	 */
851
	public function set_shipping_company( $value ) {
852
		$this->_data['shipping']['company'] = $value;
853
	}
854
855
	/**
856
	 * Set shipping_address_1
857
	 * @param string $value
858
	 */
859
	public function set_shipping_address_1( $value ) {
860
		$this->_data['shipping']['address_1'] = $value;
861
	}
862
863
	/**
864
	 * Set shipping_address_2
865
	 * @param string $value
866
	 */
867
	public function set_shipping_address_2( $value ) {
868
		$this->_data['shipping']['address_2'] = $value;
869
	}
870
871
	/**
872
	 * Set shipping_city
873
	 * @param string $value
874
	 */
875
	public function set_shipping_city( $value ) {
876
		$this->_data['shipping']['city'] = $value;
877
	}
878
879
	/**
880
	 * Set shipping_state
881
	 * @param string $value
882
	 */
883
	public function set_shipping_state( $value ) {
884
		$this->_data['shipping']['state'] = $value;
885
	}
886
887
	/**
888
	 * Set shipping_postcode
889
	 * @param string $value
890
	 */
891
	public function set_shipping_postcode( $value ) {
892
		$this->_data['shipping']['postcode'] = $value;
893
	}
894
895
	/**
896
	 * Set shipping_country
897
	 * @param string $value
898
	 */
899
	public function set_shipping_country( $value ) {
900
		$this->_data['shipping']['country'] = $value;
901
	}
902
903
	/**
904
	 * Set the payment method.
905
	 * @param string $payment_method Supports WC_Payment_Gateway for bw compatibility with < 2.7
906
	 */
907
	public function set_payment_method( $payment_method = '' ) {
908
		if ( is_object( $payment_method ) ) {
909
			$this->set_payment_method( $payment_method->id );
910
			$this->set_payment_method_title( $payment_method->get_title() );
911
		} elseif ( '' === $payment_method ) {
912
			$this->_data['payment_method']       = '';
913
			$this->_data['payment_method_title'] = '';
914
		} else {
915
			$this->_data['payment_method']       = $payment_method;
916
		}
917
	}
918
919
	/**
920
	 * Set payment_method_title
921
	 * @param string $value
922
	 */
923
	public function set_payment_method_title( $value ) {
924
		$this->_data['payment_method_title'] = $value;
925
	}
926
927
	/**
928
	 * Set transaction_id
929
	 * @param string $value
930
	 */
931
	public function set_transaction_id( $value ) {
932
		$this->_data['transaction_id'] = $value;
933
	}
934
935
	/**
936
	 * Set customer_ip_address
937
	 * @param string $value
938
	 */
939
	public function set_customer_ip_address( $value ) {
940
		$this->_data['customer_ip_address'] = $value;
941
	}
942
943
	/**
944
	 * Set customer_user_agent
945
	 * @param string $value
946
	 */
947
	public function set_customer_user_agent( $value ) {
948
		$this->_data['customer_user_agent'] = $value;
949
	}
950
951
	/**
952
	 * Set created_via
953
	 * @param string $value
954
	 */
955
	public function set_created_via( $value ) {
956
		$this->_data['created_via'] = $value;
957
	}
958
959
	/**
960
	 * Set customer_note
961
	 * @param string $value
962
	 */
963
	public function set_customer_note( $value ) {
964
		$this->_data['customer_note'] = $value;
965
	}
966
967
	/**
968
	 * Set date_completed
969
	 * @param string $timestamp
970
	 */
971
	public function set_date_completed( $timestamp ) {
972
		$this->_data['date_completed'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
973
	}
974
975
	/**
976
	 * Set date_paid
977
	 * @param string $timestamp
978
	 */
979
	public function set_date_paid( $timestamp ) {
980
		$this->_data['date_paid'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
981
	}
982
983
	/**
984
	 * Set cart hash
985
	 * @param string $value
986
	 */
987
	public function set_cart_hash( $value ) {
988
		$this->_data['cart_hash'] = $value;
989
	}
990
991
	/*
992
	|--------------------------------------------------------------------------
993
	| Conditionals
994
	|--------------------------------------------------------------------------
995
	|
996
	| Checks if a condition is true or false.
997
	|
998
	*/
999
1000
	/**
1001
	 * See if order matches cart_hash.
1002
	 * @return bool
1003
	 */
1004
	public function has_cart_hash( $cart_hash = '' ) {
1005
		return hash_equals( $this->get_cart_hash(), $cart_hash );
1006
	}
1007
1008
	/**
1009
	 * Checks if an order can be edited, specifically for use on the Edit Order screen.
1010
	 * @return bool
1011
	 */
1012
	public function is_editable() {
1013
		return apply_filters( 'wc_order_is_editable', in_array( $this->get_status(), array( 'pending', 'on-hold', 'auto-draft' ) ), $this );
1014
	}
1015
1016
	/**
1017
	 * Returns if an order has been paid for based on the order status.
1018
	 * @since 2.5.0
1019
	 * @return bool
1020
	 */
1021
	public function is_paid() {
1022
		return apply_filters( 'woocommerce_order_is_paid', $this->has_status( apply_filters( 'woocommerce_order_is_paid_statuses', array( 'processing', 'completed' ) ) ), $this );
1023
	}
1024
1025
	/**
1026
	 * Checks if product download is permitted.
1027
	 *
1028
	 * @return bool
1029
	 */
1030
	public function is_download_permitted() {
1031
		return apply_filters( 'woocommerce_order_is_download_permitted', $this->has_status( 'completed' ) || ( 'yes' === get_option( 'woocommerce_downloads_grant_access_after_payment' ) && $this->has_status( 'processing' ) ), $this );
1032
	}
1033
1034
	/**
1035
	 * Checks if an order needs display the shipping address, based on shipping method.
1036
	 * @return bool
1037
	 */
1038
	public function needs_shipping_address() {
1039
		if ( 'no' === get_option( 'woocommerce_calc_shipping' ) ) {
1040
			return false;
1041
		}
1042
1043
		$hide  = apply_filters( 'woocommerce_order_hide_shipping_address', array( 'local_pickup' ), $this );
1044
		$needs_address = false;
1045
1046
		foreach ( $this->get_shipping_methods() as $shipping_method ) {
1047
			// Remove any instance IDs after :
1048
			$shipping_method_id = current( explode( ':', $shipping_method['method_id'] ) );
1049
1050
			if ( ! in_array( $shipping_method_id, $hide ) ) {
1051
				$needs_address = true;
1052
				break;
1053
			}
1054
		}
1055
1056
		return apply_filters( 'woocommerce_order_needs_shipping_address', $needs_address, $hide, $this );
1057
	}
1058
1059
	/**
1060
	 * Returns true if the order contains a downloadable product.
1061
	 * @return bool
1062
	 */
1063
	public function has_downloadable_item() {
1064
		foreach ( $this->get_items() as $item ) {
1065
			if ( $item->is_type( 'line_item' ) && ( $product = $item->get_product() ) && $product->is_downloadable() && $product->has_file() ) {
1066
				return true;
1067
			}
1068
		}
1069
		return false;
1070
	}
1071
1072
	/**
1073
	 * Checks if an order needs payment, based on status and order total.
1074
	 *
1075
	 * @return bool
1076
	 */
1077
	public function needs_payment() {
1078
		$valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $this );
1079
		return apply_filters( 'woocommerce_order_needs_payment', ( $this->has_status( $valid_order_statuses ) && $this->get_total() > 0 ), $this, $valid_order_statuses );
1080
	}
1081
1082
	/*
1083
	|--------------------------------------------------------------------------
1084
	| URLs and Endpoints
1085
	|--------------------------------------------------------------------------
1086
	*/
1087
1088
	/**
1089
	 * Generates a URL so that a customer can pay for their (unpaid - pending) order. Pass 'true' for the checkout version which doesn't offer gateway choices.
1090
	 *
1091
	 * @param  bool $on_checkout
1092
	 * @return string
1093
	 */
1094
	public function get_checkout_payment_url( $on_checkout = false ) {
1095
		$pay_url = wc_get_endpoint_url( 'order-pay', $this->get_id(), wc_get_page_permalink( 'checkout' ) );
1096
1097 View Code Duplication
		if ( 'yes' == get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1098
			$pay_url = str_replace( 'http:', 'https:', $pay_url );
1099
		}
1100
1101
		if ( $on_checkout ) {
1102
			$pay_url = add_query_arg( 'key', $this->get_order_key(), $pay_url );
1103
		} else {
1104
			$pay_url = add_query_arg( array( 'pay_for_order' => 'true', 'key' => $this->get_order_key() ), $pay_url );
1105
		}
1106
1107
		return apply_filters( 'woocommerce_get_checkout_payment_url', $pay_url, $this );
1108
	}
1109
1110
	/**
1111
	 * Generates a URL for the thanks page (order received).
1112
	 *
1113
	 * @return string
1114
	 */
1115
	public function get_checkout_order_received_url() {
1116
		$order_received_url = wc_get_endpoint_url( 'order-received', $this->get_id(), wc_get_page_permalink( 'checkout' ) );
1117
1118
		if ( 'yes' === get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) {
1119
			$order_received_url = str_replace( 'http:', 'https:', $order_received_url );
1120
		}
1121
1122
		$order_received_url = add_query_arg( 'key', $this->get_order_key(), $order_received_url );
1123
1124
		return apply_filters( 'woocommerce_get_checkout_order_received_url', $order_received_url, $this );
1125
	}
1126
1127
	/**
1128
	 * Generates a URL so that a customer can cancel their (unpaid - pending) order.
1129
	 *
1130
	 * @param string $redirect
1131
	 *
1132
	 * @return string
1133
	 */
1134 View Code Duplication
	public function get_cancel_order_url( $redirect = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1135
		return apply_filters( 'woocommerce_get_cancel_order_url', wp_nonce_url( add_query_arg( array(
1136
			'cancel_order' => 'true',
1137
			'order'        => $this->get_order_key(),
1138
			'order_id'     => $this->get_id(),
1139
			'redirect'     => $redirect
1140
		), $this->get_cancel_endpoint() ), 'woocommerce-cancel_order' ) );
1141
	}
1142
1143
	/**
1144
	 * Generates a raw (unescaped) cancel-order URL for use by payment gateways.
1145
	 *
1146
	 * @param string $redirect
1147
	 *
1148
	 * @return string The unescaped cancel-order URL.
1149
	 */
1150 View Code Duplication
	public function get_cancel_order_url_raw( $redirect = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1151
		return apply_filters( 'woocommerce_get_cancel_order_url_raw', add_query_arg( array(
1152
			'cancel_order' => 'true',
1153
			'order'        => $this->get_order_key(),
1154
			'order_id'     => $this->get_id(),
1155
			'redirect'     => $redirect,
1156
			'_wpnonce'     => wp_create_nonce( 'woocommerce-cancel_order' )
1157
		), $this->get_cancel_endpoint() ) );
1158
	}
1159
1160
	/**
1161
	 * Helper method to return the cancel endpoint.
1162
	 *
1163
	 * @return string the cancel endpoint; either the cart page or the home page.
1164
	 */
1165
	public function get_cancel_endpoint() {
1166
		$cancel_endpoint = wc_get_page_permalink( 'cart' );
1167
		if ( ! $cancel_endpoint ) {
1168
			$cancel_endpoint = home_url();
1169
		}
1170
1171
		if ( false === strpos( $cancel_endpoint, '?' ) ) {
1172
			$cancel_endpoint = trailingslashit( $cancel_endpoint );
1173
		}
1174
1175
		return $cancel_endpoint;
1176
	}
1177
1178
	/**
1179
	 * Generates a URL to view an order from the my account page.
1180
	 *
1181
	 * @return string
1182
	 */
1183
	public function get_view_order_url() {
1184
		return apply_filters( 'woocommerce_get_view_order_url', wc_get_endpoint_url( 'view-order', $this->get_id(), wc_get_page_permalink( 'myaccount' ) ), $this );
1185
	}
1186
1187
	/*
1188
	|--------------------------------------------------------------------------
1189
	| Order notes.
1190
	|--------------------------------------------------------------------------
1191
	*/
1192
1193
	/**
1194
	 * Adds a note (comment) to the order. Order must exist.
1195
	 *
1196
	 * @param string $note Note to add.
1197
	 * @param int $is_customer_note (default: 0) Is this a note for the customer?
1198
	 * @param  bool added_by_user Was the note added by a user?
1199
	 * @return int Comment ID.
1200
	 */
1201
	public function add_order_note( $note, $is_customer_note = 0, $added_by_user = false ) {
1202
		if ( ! $this->get_id() ) {
1203
			return 0;
1204
		}
1205
1206
		if ( is_user_logged_in() && current_user_can( 'edit_shop_order', $this->get_id() ) && $added_by_user ) {
1207
			$user                 = get_user_by( 'id', get_current_user_id() );
1208
			$comment_author       = $user->display_name;
1209
			$comment_author_email = $user->user_email;
1210
		} else {
1211
			$comment_author       = __( 'WooCommerce', 'woocommerce' );
1212
			$comment_author_email = strtolower( __( 'WooCommerce', 'woocommerce' ) ) . '@';
1213
			$comment_author_email .= isset( $_SERVER['HTTP_HOST'] ) ? str_replace( 'www.', '', $_SERVER['HTTP_HOST'] ) : 'noreply.com';
1214
			$comment_author_email = sanitize_email( $comment_author_email );
1215
		}
1216
		$commentdata = apply_filters( 'woocommerce_new_order_note_data', array(
1217
			'comment_post_ID'      => $this->get_id(),
1218
			'comment_author'       => $comment_author,
1219
			'comment_author_email' => $comment_author_email,
1220
			'comment_author_url'   => '',
1221
			'comment_content'      => $note,
1222
			'comment_agent'        => 'WooCommerce',
1223
			'comment_type'         => 'order_note',
1224
			'comment_parent'       => 0,
1225
			'comment_approved'     => 1,
1226
		), array( 'order_id' => $this->get_id(), 'is_customer_note' => $is_customer_note ) );
1227
1228
		$comment_id = wp_insert_comment( $commentdata );
1229
1230
		if ( $is_customer_note ) {
1231
			add_comment_meta( $comment_id, 'is_customer_note', 1 );
1232
1233
			do_action( 'woocommerce_new_customer_note', array( 'order_id' => $this->get_id(), 'customer_note' => $commentdata['comment_content'] ) );
1234
		}
1235
1236
		return $comment_id;
1237
	}
1238
1239
	/**
1240
	 * List order notes (public) for the customer.
1241
	 *
1242
	 * @return array
1243
	 */
1244
	public function get_customer_order_notes() {
1245
		$notes = array();
1246
		$args  = array(
1247
			'post_id' => $this->get_id(),
1248
			'approve' => 'approve',
1249
			'type'    => ''
1250
		);
1251
1252
		remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) );
1253
1254
		$comments = get_comments( $args );
1255
1256
		foreach ( $comments as $comment ) {
1257
			if ( ! get_comment_meta( $comment->comment_ID, 'is_customer_note', true ) ) {
1258
				continue;
1259
			}
1260
			$comment->comment_content = make_clickable( $comment->comment_content );
1261
			$notes[] = $comment;
1262
		}
1263
1264
		add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) );
1265
1266
		return $notes;
1267
	}
1268
1269
	/*
1270
	|--------------------------------------------------------------------------
1271
	| Refunds
1272
	|--------------------------------------------------------------------------
1273
	*/
1274
1275
	/**
1276
	 * Get order refunds.
1277
	 * @since 2.2
1278
	 * @return array of WC_Order_Refund objects
1279
	 */
1280
	public function get_refunds() {
1281
		$this->refunds = wc_get_orders( array(
1282
			'type'   => 'shop_order_refund',
1283
			'parent' => $this->get_id(),
1284
			'limit'  => -1,
1285
		) );
1286
		return $this->refunds;
1287
	}
1288
1289
	/**
1290
	 * Get amount already refunded.
1291
	 *
1292
	 * @since 2.2
1293
	 * @return string
1294
	 */
1295 View Code Duplication
	public function get_total_refunded() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1296
		global $wpdb;
1297
1298
		$total = $wpdb->get_var( $wpdb->prepare( "
1299
			SELECT SUM( postmeta.meta_value )
1300
			FROM $wpdb->postmeta AS postmeta
1301
			INNER JOIN $wpdb->posts AS posts ON ( posts.post_type = 'shop_order_refund' AND posts.post_parent = %d )
1302
			WHERE postmeta.meta_key = '_refund_amount'
1303
			AND postmeta.post_id = posts.ID
1304
		", $this->get_id() ) );
1305
1306
		return $total;
1307
	}
1308
1309
	/**
1310
	 * Get the total tax refunded.
1311
	 *
1312
	 * @since  2.3
1313
	 * @return float
1314
	 */
1315 View Code Duplication
	public function get_total_tax_refunded() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1316
		global $wpdb;
1317
1318
		$total = $wpdb->get_var( $wpdb->prepare( "
1319
			SELECT SUM( order_itemmeta.meta_value )
1320
			FROM {$wpdb->prefix}woocommerce_order_itemmeta AS order_itemmeta
1321
			INNER JOIN $wpdb->posts AS posts ON ( posts.post_type = 'shop_order_refund' AND posts.post_parent = %d )
1322
			INNER JOIN {$wpdb->prefix}woocommerce_order_items AS order_items ON ( order_items.order_id = posts.ID AND order_items.order_item_type = 'tax' )
1323
			WHERE order_itemmeta.order_item_id = order_items.order_item_id
1324
			AND order_itemmeta.meta_key IN ('tax_amount', 'shipping_tax_amount')
1325
		", $this->get_id() ) );
1326
1327
		return abs( $total );
1328
	}
1329
1330
	/**
1331
	 * Get the total shipping refunded.
1332
	 *
1333
	 * @since  2.4
1334
	 * @return float
1335
	 */
1336 View Code Duplication
	public function get_total_shipping_refunded() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1337
		global $wpdb;
1338
1339
		$total = $wpdb->get_var( $wpdb->prepare( "
1340
			SELECT SUM( order_itemmeta.meta_value )
1341
			FROM {$wpdb->prefix}woocommerce_order_itemmeta AS order_itemmeta
1342
			INNER JOIN $wpdb->posts AS posts ON ( posts.post_type = 'shop_order_refund' AND posts.post_parent = %d )
1343
			INNER JOIN {$wpdb->prefix}woocommerce_order_items AS order_items ON ( order_items.order_id = posts.ID AND order_items.order_item_type = 'shipping' )
1344
			WHERE order_itemmeta.order_item_id = order_items.order_item_id
1345
			AND order_itemmeta.meta_key IN ('cost')
1346
		", $this->get_id() ) );
1347
1348
		return abs( $total );
1349
	}
1350
1351
	/**
1352
	 * Gets the count of order items of a certain type that have been refunded.
1353
	 * @since  2.4.0
1354
	 * @param string $item_type
1355
	 * @return string
1356
	 */
1357
	public function get_item_count_refunded( $item_type = '' ) {
1358
		if ( empty( $item_type ) ) {
1359
			$item_type = array( 'line_item' );
1360
		}
1361
		if ( ! is_array( $item_type ) ) {
1362
			$item_type = array( $item_type );
1363
		}
1364
		$count = 0;
1365
1366
		foreach ( $this->get_refunds() as $refund ) {
0 ignored issues
show
Bug introduced by
The expression $this->get_refunds() of type array|object<stdClass> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1367
			foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
1368
				$count += $refunded_item->get_qty();
1369
			}
1370
		}
1371
1372
		return apply_filters( 'woocommerce_get_item_count_refunded', $count, $item_type, $this );
1373
	}
1374
1375
	/**
1376
	 * Get the total number of items refunded.
1377
	 *
1378
	 * @since  2.4.0
1379
	 * @param  string $item_type type of the item we're checking, if not a line_item
1380
	 * @return integer
1381
	 */
1382
	public function get_total_qty_refunded( $item_type = 'line_item' ) {
1383
		$qty = 0;
1384
		foreach ( $this->get_refunds() as $refund ) {
0 ignored issues
show
Bug introduced by
The expression $this->get_refunds() of type array|object<stdClass> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1385
			foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
1386
				$qty += $refunded_item->get_qty();
1387
			}
1388
		}
1389
		return $qty;
1390
	}
1391
1392
	/**
1393
	 * Get the refunded amount for a line item.
1394
	 *
1395
	 * @param  int $item_id ID of the item we're checking
1396
	 * @param  string $item_type type of the item we're checking, if not a line_item
1397
	 * @return integer
1398
	 */
1399 View Code Duplication
	public function get_qty_refunded_for_item( $item_id, $item_type = 'line_item' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1400
		$qty = 0;
1401
		foreach ( $this->get_refunds() as $refund ) {
0 ignored issues
show
Bug introduced by
The expression $this->get_refunds() of type array|object<stdClass> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1402
			foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
1403
				if ( absint( $refunded_item->get_meta( '_refunded_item_id' ) ) === $item_id ) {
1404
					$qty += $refunded_item->get_qty();
1405
				}
1406
			}
1407
		}
1408
		return $qty;
1409
	}
1410
1411
	/**
1412
	 * Get the refunded amount for a line item.
1413
	 *
1414
	 * @param  int $item_id ID of the item we're checking
1415
	 * @param  string $item_type type of the item we're checking, if not a line_item
1416
	 * @return integer
1417
	 */
1418 View Code Duplication
	public function get_total_refunded_for_item( $item_id, $item_type = 'line_item' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1419
		$total = 0;
1420
		foreach ( $this->get_refunds() as $refund ) {
0 ignored issues
show
Bug introduced by
The expression $this->get_refunds() of type array|object<stdClass> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1421
			foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
1422
				if ( absint( $refunded_item->get_meta( '_refunded_item_id' ) ) === $item_id ) {
1423
					$total += $refunded_item->get_total();
1424
				}
1425
			}
1426
		}
1427
		return $total * -1;
1428
	}
1429
1430
	/**
1431
	 * Get the refunded amount for a line item.
1432
	 *
1433
	 * @param  int $item_id ID of the item we're checking
1434
	 * @param  int $tax_id ID of the tax we're checking
1435
	 * @param  string $item_type type of the item we're checking, if not a line_item
1436
	 * @return double
1437
	 */
1438 View Code Duplication
	public function get_tax_refunded_for_item( $item_id, $tax_id, $item_type = 'line_item' ) {
0 ignored issues
show
Unused Code introduced by
The parameter $tax_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1439
		$total = 0;
1440
		foreach ( $this->get_refunds() as $refund ) {
0 ignored issues
show
Bug introduced by
The expression $this->get_refunds() of type array|object<stdClass> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1441
			foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
1442
				if ( absint( $refunded_item->get_meta( '_refunded_item_id' ) ) === $item_id ) {
1443
					$total += $refunded_item->get_total_tax();
1444
				}
1445
			}
1446
		}
1447
		return wc_round_tax_total( $total ) * -1;
1448
	}
1449
1450
	/**
1451
	 * Get total tax refunded by rate ID.
1452
	 *
1453
	 * @param  int $rate_id
1454
	 *
1455
	 * @return float
1456
	 */
1457
	public function get_total_tax_refunded_by_rate_id( $rate_id ) {
1458
		$total = 0;
1459
		foreach ( $this->get_refunds() as $refund ) {
0 ignored issues
show
Bug introduced by
The expression $this->get_refunds() of type array|object<stdClass> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1460
			foreach ( $refund->get_items( 'tax' ) as $refunded_item ) {
1461
				if ( absint( $refunded_item->get_rate_id() ) === $rate_id ) {
1462
					$total += abs( $refunded_item->tax_total() ) + abs( $refunded_item->shipping_tax_total() );
1463
				}
1464
			}
1465
		}
1466
1467
		return $total;
1468
	}
1469
1470
	/**
1471
	 * How much money is left to refund?
1472
	 * @return string
1473
	 */
1474
	public function get_remaining_refund_amount() {
1475
		return wc_format_decimal( $this->get_total() - $this->get_total_refunded(), wc_get_price_decimals() );
1476
	}
1477
1478
	/**
1479
	 * How many items are left to refund?
1480
	 * @return int
1481
	 */
1482
	public function get_remaining_refund_items() {
1483
		return absint( $this->get_item_count() - $this->get_item_count_refunded() );
1484
	}
1485
}
1486