Completed
Push — master ( d786b7...986814 )
by Justin
06:40 queued 01:07
created

WPSC_Purchase_Log::get_cart_contents()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 4
nop 0
dl 0
loc 25
rs 8.439
c 0
b 0
f 0
1
<?php
2
// by default, expire stats cache after 48 hours
3
// this doesn't have any effect if you're not using APC or memcached
4
5
if ( ! defined( 'WPSC_PURCHASE_LOG_STATS_CACHE_EXPIRE' ) ) {
6
	define( 'WPSC_PURCHASE_LOG_STATS_CACHE_EXPIRE', DAY_IN_SECONDS * 2 );
7
}
8
9
class WPSC_Purchase_Log extends WPSC_Query_Base {
10
	const INCOMPLETE_SALE		= 1;
11
	const ORDER_RECEIVED		= 2;
12
	const ACCEPTED_PAYMENT		= 3;
13
	const JOB_DISPATCHED		= 4;
14
	const CLOSED_ORDER			= 5;
15
	const PAYMENT_DECLINED		= 6;
16
	const REFUNDED				= 7;
17
	const REFUND_PENDING		= 8;
18
	const PARTIALLY_REFUNDED	= 9;
19
20
	/**
21
	 * Names of column that requires escaping values as strings before being inserted
22
	 * into the database
23
	 *
24
	 * @access private
25
	 * @static
26
	 * @since 3.8.9
27
	 *
28
	 * @var array
29
	 */
30
	private static $string_cols = array(
31
		'sessionid',
32
		'transactid',
33
		'authcode',
34
		'date',
35
		'gateway',
36
		'billing_country',
37
		'shipping_country',
38
		'email_sent',
39
		'stock_adjusted',
40
		'discount_data',
41
		'track_id',
42
		'billing_region',
43
		'shipping_region',
44
		'find_us',
45
		'engrave_text',
46
		'shipping_method',
47
		'shipping_option',
48
		'affiliate_id',
49
		'plugin_version',
50
		'notes',
51
	);
52
53
	/**
54
	 * Names of column that requires escaping values as integers before being inserted
55
	 * into the database
56
	 *
57
	 * @static
58
	 * @since 3.8.9
59
	 * @var array
60
	 */
61
	private static $int_cols = array(
62
		'id',
63
		'statusno',
64
		'processed',
65
		'user_ID',
66
	);
67
68
	/**
69
	 * Names of column that requires escaping values as float before being inserted
70
	 * into the database
71
	 *
72
	 * @static
73
	 * @since 4.0
74
	 * @var array
75
	 */
76
	private static $float_cols = array(
77
		'totalprice',
78
		'base_shipping',
79
		'discount_value',
80
		'wpec_taxes_total',
81
		'wpec_taxes_rate',
82
	);
83
84
	/**
85
	 * Array of metadata
86
	 *
87
	 * @static
88
	 * @since 4.0
89
	 * @var array
90
	 */
91
	private static $metadata = array(
0 ignored issues
show
Unused Code introduced by
The property $metadata is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
92
		'totalprice',
93
		'base_shipping',
94
		'discount_value',
95
		'wpec_taxes_total',
96
		'wpec_taxes_rate',
97
	);
98
99
	private $gateway_data = array();
100
101
	private $is_status_changed = false;
102
	private $previous_status   = false;
103
104
	private $cart_contents = array();
105
	private $cart_ids = array();
106
	private $can_edit = null;
107
108
	/**
109
	 * Contains the constructor arguments. This array is necessary because we will
110
	 * lazy load the DB row into $this->data whenever necessary. Lazy loading is,
111
	 * in turn, necessary because sometimes right after saving a new record, we need
112
	 * to fetch a property with the same object.
113
	 *
114
	 * @access private
115
	 * @since 3.8.9
116
	 *
117
	 * @var array
118
	 */
119
	private $args = array(
120
		'col'   => '',
121
		'value' => '',
122
	);
123
124
   protected $buyers_name = null;
125
   protected $buyers_city = null;
126
   protected $buyers_email = null;
127
   protected $buyers_address = null;
128
   protected $buyers_state_and_postcode = null;
129
   protected $buyers_country = null;
130
   protected $buyers_phone = null;
131
   protected $shipping_name = null;
132
   protected $shipping_address = null;
133
   protected $shipping_city = null;
134
   protected $shipping_state_and_postcode = null;
135
   protected $shipping_country = null;
136
   protected $payment_method = null;
137
   protected $shipping_method = null;
138
139
	/**
140
	 * Get the SQL query format for a column
141
	 *
142
	 * @since 3.8.9
143
	 * @param  string $col Name of the column
144
	 * @return string	  Placeholder
145
	 */
146
	private static function get_column_format( $col ) {
147
		if ( in_array( $col, self::$string_cols ) ) {
148
			return '%s';
149
		}
150
151
		if ( in_array( $col, self::$int_cols ) ) {
152
			return '%d';
153
		}
154
155
		return '%f';
156
	}
157
158
	/**
159
	 * Query the purchase log table to get sales and earning stats
160
	 *
161
	 * Accepts an array of arguments:
162
	 *	- 'ids': IDs of products for which you want to get stats
163
	 *	- 'products': array of WPSC_Product objects for which you want to get stats
164
	 *	- 'start' and 'end': the timestamp range (integers) during which you want
165
	 *						 to collect the stats.
166
	 *						 You can use none, either, or both of them.
167
	 *						 Note that the [start, end) interval is a left-closed,
168
	 *						 right-open.
169
	 *						 E.g.: to get stats from Jan 1st, 2013 to
170
	 *						 Dec 31st, 2013 (23:59:59),
171
	 *						 set "start" to the timestamp for Jan 1st, 2013, set
172
	 *						 "end" to the timestamp for Jan 1st, 2014
173
	 *  - 'order': what to sort the results by, defaults to 'id'.
174
	 *			Can be 'ids', 'sales', 'earnings' or empty string to disable sorting
175
	 *  - 'orderby': how to sort the results, defaults to 'ASC'.
176
	 *			  Can be 'ASC', 'DESC' (lowercase is fine too)
177
	 *  - 'per_page': How many items to fetch, defaults to 0, which fetches all results
178
	 *  - 'page': Which page of the results to fetch, defaults to 1.
179
	 *			Has no effect if per_page is set to 0.
180
	 *
181
	 * @since 3.8.14
182
	 * @param  array|string $args Arguments
183
	 * @return array	   Array containing 'sales' and 'earnings' stats
184
	 */
185
	public static function fetch_stats( $args ) {
186
		global $wpdb;
187
188
		$defaults = array(
189
			'ids'	  => array(), // IDs of the products to be queried
190
			'products' => array(), // Array of WPSC_Products objects
191
			'start'	=> 0,	   // Int. timestamp, has to be UTC
192
			'end'	  => 0,	   // Int. timestamp, has to be UTC
193
			'order'	=> 'ASC',
194
			'orderby'  => 'id',
195
			'per_page' => 0,
196
			'page'	 => 1,
197
		);
198
199
		$args = wp_parse_args( $args, $defaults );
200
201
		// convert more advanced date / time args into "start" and "end"
202
		$args = self::convert_date_args( $args );
203
204
		// build an array of WPSC_Product objects based on 'ids' and 'products' args
205
		$products = array_merge(
206
			$args['products'],
207
			array_map( array( 'WPSC_Product', 'get_instance' ), $args['ids'] )
208
		);
209
210
		// eliminate duplicates (Note: usage of this requires PHP 5.2.9)
211
		$products = array_unique( $products, SORT_REGULAR );
212
213
		if ( empty( $products ) ) {
214
			return null;
215
		}
216
217
		$needs_fetching = array();
218
219
		$stats = array(
220
			'sales'	=> 0,
221
			'earnings' => 0,
222
		);
223
224
		// if we have date restriction, that means we won't be able to rely upon
225
		// individual stats cache inside WPSC_Product objects
226
		$has_date_restriction = ! ( empty( $args['start'] ) && empty( $args['end'] ) );
227
228
		// if we do NOT have date restriction, find out which WPSC_Product object
229
		// has stats cache, and which don't
230
		if ( ! $has_date_restriction ) {
231
			foreach ( $products as $product ) {
232
				// store the ID if this product doesn't have a stats cache yet
233
				if ( $product->post->_wpsc_stats === '' ) {
234
					$needs_fetching[] = $product->post->ID;
235
				} else {
236
237
					// tally up the sales and earnings if this one has cache already
238
					$prod_meta = get_post_meta( $product->post->ID, '_wpsc_stats', true );
239
240
					if ( isset( $prod_meta['sales'] ) && isset( $prod_meta['earnings'] ) ) {
241
						$stats['sales']	+= $prod_meta['sales'];
242
						$stats['earnings'] += $prod_meta['earnings'];
243
					}
244
					$needs_fetching[]   = $product->post->ID;
245
				}
246
			}
247
		}
248
249
		// never hurts to make sure
250
		$needs_fetching = array_map( 'absint', $needs_fetching );
251
252
		// pagination arguments
253
		$limit = '';
254
255
		if ( ! empty( $args['per_page'] ) ) {
256
			$offset = ( $args['page'] - 1 ) * $args['per_page'];
257
			$limit = "LIMIT " . absint( $args['per_page'] ) . " OFFSET " . absint( $offset );
258
		}
259
260
		// sorting
261
		$order = '';
262
263
		if ( ! empty( $args['orderby'] ) )
264
			$order = "ORDER BY " . esc_sql( $args['orderby'] ) . " " . esc_sql( $args['order'] );
265
266
		// date
267
		$where = "WHERE p.processed IN (3, 4, 5)";
268
269
		if ( $has_date_restriction ) {
270
			// start date equal or larger than $args['start']
271
			if ( ! empty( $args['start'] ) )
272
				$where .= " AND CAST(p.date AS UNSIGNED) >= " . absint( $args['start'] );
273
274
			// end date less than $args['end'].
275
			// the "<" sign is not a typo, such upper limit makes it easier for
276
			// people to specify range.
277
			// E.g.: [1/1/2013 - 1/1/2014) rather than:
278
			//	   [1/1/2013 - 31/12/2013 23:59:59]
279
			if ( ! empty( $args['end'] ) )
280
				$where .= " AND CAST(p.date AS UNSIGNED) < " . absint( $args['end'] );
281
		}
282
283
		// assemble the SQL query
284
		$sql = "
285
			SELECT cc.prodid AS id, SUM(cc.quantity) AS sales, SUM(cc.quantity * cc.price) AS earnings
286
			FROM $wpdb->wpsc_purchase_logs AS p
287
			INNER JOIN
288
				$wpdb->wpsc_cart_contents AS cc
289
				ON p.id = cc.purchaseid AND cc.prodid IN (" . implode( ', ', $needs_fetching ) . ")
290
			{$where}
291
			GROUP BY cc.prodid
292
			{$order}
293
			{$limit}
294
		";
295
296
		// if the result is cached, don't bother querying the database
297
		$cache_key = md5( $sql );
298
		$results   = wp_cache_get( $cache_key, 'wpsc_purchase_logs_stats' );
299
300
		if ( false === $results ) {
301
			$results = $wpdb->get_results( $sql );
302
			wp_cache_set( $cache_key, $results, 'wpsc_purchase_logs_stats', WPSC_PURCHASE_LOG_STATS_CACHE_EXPIRE );
303
		}
304
305
		// tally up the sales and earnings from the query results
306
		foreach ( $results as $row ) {
307
			if ( ! $has_date_restriction ) {
308
				$product		   = WPSC_Product::get_instance( $row->id );
309
				$product->sales	= $row->sales;
310
				$product->earnings = $row->earnings;
311
			}
312
313
			$stats['sales']	+= $row->sales;
314
			$stats['earnings'] += $row->earnings;
315
		}
316
317
		return $stats;
318
	}
319
320
	/**
321
	 * Convert advanced date/time arguments like year, month, day, 'ago' etc.
322
	 * into basic arguments which are "start" and "end".
323
	 *
324
	 * @since  3.8.14
325
	 * @param  array $args Arguments
326
	 * @return array	   Arguments after converting
327
	 */
328
	private static function convert_date_args( $args ) {
329
		// TODO: Implement this
330
		return $args;
331
	}
332
333
	/**
334
	 * Get overall sales and earning stats for just one product
335
	 *
336
	 * @since 3.8.14
337
	 * @param  int $id ID of the product
338
	 * @return array   Array containing 'sales' and 'earnings' stats
339
	 */
340
	public static function get_stats_for_product( $id, $args = '' ) {
341
342
		$product = WPSC_Product::get_instance( $id );
343
344
		// if this product has variations
345
		if ( $product->has_variations ) {
346
			// get total stats of variations
347
			$args['products'] = $product->variations;
348
		} else {
349
			// otherwise, get stats of only this product
350
			$args['products'] = array( $product );
351
		}
352
353
		return self::fetch_stats( $args );
354
	}
355
356
	/**
357
	 * Check whether the status code indicates a completed status
358
	 *
359
	 * @since 3.8.13
360
	 * @param int  $status Status code
361
	 * @return boolean
362
	 */
363
	public static function is_order_status_completed( $status ) {
364
		$completed_status = apply_filters( 'wpsc_order_status_completed', array(
365
			self::ACCEPTED_PAYMENT,
366
			self::JOB_DISPATCHED,
367
			self::CLOSED_ORDER,
368
		) );
369
370
		return in_array( $status, $completed_status );
371
	}
372
373
	/**
374
	 * Update cache of the passed log object
375
	 *
376
	 * @access public
377
	 * @static
378
	 * @since 3.8.9
379
	 *
380
	 * @param WPSC_Purchase_Log $log The log object that you want to store into cache
381
	 * @return void
382
	 */
383
	public static function update_cache( &$log ) {
384
385
		// wpsc_purchase_logs stores the data array, while wpsc_purchase_logs_sessionid stores the
386
		// log id that's associated with the sessionid
387
		$id = $log->get( 'id' );
388
		wp_cache_set( $id, $log->data, 'wpsc_purchase_logs' );
389
390
		if ( $sessionid = $log->get( 'sessionid' ) ) {
391
			wp_cache_set( $sessionid, $id, 'wpsc_purchase_logs_sessionid' );
392
		}
393
394
		wp_cache_set( $id, $log->cart_contents, 'wpsc_purchase_log_cart_contents' );
395
		do_action( 'wpsc_purchase_log_update_cache', $log );
396
	}
397
398
	/**
399
	 * Deletes cache of a log (either by using the log ID or sessionid)
400
	 *
401
	 * @access public
402
	 * @static
403
	 * @since 3.8.9
404
	 *
405
	 * @param string $value The value to query
406
	 * @param string $col Optional. Defaults to 'id'. Whether to delete cache by using
407
	 *					a purchase log ID or sessionid
408
	 * @return void
409
	 */
410
	public static function delete_cache( $value, $col = 'id' ) {
411
		// this will pull from the old cache, so no worries there
412
		$log = new WPSC_Purchase_Log( $value, $col );
413
414
		wp_cache_delete( $log->get( 'id' ), 'wpsc_purchase_logs' );
415
		wp_cache_delete( $log->get( 'sessionid' ), 'wpsc_purchase_logs_sessionid' );
416
		wp_cache_delete( $log->get( 'id' ), 'wpsc_purchase_log_cart_contents' );
417
		wp_cache_delete( $log->get( 'id' ), 'wpsc_purchase_meta' );
418
419
		do_action( 'wpsc_purchase_log_delete_cache', $log, $value, $col );
420
	}
421
422
	/**
423
	 * Deletes a log from the database.
424
	 *
425
	 * @access  public
426
	 * @since   3.8.9
427
	 *
428
	 * @uses  $wpdb							  Global database instance.
429
	 * @uses  wpsc_is_store_admin()			  Check user has admin capabilities.
430
	 * @uses  WPSC_Purchase_Log::delete_cache()  Delete purchaselog cache.
431
	 * @uses  WPSC_Claimed_Stock				 Claimed Stock class.
432
	 *
433
	 * @param   string   $log_id   ID of the log.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $log_id not be false|string?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
434
	 * @return  boolean			Deleted successfully.
435
	 */
436
	public function delete( $log_id = false ) {
437
438
		global $wpdb;
439
440
		if ( ! ( isset( $this ) && get_class( $this ) == __CLASS__ ) ) {
441
			_wpsc_doing_it_wrong( 'WPSC_Purchase_Log::delete', __( 'WPSC_Purchase_Log::delete() is no longer a static method and should not be called statically.', 'wp-e-commerce' ), '3.9.0' );
442
		}
443
444
		if ( false !== $log_id ) {
445
			_wpsc_deprecated_argument( __FUNCTION__, '3.9.0', 'The $log_id param is not used. You must first create an instance of WPSC_Purchase_Log before calling this method.' );
446
		}
447
448
		if ( ! wpsc_is_store_admin() ) {
449
			return false;
450
		}
451
452
		$log_id = $this->get( 'id' );
453
454
		if ( $log_id > 0 ) {
455
456
			do_action( 'wpsc_purchase_log_before_delete', $log_id );
457
458
			self::delete_cache( $log_id );
459
460
			// Delete claimed stock
461
			$purchlog_status = $wpdb->get_var( $wpdb->prepare( "SELECT `processed` FROM `" . WPSC_TABLE_PURCHASE_LOGS . "` WHERE `id`= %d", $log_id ) );
462
			if ( $purchlog_status == WPSC_Purchase_Log::CLOSED_ORDER || $purchlog_status == WPSC_Purchase_Log::INCOMPLETE_SALE ) {
463
				$claimed_query = new WPSC_Claimed_Stock( array(
464
					'cart_id'		=> $log_id,
465
					'cart_submitted' => 1
466
				) );
467
				$claimed_query->clear_claimed_stock( 0 );
468
			}
469
470
			// Delete cart content, submitted data, then purchase log
471
			$wpdb->query( $wpdb->prepare( "DELETE FROM `" . WPSC_TABLE_CART_CONTENTS . "` WHERE `purchaseid` = %d", $log_id ) );
472
			$wpdb->query( $wpdb->prepare( "DELETE FROM `" . WPSC_TABLE_SUBMITTED_FORM_DATA . "` WHERE `log_id` IN (%d)", $log_id ) );
473
			$wpdb->query( $wpdb->prepare( "DELETE FROM `" . WPSC_TABLE_PURCHASE_LOGS . "` WHERE `id` = %d LIMIT 1", $log_id ) );
474
			$wpdb->query( $wpdb->prepare( "DELETE FROM `" . WPSC_TABLE_PURCHASE_META . "` WHERE `wpsc_purchase_id` = %d", $log_id ) );
475
			$wpdb->query( $wpdb->prepare( "DELETE FROM `" . WPSC_TABLE_DOWNLOAD_STATUS . "` WHERE `purchid` = %d ", $log_id ) );
476
477
			do_action( 'wpsc_purchase_log_delete', $log_id );
478
479
			return true;
480
481
		}
482
483
		return false;
484
485
	}
486
487
	/**
488
	 * Constructor of the purchase log object. If no argument is passed, this simply
489
	 * create a new empty object. Otherwise, this will get the purchase log from the
490
	 * DB either by using purchase log id or sessionid (specified by the 2nd argument).
491
	 *
492
	 * Eg:
493
	 *
494
	 * // get purchase log with ID number 23
495
	 * $log = new WPSC_Purchase_Log( 23 );
496
	 *
497
	 * // get purchase log with sessionid "asdf"
498
	 * $log = new WPSC_Purchase_Log( 'asdf', 'sessionid' )
499
	 *
500
	 * @access public
501
	 * @since 3.8.9
502
	 *
503
	 * @param string $value Optional. Defaults to false.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $value not be false|string?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
504
	 * @param string $col Optional. Defaults to 'id'.
505
	 */
506
	public function __construct( $value = false, $col = 'id' ) {
507
		if ( false === $value ) {
508
			return;
509
		}
510
511
		if ( is_array( $value ) ) {
512
			$this->set( $value );
513
			return;
514
		}
515
516
		global $wpdb;
517
518
		if ( ! in_array( $col, array( 'id', 'sessionid' ) ) ) {
519
			return;
520
		}
521
522
		// store the constructor args into an array so that later we can lazy load the data
523
		$this->args = array(
524
			'col'   => $col,
525
			'value' => $value,
526
		);
527
528
		// if the sessionid is in cache, pull out the id
529
		if ( $col == 'sessionid'  && $id = wp_cache_get( $value, 'wpsc_purchase_logs_sessionid' ) ) {
530
				$col = 'id';
531
				$value = $id;
532
		}
533
534
		// if the id is specified, try to get from cache
535
		if ( $col == 'id' ) {
536
			$this->data = wp_cache_get( $value, 'wpsc_purchase_logs' );
537
			$this->cart_contents = wp_cache_get( $value, 'wpsc_purchase_log_cart_contents' );
538
		}
539
540
		// cache exists
541
		if ( $this->data ) {
542
			$this->set_meta_props();
543
			$this->fetched = true;
0 ignored issues
show
Documentation Bug introduced by
The property $fetched was declared of type string, but true is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
544
			$this->exists  = true;
0 ignored issues
show
Documentation Bug introduced by
The property $exists was declared of type string, but true is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
545
			return;
546
		}
547
	}
548
549
	private function set_total_shipping() {
550
551
		$base_shipping  = $this->get( 'base_shipping' );
552
		$item_shipping  = wp_list_pluck( $this->get_cart_contents(), 'pnp' );
553
554
		$this->meta_data['total_shipping'] = $base_shipping + array_sum( $item_shipping );
555
556
		return $this->meta_data['total_shipping'];
557
	}
558
559
	private function set_gateway_name() {
560
		global $wpsc_gateways;
561
		$gateway = $this->get( 'gateway' );
562
		$gateway_name = $gateway;
563
564
		if( 'wpsc_merchant_testmode' == $gateway )
565
			$gateway_name = __( 'Manual Payment', 'wp-e-commerce' );
566
		elseif ( isset( $wpsc_gateways[$gateway] ) )
567
			$gateway_name = $wpsc_gateways[$gateway]['name'];
568
569
		$this->meta_data['gateway_name'] = $gateway_name;
570
		return $this->meta_data['gateway_name'];
571
	}
572
573
	private function set_shipping_method_names() {
574
		global $wpsc_shipping_modules;
575
576
		$shipping_method = $this->get( 'shipping_method' );
577
		$shipping_option = $this->get( 'shipping_option' );
578
		$shipping_method_name = $shipping_method;
579
		$shipping_option_name = $shipping_option;
580
581
		if ( ! empty ( $wpsc_shipping_modules[$shipping_method] ) ) {
0 ignored issues
show
Coding Style introduced by
Space before opening parenthesis of function call prohibited
Loading history...
582
			$shipping_class = $wpsc_shipping_modules[$shipping_method];
583
			$shipping_method_name = $shipping_class->name;
584
		}
585
586
		$this->meta_data['shipping_method_name'] = $shipping_method_name;
587
		$this->meta_data['shipping_option_name'] = $shipping_option_name;
588
	}
589
590
	private function set_meta_props() {
591
592
		foreach ( wpsc_get_purchase_custom( $this->get( 'id' ) ) as $key => $value  ) {
593
			$this->meta_data[ $key ] = wpsc_get_purchase_meta( $this->get( 'id' ), $key, true );
594
		}
595
596
		$this->set_total_shipping();
597
		$this->set_gateway_name();
598
		$this->set_shipping_method_names();
599
	}
600
601
public function get_meta() {
602
603
		if ( empty( $this->data ) || empty( $this->meta_data ) ) {
604
			$this->fetch();
605
		}
606
607
		return (array) apply_filters( 'wpsc_purchase_log_meta_data', $this->meta_data );
608
	}
609
610
	/**
611
	 * Fetches the actual record from the database
612
	 *
613
	 * @access protected
614
	 * @since 3.8.9
615
	 *
616
	 * @return void
617
	 */
618
	protected function fetch() {
619
		global $wpdb;
620
621
		if ( $this->fetched ) {
622
			return;
623
		}
624
625
		// If $this->args is not set yet, it means the object contains a new unsaved
626
		// row so we don't need to fetch from DB
627
		if ( ! $this->args['col'] || ! $this->args['value'] ) {
628
			return;
629
		}
630
631
		extract( $this->args );
0 ignored issues
show
introduced by
extract() usage is highly discouraged, due to the complexity and unintended issues it might cause.
Loading history...
632
633
		$format = self::get_column_format( $col );
634
		$sql	= $wpdb->prepare( "SELECT * FROM " . WPSC_TABLE_PURCHASE_LOGS . " WHERE {$col} = {$format}", $value );
635
636
		$this->exists = false;
0 ignored issues
show
Documentation Bug introduced by
The property $exists was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
637
638
		if ( $data = $wpdb->get_row( $sql, ARRAY_A ) ) {
639
			$this->exists		= true;
0 ignored issues
show
Documentation Bug introduced by
The property $exists was declared of type string, but true is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
640
			$this->data		  = apply_filters( 'wpsc_purchase_log_data', $data );
641
			$this->cart_contents = $this->get_cart_contents();
642
643
			$this->set_meta_props();
644
			self::update_cache( $this );
645
		}
646
647
		do_action( 'wpsc_purchase_log_fetched', $this );
648
649
		$this->fetched = true;
0 ignored issues
show
Documentation Bug introduced by
The property $fetched was declared of type string, but true is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
650
	}
651
652
	/**
653
	 * Prepares the return value for get() (apply_filters, etc).
654
	 *
655
	 * @access protected
656
	 * @since  4.0
657
	 *
658
	 * @param  mixed  $value Value fetched
659
	 * @param  string $key   Key for $data.
660
	 *
661
	 * @return mixed
662
	 */
663
	protected function prepare_get( $value, $key ) {
664
		return apply_filters( 'wpsc_purchase_log_get_property', $value, $key, $this );
665
	}
666
667
	/**
668
	 * Prepares the return value for get_data() (apply_filters, etc).
669
	 *
670
	 * @access protected
671
	 * @since  4.0
672
	 *
673
	 * @return mixed
674
	 */
675
	protected function prepare_get_data() {
676
		return apply_filters( 'wpsc_purchase_log_get_data', $this->data, $this );
677
	}
678
679
	/**
680
	 * Prepares the return value for get_meta() (apply_filters, etc).
681
	 *
682
	 * @access protected
683
	 * @since  4.0
684
	 *
685
	 * @return mixed
686
	 */
687
	protected function prepare_get_meta() {
688
		return (array) apply_filters( 'wpsc_purchase_log_meta_data', $this->meta_data );
689
	}
690
691
	public function get_cart_contents() {
692
		global $wpdb;
693
694
		if ( ! empty( $this->cart_contents ) && $this->fetched ) {
695
			return $this->cart_contents;
696
		}
697
698
		$id = $this->get( 'id' );
699
700
		// Bail if we don't have a log object yet (no id).
701
		if ( empty( $id ) ) {
702
			return $this->cart_contents;
703
		}
704
705
		$sql = $wpdb->prepare( "SELECT * FROM " . WPSC_TABLE_CART_CONTENTS . " WHERE purchaseid = %d", $id );
706
		$this->cart_contents = $wpdb->get_results( $sql );
707
708
		if ( is_array( $this->cart_contents ) ) {
709
			foreach ( $this->cart_contents as $index => $item ) {
710
				$this->cart_ids[ absint( $item->id ) ] = $index;
711
			}
712
		}
713
714
		return $this->cart_contents;
715
	}
716
717
	public function get_cart_item( $item_id ) {
718
		$item_id = absint( $item_id );
719
		$cart	= $this->get_cart_contents();
720
721
		if ( isset( $this->cart_ids[ $item_id ] ) ) {
722
			return $cart[ $this->cart_ids[ $item_id ] ];
723
		}
724
725
		return false;
726
	}
727
728
	public function get_cart_item_from_product_id( $product_id ) {
729
		$product_id = absint( $product_id );
730
		$cart	   = $this->get_cart_contents();
731
732
		foreach ( $cart as $item ) {
733
			if ( $product_id === absint( $item->prodid ) ) {
734
				return $item;
735
			}
736
		}
737
738
		return false;
739
	}
740
741
	public function update_cart_item( $item_id, $data ) {
742
		global $wpdb;
743
744
		$item_id = absint( $item_id );
745
		$item = $this->get_cart_item( $item_id );
746
747
		if ( $item ) {
748
			do_action( 'wpsc_purchase_log_before_update_cart_item', $item_id );
749
750
			$data = wp_unslash( $data );
751
			$result = $wpdb->update( WPSC_TABLE_CART_CONTENTS, $data, array( 'id' => $item_id  ) );
752
753
			if ( $result ) {
754
755
				$this->cart_contents = array();
756
				$this->get_cart_item( $item_id );
757
758
				do_action( 'wpsc_purchase_log_update_cart_item', $item_id );
759
			}
760
761
			return $result;
762
		}
763
764
		return false;
765
	}
766
767
	public function remove_cart_item( $item_id ) {
768
		global $wpdb;
769
770
		$item_id = absint( $item_id );
771
		$item = $this->get_cart_item( $item_id );
772
773
		if ( $item ) {
774
			do_action( 'wpsc_purchase_log_before_remove_cart_item', $item_id );
775
776
			$result = $wpdb->delete( WPSC_TABLE_CART_CONTENTS, array( 'id' => $item_id ) );
777
778
			if ( $result ) {
779
780
				unset( $this->cart_contents[ $this->cart_ids[ $item_id ] ] );
781
				unset( $this->cart_ids[ $item_id ] );
782
783
				do_action( 'wpsc_purchase_log_remove_cart_item', $item_id );
784
			}
785
786
			return $result;
787
		}
788
789
		return false;
790
	}
791
792
	public function get_gateway_data( $from_currency = false, $to_currency = false ) {
793
		if ( ! $this->exists() ) {
794
			return array();
795
		}
796
797
		$subtotal = 0;
798
		$shipping = wpsc_convert_currency( (float) $this->get( 'base_shipping' ), $from_currency, $to_currency );
799
		$items	= array();
800
801
		$this->gateway_data = array(
802
			'amount'  => wpsc_convert_currency( $this->get( 'totalprice' ), $from_currency, $to_currency ),
803
			'invoice' => $this->get( 'sessionid' ),
804
			'tax'	 => wpsc_convert_currency( $this->get( 'wpec_taxes_total' ), $from_currency, $to_currency ),
805
		);
806
807
		foreach ( $this->cart_contents as $item ) {
808
			$item_price = wpsc_convert_currency( $item->price, $from_currency, $to_currency );
809
			$items[] = array(
810
				'name'	 => $item->name,
811
				'amount'   => $item_price,
812
				'tax'	  => wpsc_convert_currency( $item->tax_charged, $from_currency, $to_currency ),
813
				'quantity' => $item->quantity,
814
			);
815
			$subtotal += $item_price * $item->quantity;
816
			$shipping += wpsc_convert_currency( $item->pnp, $from_currency, $to_currency );
817
		}
818
819
		$this->gateway_data['discount'] = wpsc_convert_currency( (float) $this->get( 'discount_value' ), $from_currency, $to_currency );
820
821
		$this->gateway_data['items'] = $items;
822
		$this->gateway_data['shipping'] = $shipping;
823
		$this->gateway_data['subtotal'] = $subtotal;
824
825
		if ( $from_currency ) {
826
			// adjust total amount in case there's slight decimal error
827
			$total = $subtotal + $shipping + $this->gateway_data['tax'] - $this->gateway_data['discount'];
828
			if ( $this->gateway_data['amount'] != $total ) {
829
				$this->gateway_data['amount'] = $total;
830
			}
831
		}
832
833
		$this->gateway_data = apply_filters( 'wpsc_purchase_log_gateway_data', $this->gateway_data, $this->get_data() );
834
		return $this->gateway_data;
835
	}
836
837
	/**
838
	 * Sets a property to a certain value. This function accepts a key and a value
839
	 * as arguments, or an associative array containing key value pairs.
840
	 *
841
	 * Loops through data, comparing against database, and saves as meta if not found in purchase log table.
842
	 *
843
	 * @access public
844
	 * @since 3.8.9
845
	 *
846
	 * @param mixed $key Name of the property (column), or an array containing key
847
	 *				   value pairs
848
	 * @param string|int $value Optional. Defaults to false. In case $key is a string,
0 ignored issues
show
Documentation introduced by
Should the type for parameter $value not be string|integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
849
	 *						  this should be specified.
850
	 * @return WPSC_Purchase_Log The current object (for method chaining)
851
	 */
852
	public function set( $key, $value = null ) {
853
		if ( is_array( $key ) ) {
854
			$properties = $key;
855
		} else {
856
			if ( is_null( $value ) ) {
857
				return $this;
858
			}
859
860
			$properties = array( $key => $value );
861
		}
862
863
		$properties = apply_filters( 'wpsc_purchase_log_set_properties', $properties, $this );
864
865
		if ( array_key_exists( 'processed', $properties ) ) {
866
			$this->previous_status = $this->get( 'processed' );
867
868
			if ( $properties['processed'] != $this->previous_status ) {
869
				$this->is_status_changed = true;
870
			}
871
		}
872
873
		if ( ! is_array( $this->data ) ) {
874
			$this->data = array();
875
		}
876
877
		foreach ( $properties as $key => $value ) {
878
			if ( ! in_array( $key, array_merge( self::$string_cols, self::$int_cols, self::$float_cols ) ) ) {
879
				$this->meta_data[ $key ] = $value;
880
				unset( $properties[ $key ] );
881
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
882
883
		}
884
885
		$this->data = array_merge( $this->data, $properties );
886
		return $this;
887
	}
888
889
	/**
890
	 * Returns an array containing the parameter format so that this can be used in
891
	 * $wpdb methods (update, insert etc.)
892
	 *
893
	 * @access private
894
	 * @since 3.8.9
895
	 *
896
	 * @param array $data
897
	 * @return array
898
	 */
899
	private function get_data_format( $data ) {
900
		$format = array();
901
902
		foreach ( $data as $key => $value ) {
903
			$format[] = self::get_column_format( $key );
904
		}
905
906
		return $format;
907
	}
908
909
	/**
910
	 * Saves the purchase log back to the database
911
	 *
912
	 * @access public
913
	 * @since 3.8.9
914
	 *
915
	 * @return void
916
	 */
917
	public function save() {
918
		global $wpdb;
919
920
		do_action( 'wpsc_purchase_log_pre_save', $this );
921
922
		// $this->args['col'] is empty when the record is new and needs to
923
		// be inserted. Otherwise, it means we're performing an update
924
		$where_col = $this->args['col'];
925
926
		$result = false;
927
928
		if ( $where_col ) {
929
			$where_val = $this->args['value'];
930
			$where_format = self::get_column_format( $where_col );
931
			do_action( 'wpsc_purchase_log_pre_update', $this );
932
			self::delete_cache( $where_val, $where_col );
933
			$data = apply_filters( 'wpsc_purchase_log_update_data', $this->data );
934
			$format = $this->get_data_format( $data );
935
			$result = $wpdb->update( WPSC_TABLE_PURCHASE_LOGS, $data, array( $where_col => $where_val ), $format, array( $where_format ) );
936
			do_action( 'wpsc_purchase_log_update', $this );
937
		} else {
938
			do_action( 'wpsc_purchase_log_pre_insert', $this );
939
			$data = apply_filters( 'wpsc_purchase_log_insert_data', $this->data );
940
			$format = $this->get_data_format( $data );
941
			$result = $wpdb->insert( WPSC_TABLE_PURCHASE_LOGS, $data, $format );
942
943
			if ( $result ) {
944
				$this->set( 'id', $wpdb->insert_id );
945
946
				// set $this->args so that properties can be lazy loaded right after
947
				// the row is inserted into the db
948
				$this->args = array(
949
					'col'   => 'id',
950
					'value' => $this->get( 'id' ),
951
				);
952
			}
953
954
			do_action( 'wpsc_purchase_log_insert', $this );
955
		}
956
957
		if ( $this->is_status_changed ) {
958
959
			if ( $this->is_transaction_completed() ) {
960
				$this->update_downloadable_status();
961
			}
962
963
			$current_status		  = $this->get( 'processed' );
964
			$previous_status		 = $this->previous_status;
965
			$this->previous_status   = $current_status;
966
			$this->is_status_changed = false;
967
968
			do_action( 'wpsc_update_purchase_log_status', $this->get( 'id' ), $current_status, $previous_status, $this );
969
		}
970
971
		if ( ! empty( $this->meta_data ) ) {
972
			$this->save_meta();
973
		}
974
975
		do_action( 'wpsc_purchase_log_save', $this );
976
977
		return $result;
978
	}
979
980
	/**
981
	 * Save meta data for purchase log, if any was set via set().
982
	 *
983
	 * @access public
984
	 * @since  4.0
985
	 *
986
	 * @return WPSC_Query_Base  The current object (for method chaining)
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use WPSC_Purchase_Log.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
987
	 */
988
	public function save_meta() {
989
		do_action( 'wpsc_purchase_log_pre_save_meta', $this );
990
991
		$meta = $this->get_meta();
992
993
		foreach ( $meta as $key => $value ) {
994
			wpsc_update_purchase_meta( $this->get( 'id' ), $key, $value );
995
		}
996
997
		do_action( 'wpsc_purchase_log_save_meta', $this );
998
999
		return $this;
1000
	}
1001
1002
	private function update_downloadable_status() {
1003
		global $wpdb;
1004
1005
		foreach ( $this->get_cart_contents() as $item ) {
1006
			$wpdb->update(
1007
				WPSC_TABLE_DOWNLOAD_STATUS,
1008
				array(
1009
					'active' => '1'
1010
				),
1011
				array(
1012
					'cartid'  => $item->id,
1013
					'purchid' => $this->get( 'id' ),
1014
				)
1015
			);
1016
		}
1017
	}
1018
1019
	/**
1020
	 * Adds ability to retrieve a purchase log by a meta key or value.
1021
	 *
1022
	 * @since  4.0
1023
	 *
1024
	 * @param  string $key   Meta key. Optional.
1025
	 * @param  string $value Meta value. Optional.
1026
	 *
1027
	 * @return false|WPSC_Purchase_Log  False if no log is found or meta key and value are both not provided. WPSC_Purchase_Log object if found.
1028
	 */
1029
	public static function get_log_by_meta( $key = '', $value = '' ) {
1030
1031
		if ( empty( $key ) && empty( $value ) ) {
1032
			return false;
1033
		}
1034
1035
		global $wpdb;
1036
1037
		if ( ! empty( $key ) && empty( $value ) ) {
1038
			$sql = $wpdb->prepare( 'SELECT wpsc_purchase_id FROM ' . WPSC_TABLE_PURCHASE_META . ' WHERE meta_key = %s', $key );
1039
		} else if ( empty( $key ) && ! empty( $value ) ) {
1040
			$sql = $wpdb->prepare( 'SELECT wpsc_purchase_id FROM ' . WPSC_TABLE_PURCHASE_META . ' WHERE meta_value = %s', $value );
1041
		} else {
1042
			$sql = $wpdb->prepare( 'SELECT wpsc_purchase_id FROM ' . WPSC_TABLE_PURCHASE_META . ' WHERE meta_key = %s AND meta_value = %s', $key, $value );
1043
		}
1044
1045
		$id = $wpdb->get_var( $sql );
1046
1047
		if ( $id ) {
1048
			return new WPSC_Purchase_Log( $id );
1049
		} else {
1050
			return false;
1051
		}
1052
	}
1053
1054
	public function get_next_log_id() {
1055
		if ( ! $this->exists() ) {
1056
			return false;
1057
		}
1058
1059
		global $wpdb;
1060
1061
		$sql = $wpdb->prepare(
1062
			"SELECT MIN(id) FROM " . WPSC_TABLE_PURCHASE_LOGS . " WHERE id > %d",
1063
			$this->get( 'id' )
1064
		);
1065
1066
		return $wpdb->get_var( $sql );
1067
	}
1068
1069
	public function get_previous_log_id() {
1070
		if ( ! $this->exists() ) {
1071
			return false;
1072
		}
1073
1074
		global $wpdb;
1075
1076
		$sql = $wpdb->prepare(
1077
			"SELECT MAX(id) FROM " . WPSC_TABLE_PURCHASE_LOGS . " WHERE id < %d",
1078
			$this->get( 'id' )
1079
		);
1080
1081
		return $wpdb->get_var( $sql );
1082
	}
1083
1084
	public function is_transaction_completed() {
1085
		return WPSC_Purchase_Log::is_order_status_completed( $this->get( 'processed' ) );
1086
	}
1087
1088
	public function can_edit() {
1089
		if ( null === $this->can_edit ) {
1090
			$can_edit = current_user_can( 'edit_others_posts' ) && ! $this->is_transaction_completed();
1091
			$this->can_edit = apply_filters( 'wpsc_can_edit_order', $can_edit, $this );
1092
		}
1093
1094
		return $this->can_edit;
1095
	}
1096
1097
	public function is_order_received() {
1098
		return $this->get( 'processed' ) == self::ORDER_RECEIVED;
1099
	}
1100
1101
	public function is_incomplete_sale() {
1102
		return $this->get( 'processed' ) == self::INCOMPLETE_SALE;
1103
	}
1104
1105
	public function is_accepted_payment() {
1106
		return $this->get( 'processed' ) == self::ACCEPTED_PAYMENT;
1107
	}
1108
1109
	public function is_job_dispatched() {
1110
		return $this->get( 'processed' ) == self::JOB_DISPATCHED;
1111
	}
1112
1113
	public function is_closed_order() {
1114
		return $this->get( 'processed' ) == self::CLOSED_ORDER;
1115
	}
1116
1117
	public function is_payment_declined() {
1118
		return $this->get( 'processed' ) == self::PAYMENT_DECLINED;
1119
	}
1120
1121
	public function is_refunded() {
1122
		return $this->get( 'processed' ) == self::REFUNDED;
1123
	}
1124
1125
	public function is_refund_pending() {
1126
		return $this->get( 'processed' ) == self::REFUND_PENDING;
1127
	}
1128
1129
	/*
1130
	 * Utility methods using the $purchlogitem global.. Global usage to be replaced in the future.
1131
	 *
1132
	 * TODO: seriously get rid of all these badly coded purchaselogs.functions.php functions
1133
	 * and wpsc_purchaselogs/wpsc_purchaselogs_items classes.
1134
	 */
1135
1136
	/**
1137
	 * Init the purchase log items for this purchase log.
1138
	 *
1139
	 * @since  4.0
1140
	 *
1141
	 * @return wpsc_purchaselogs_items|false The purhchase log item object or false.
1142
	 */
1143
	public function init_items() {
1144
		global $purchlogitem;
1145
		if ( ! $this->exists() ) {
1146
			return false;
1147
		}
1148
1149
		$purchlogitem = new wpsc_purchaselogs_items( $this->get( 'id' ), $this );
1150
	}
1151
1152
	public function buyers_name() {
1153
		global $purchlogitem;
1154
1155
		if ( null === $this->buyers_name ) {
1156
			$first_name = $last_name = '';
1157
1158
			if ( isset( $purchlogitem->userinfo['billingfirstname'] ) ) {
1159
				$first_name = $purchlogitem->userinfo['billingfirstname']['value'];
1160
			}
1161
1162
			if ( isset( $purchlogitem->userinfo['billinglastname'] ) ) {
1163
				$last_name = ' ' . $purchlogitem->userinfo['billinglastname']['value'];
1164
			}
1165
1166
			$this->buyers_name = trim( $first_name . $last_name );
1167
		}
1168
1169
		return $this->buyers_name;
1170
	}
1171
1172
	public function buyers_city() {
1173
		global $purchlogitem;
1174
1175
		if ( null === $this->buyers_city ) {
1176
			$this->buyers_city = isset( $purchlogitem->userinfo['billingcity']['value'] ) ? $purchlogitem->userinfo['billingcity']['value'] : '';
1177
		}
1178
1179
		return $this->buyers_city;
1180
	}
1181
1182
	public function buyers_email() {
1183
		global $purchlogitem;
1184
1185
		if ( null === $this->buyers_email ) {
1186
			$this->buyers_email = isset( $purchlogitem->userinfo['billingemail']['value'] ) ? $purchlogitem->userinfo['billingemail']['value'] : '';
1187
		}
1188
1189
		return $this->buyers_email;
1190
	}
1191
1192
	public function buyers_address() {
1193
		global $purchlogitem;
1194
1195
		if ( null === $this->buyers_address ) {
1196
			$this->buyers_address = isset( $purchlogitem->userinfo['billingaddress']['value'] ) ? nl2br( esc_html( $purchlogitem->userinfo['billingaddress']['value'] ) ) : '';
1197
		}
1198
1199
		return $this->buyers_address;
1200
	}
1201
1202
	public function buyers_state_and_postcode() {
1203
		global $purchlogitem;
1204
1205
		if ( null === $this->buyers_state_and_postcode ) {
1206
			if ( is_numeric( $purchlogitem->extrainfo->billing_region ) ) {
1207
				$state = wpsc_get_region( $purchlogitem->extrainfo->billing_region );
1208
			} else {
1209
				$state = $purchlogitem->userinfo['billingstate']['value'];
1210
				$state = is_numeric( $state ) ? wpsc_get_region( $state ) : $state;
1211
			}
1212
1213
			$output = esc_html( $state );
1214
1215
			if ( isset( $purchlogitem->userinfo['billingpostcode']['value'] ) && ! empty( $purchlogitem->userinfo['billingpostcode']['value'] ) ) {
1216
				if ( $output ) {
1217
					$output .= ', '; // TODO determine if it's ok to make this a space only (like shipping_state_and_postcode)
1218
				}
1219
				$output .= $purchlogitem->userinfo['billingpostcode']['value'];
1220
			}
1221
1222
			$this->buyers_state_and_postcode = $output;
1223
		}
1224
1225
		return $this->buyers_state_and_postcode;
1226
	}
1227
1228
	public function buyers_country() {
1229
		global $purchlogitem;
1230
1231
		if ( null === $this->buyers_country ) {
1232
			$this->buyers_country = isset( $purchlogitem->userinfo['billingcountry']['value'] ) ? wpsc_get_country( $purchlogitem->userinfo['billingcountry']['value'] ) : '';
1233
		}
1234
1235
		return $this->buyers_country;
1236
	}
1237
1238
	public function buyers_phone() {
1239
		global $purchlogitem;
1240
1241
		if ( null === $this->buyers_phone ) {
1242
			$this->buyers_phone = isset( $purchlogitem->userinfo['billingphone']['value'] ) ? $purchlogitem->userinfo['billingphone']['value'] : '';
1243
		}
1244
1245
		return $this->buyers_phone;
1246
	}
1247
1248
	public function shipping_name() {
1249
		global $purchlogitem;
1250
1251
		if ( null === $this->shipping_name ) {
1252
			$this->shipping_name = isset( $purchlogitem->shippinginfo['shippingfirstname']['value'] ) ? $purchlogitem->shippinginfo['shippingfirstname']['value'] : '';
1253
		}
1254
1255
		return $this->shipping_name;
1256
	}
1257
1258
	public function shipping_city() {
1259
		global $purchlogitem;
1260
1261
		if ( null === $this->shipping_city ) {
1262
			$this->shipping_city = isset( $purchlogitem->shippinginfo['shippingcity']['value'] ) ? $purchlogitem->shippinginfo['shippingcity']['value'] : '';
1263
		}
1264
1265
		return $this->shipping_city;
1266
	}
1267
1268
	public function shipping_address() {
1269
		global $purchlogitem;
1270
1271
		if ( null === $this->shipping_address ) {
1272
			$this->shipping_address = isset( $purchlogitem->shippinginfo['shippingaddress']['value'] ) ? nl2br( esc_html( $purchlogitem->shippinginfo['shippingaddress']['value'] ) ) : '';
1273
		}
1274
1275
		return $this->shipping_address;
1276
	}
1277
1278
	public function shipping_state_and_postcode() {
1279
		global $purchlogitem;
1280
1281
		if ( null === $this->shipping_state_and_postcode ) {
1282
			if ( is_numeric( $purchlogitem->extrainfo->shipping_region ) ) {
1283
				$output = wpsc_get_region( $purchlogitem->extrainfo->shipping_region );
1284
			} else {
1285
				$state = $purchlogitem->shippinginfo['shippingstate']['value'];
1286
				$output = is_numeric( $state ) ? wpsc_get_region( $state ) : $state;
1287
			}
1288
1289
			if ( !empty( $purchlogitem->shippinginfo['shippingpostcode']['value'] ) ){
1290
				if ( $output ) {
1291
					$output .= ' ';
1292
				}
1293
1294
				$output .= $purchlogitem->shippinginfo['shippingpostcode']['value'];
1295
			}
1296
1297
			$this->shipping_state_and_postcode = $output;
1298
		}
1299
1300
		return $this->shipping_state_and_postcode;
1301
	}
1302
1303
	public function shipping_country() {
1304
		global $purchlogitem;
1305
1306
		if ( null === $this->shipping_country ) {
1307
			$this->shipping_country = isset( $purchlogitem->shippinginfo['shippingcountry'] )
1308
				? wpsc_get_country( $purchlogitem->shippinginfo['shippingcountry']['value'] )
1309
				: '';
1310
		}
1311
1312
		return $this->shipping_country;
1313
	}
1314
1315
	public function payment_method() {
1316
		global $purchlogitem, $nzshpcrt_gateways;
1317
1318
		if ( null === $this->payment_method ) {
1319
			if ( 'wpsc_merchant_testmode' == $purchlogitem->extrainfo->gateway ) {
1320
				$this->payment_method = __( 'Manual Payment', 'wp-e-commerce' );
1321
			} else {
1322
				foreach ( (array) $nzshpcrt_gateways as $gateway ) {
1323
					if ( isset( $gateway['internalname'] ) && $gateway['internalname'] == $purchlogitem->extrainfo->gateway ) {
1324
						$this->payment_method = $gateway['name'];
1325
					}
1326
				}
1327
1328
				if ( ! $this->payment_method ) {
1329
					$this->payment_method = $purchlogitem->extrainfo->gateway;
1330
				}
1331
			}
1332
		}
1333
1334
		return $this->payment_method;
1335
	}
1336
1337
	public function shipping_method() {
1338
		global $purchlogitem, $wpsc_shipping_modules;
1339
1340
		if ( null === $this->shipping_method ) {
1341
1342
			if ( ! empty( $wpsc_shipping_modules[ $purchlogitem->extrainfo->shipping_method ] ) ) {
1343
				$this->shipping_method = $wpsc_shipping_modules[ $purchlogitem->extrainfo->shipping_method ]->getName();
1344
			} else {
1345
				$this->shipping_method = $purchlogitem->extrainfo->shipping_method;
1346
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
1347
1348
		}
1349
1350
		return $this->shipping_method;
1351
	}
1352
1353
	/**
1354
	 * Returns base shipping should make a function to calculate items shipping as well
1355
	 *
1356
	 * @since  4.0
1357
	 *
1358
	 * @param  boolean $numeric Return numeric value.
1359
	 *
1360
	 * @return mixed
1361
	 */
1362
	public function discount( $numeric = false ) {
1363
		global $purchlogitem;
1364
1365
		$discount = $purchlogitem->extrainfo->discount_value;
1366
		if ( ! $numeric ) {
1367
			$discount = wpsc_currency_display( $discount, array( 'display_as_html' => false ) );
1368
		}
1369
1370
		return $discount;
1371
	}
1372
1373
	/**
1374
	 * Returns base shipping should make a function to calculate items shipping as well
1375
	 *
1376
	 * @since  4.0
1377
	 *
1378
	 * @param  boolean $numeric	   Return numeric value.
1379
	 * @param  boolean $include_items Whether to calculate per-item-shipping.
1380
	 *
1381
	 * @return mixed
1382
	 */
1383
	public function shipping( $numeric = false, $include_items = false ) {
1384
		$total_shipping = $this->get( 'base_shipping' );
1385
1386
		if ( $include_items ) {
1387
			$total_shipping = $this->meta_data['total_shipping'];
1388
		}
1389
1390
		if ( ! $numeric ) {
1391
			$total_shipping = wpsc_currency_display( $total_shipping, array( 'display_as_html' => false ) );
1392
		}
1393
1394
		return $total_shipping;
1395
	}
1396
1397
	/**
1398
	 * Returns taxes total.
1399
	 *
1400
	 * @since  4.0
1401
	 *
1402
	 * @param  boolean $numeric Return numeric value.
1403
	 *
1404
	 * @return mixed
1405
	 */
1406
	public function taxes( $numeric = false ) {
1407
		global $purchlogitem;
1408
1409
		$taxes = $purchlogitem->extrainfo->wpec_taxes_total;
1410
		if ( ! $numeric ) {
1411
			$taxes = wpsc_currency_display( $taxes, array( 'display_as_html' => false ) );
1412
		}
1413
1414
		return $taxes;
1415
	}
1416
1417
	public function total_price() {
1418
		global $purchlogitem;
1419
1420
		$total = $purchlogitem->totalAmount - $this->discount( true ) + $this->shipping( true ) + $this->taxes( true );
1421
		return wpsc_currency_display( $total, array( 'display_as_html' => false ) );
1422
	}
1423
1424
}
1425