Passed
Pull Request — master (#126)
by Kiran
04:13
created

WPInv_Subscription::is_expired()   D

Complexity

Conditions 9
Paths 5

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 12
nc 5
nop 0
dl 0
loc 26
rs 4.909
c 0
b 0
f 0
1
<?php
2
3
// Exit if accessed directly
4
if ( ! defined( 'ABSPATH' ) ) {
5
	exit;
6
}
7
8
9
/**
10
 * The Subscription Class
11
 *
12
 * @since  1.0.0
13
 */
14
class WPInv_Subscription {
15
16
	private $subs_db;
17
18
	public $id                = 0;
19
	public $customer_id       = 0;
20
	public $period            = '';
21
	public $initial_amount    = '';
22
	public $recurring_amount  = '';
23
	public $bill_times        = 0;
24
	public $transaction_id    = '';
25
	public $parent_payment_id = 0;
26
	public $product_id        = 0;
27
	public $created           = '0000-00-00 00:00:00';
28
	public $expiration        = '0000-00-00 00:00:00';
29
	public $trial_period      = '';
30
	public $status            = 'pending';
31
	public $profile_id        = '';
32
	public $gateway           = '';
33
	public $customer;
34
35
	/**
36
	 * Get us started
37
	 *
38
	 * @since  1.0.0
39
	 * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
40
	 */
41
	function __construct( $_id_or_object = 0, $_by_profile_id = false ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
42
43
		$this->subs_db = new WPInv_Subscriptions_DB;
44
45
		if( $_by_profile_id ) {
46
47
			$_sub = $this->subs_db->get_by( 'profile_id', $_id_or_object );
48
49
			if( empty( $_sub ) ) {
50
				return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
51
			}
52
53
			$_id_or_object = $_sub;
54
55
		}
56
57
		return $this->setup_subscription( $_id_or_object );
0 ignored issues
show
Bug introduced by
It seems like $_id_or_object defined by $_sub on line 53 can also be of type object; however, WPInv_Subscription::setup_subscription() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
58
	}
59
60
	/**
61
	 * Setup the subscription object
62
	 *
63
	 * @since  1.0.0
64
	 * @return void
65
	 */
66
	private function setup_subscription( $id_or_object = 0 ) {
67
68
		if( empty( $id_or_object ) ) {
69
			return false;
70
		}
71
72
		if( is_numeric( $id_or_object ) ) {
73
74
			$sub = $this->subs_db->get( $id_or_object );
75
76
		} elseif( is_object( $id_or_object ) ) {
77
78
			$sub = $id_or_object;
79
80
		}
81
82
		if( empty( $sub ) ) {
83
			return false;
84
		}
85
86
		foreach( $sub as $key => $value ) {
87
			$this->$key = $value;
88
		}
89
90
		$this->customer = get_userdata( $this->customer_id );
91
		$this->gateway  = wpinv_get_payment_gateway( $this->parent_payment_id );
92
93
		do_action( 'wpinv_recurring_setup_subscription', $this );
94
95
		return $this;
96
	}
97
98
	/**
99
	 * Magic __get function to dispatch a call to retrieve a private property
100
	 *
101
	 * @since 1.0.0
102
	 */
103 View Code Duplication
	public function __get( $key ) {
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...
104
105
		if( method_exists( $this, 'get_' . $key ) ) {
106
107
			return call_user_func( array( $this, 'get_' . $key ) );
108
109
		} else {
110
111
			return new WP_Error( 'wpinv-subscription-invalid-property', sprintf( __( 'Can\'t get property %s', 'invoicing' ), $key ) );
112
113
		}
114
115
	}
116
117
	/**
118
	 * Creates a subscription
119
	 *
120
	 * @since  1.0.0
121
	 * @param  array  $data Array of attributes for a subscription
122
	 * @return mixed  false if data isn't passed and class not instantiated for creation
123
	 */
124
	public function create( $data = array() ) {
125
126
		if ( $this->id != 0 ) {
127
			return false;
128
		}
129
130
		$defaults = array(
131
			'customer_id'       => 0,
132
			'frequency'         => '',
133
			'period'            => '',
134
			'initial_amount'    => '',
135
			'recurring_amount'  => '',
136
			'bill_times'        => 0,
137
			'parent_payment_id' => 0,
138
			'product_id'        => 0,
139
			'created'           => '',
140
			'expiration'        => '',
141
			'status'            => '',
142
			'profile_id'        => '',
143
		);
144
145
		$args = wp_parse_args( $data, $defaults );
146
147
		if( $args['expiration'] && strtotime( 'NOW', current_time( 'timestamp' ) ) > strtotime( $args['expiration'], current_time( 'timestamp' ) ) ) {
148
149
			if( 'active' == $args['status'] || 'trialling' == $args['status'] ) {
150
151
				// Force an active subscription to expired if expiration date is in the past
152
				$args['status'] = 'expired';
153
154
			}
155
		}
156
157
		do_action( 'wpinv_subscription_pre_create', $args );
158
159
		$id = $this->subs_db->insert( $args, 'subscription' );
160
161
		do_action( 'wpinv_subscription_post_create', $id, $args );
162
163
		return $this->setup_subscription( $id );
164
165
	}
166
167
	/**
168
	 * Updates a subscription
169
	 *
170
	 * @since  1.0.0
171
	 * @param  array $args Array of fields to update
172
	 * @return bool
173
	 */
174
	public function update( $args = array() ) {
175
176
		$ret = $this->subs_db->update( $this->id, $args );
177
178
		do_action( 'wpinv_recurring_update_subscription', $this->id, $args, $this );
179
180
		return $ret;
181
182
	}
183
184
	/**
185
	 * Delete the subscription
186
	 *
187
	 * @since  1.0.0
188
	 * @return bool
189
	 */
190
	public function delete() {
191
		return $this->subs_db->delete( $this->id );
192
	}
193
194
    /**
195
     * Retrieves the parent payment ID
196
     *
197
     * @since  1.0.0
198
     * @return int
199
     */
200
    public function get_original_payment_id() {
201
        return $this->parent_payment_id;
202
    }
203
204
    /**
205
     * Retrieve renewal payments for a subscription
206
     *
207
     * @since  1.0.0
208
     * @return array
209
     */
210
    public function get_child_payments() {
211
        $payments = get_posts( array(
212
            'post_parent'    => (int) $this->parent_payment_id,
213
            'posts_per_page' => '999',
214
            'post_status'    => array( 'publish', 'wpi-processing', 'wpi-renewal' ),
215
            'orderby'           => 'ID',
216
            'order'             => 'DESC',
217
            'post_type'      => 'wpi_invoice'
218
        ) );
219
220
        return $payments;
221
    }
222
223
    /**
224
     * Counts the number of payments made to the subscription
225
     *
226
     * @since  2.4
227
     * @return int
228
     */
229
    public function get_total_payments() {
230
        $child_payments = $this->get_child_payments();
231
        $total_payments = !empty( $child_payments ) ? count( $child_payments ) : 0;
232
233
        if ( 'pending' != $this->status ) {
234
                $total_payments++;
235
        }
236
237
        return $total_payments;
238
    }
239
240
    /**
241
     * Returns the number of times the subscription has been billed
242
     *
243
     * @since  1.0.2
244
     * @return int
245
     */
246
    public function get_times_billed() {
247
        $times_billed = (int)$this->get_total_payments();
248
249
        if ( ! empty( $this->trial_period ) && $times_billed > 0 ) {
250
            $times_billed--;
251
        }
252
253
        return $times_billed;
254
    }
255
256
    /**
257
     * Records a new payment on the subscription
258
     *
259
     * @since  2.4
260
     * @param  array $args Array of values for the payment, including amount and transaction ID
261
     * @return bool
262
     */
263
    public function add_payment( $args = array() ) {
264
        if ( ! $this->parent_payment_id ) {
265
            return false;
266
        }
267
268
        $args = wp_parse_args( $args, array(
269
            'amount'         => '',
270
            'transaction_id' => '',
271
            'gateway'        => ''
272
        ) );
273
        
274
        if ( empty( $args['transaction_id'] ) || $this->payment_exists( $args['transaction_id'] ) ) {
275
            return false;
276
        }
277
        
278
        $parent_invoice = wpinv_get_invoice( $this->parent_payment_id );
279
        if ( empty( $parent_invoice->ID ) ) {
280
            return false;
281
        }
282
283
        $invoice = new WPInv_Invoice();
284
        $invoice->set( 'post_type', 'wpi_invoice' );
285
        $invoice->set( 'parent_invoice', $this->parent_payment_id );
286
        $invoice->set( 'currency', $parent_invoice->get_currency() );
287
        $invoice->set( 'transaction_id', $args['transaction_id'] );
288
        $invoice->set( 'key', $parent_invoice->generate_key() );
289
        $invoice->set( 'ip', $parent_invoice->ip );
290
        $invoice->set( 'user_id', $parent_invoice->get_user_id() );
291
        $invoice->set( 'first_name', $parent_invoice->get_first_name() );
292
        $invoice->set( 'last_name', $parent_invoice->get_last_name() );
293
        $invoice->set( 'phone', $parent_invoice->phone );
294
        $invoice->set( 'address', $parent_invoice->address );
295
        $invoice->set( 'city', $parent_invoice->city );
296
        $invoice->set( 'country', $parent_invoice->country );
297
        $invoice->set( 'state', $parent_invoice->state );
298
        $invoice->set( 'zip', $parent_invoice->zip );
299
        $invoice->set( 'company', $parent_invoice->company );
300
        $invoice->set( 'vat_number', $parent_invoice->vat_number );
301
        $invoice->set( 'vat_rate', $parent_invoice->vat_rate );
302
        $invoice->set( 'adddress_confirmed', $parent_invoice->adddress_confirmed );
303
304
        if ( empty( $args['gateway'] ) ) {
305
            $invoice->set( 'gateway', $parent_invoice->get_gateway() );
306
        } else {
307
            $invoice->set( 'gateway', $args['gateway'] );
308
        }
309
        
310
        $recurring_details = $parent_invoice->get_recurring_details();
311
312
        // increase the earnings for each item in the subscription
313
        $items = $recurring_details['cart_details'];
314
        
315
        if ( $items ) {        
316
            $add_items      = array();
317
            $cart_details   = array();
318
            
319
            foreach ( $items as $item ) {
320
                $add_item             = array();
321
                $add_item['id']       = $item['id'];
322
                $add_item['quantity'] = $item['quantity'];
323
                
324
                $add_items[]    = $add_item;
325
                $cart_details[] = $item;
326
                break;
327
            }
328
            
329
            $invoice->set( 'items', $add_items );
330
            $invoice->cart_details = $cart_details;
331
        }
332
        
333
        $total = $args['amount'];
334
        
335
        $subtotal           = $recurring_details['subtotal'];
336
        $tax                = $recurring_details['tax'];
337
        $discount           = $recurring_details['discount'];
338
        
339
        if ( $discount > 0 ) {
340
            $invoice->set( 'discount_code', $parent_invoice->discount_code );
341
        }
342
        
343
        $invoice->subtotal = wpinv_round_amount( $subtotal );
344
        $invoice->tax      = wpinv_round_amount( $tax );
345
        $invoice->discount = wpinv_round_amount( $discount );
346
        $invoice->total    = wpinv_round_amount( $total );
347
348
        $invoice  = apply_filters( 'wpinv_subscription_add_payment_save', $invoice, $this, $args );
349
350
        $invoice->save();
351
        $invoice->update_meta( '_wpinv_subscription_id', $this->id );
352
        
353
        if ( !empty( $invoice->ID ) ) {
354
            wpinv_update_payment_status( $invoice->ID, 'publish' );
355
            sleep(1);
356
            wpinv_update_payment_status( $invoice->ID, 'wpi-renewal' );
357
            
358
            $invoice = wpinv_get_invoice( $invoice->ID );
359
360
            do_action( 'wpinv_recurring_add_subscription_payment', $invoice, $this );
361
            do_action( 'wpinv_recurring_record_payment', $invoice->ID, $this->parent_payment_id, $args['amount'], $args['transaction_id'] );
362
            
363
            return $invoice->ID;
364
        }
365
366
        return false;
367
    }
368
369
	/**
370
	 * Retrieves the transaction ID from the subscription
371
	 *
372
	 * @since  1.0.0
373
	 * @return bool
374
	 */
375
	public function get_transaction_id() {
376
377
		if( empty( $this->transaction_id ) ) {
378
379
			$txn_id = wpinv_get_payment_transaction_id( $this->parent_payment_id );
380
381
			if( ! empty( $txn_id ) && (int) $this->parent_payment_id !== (int) $txn_id ) {
382
				$this->set_transaction_id( $txn_id );
383
			}
384
385
		}
386
387
		return $this->transaction_id;
388
389
	}
390
391
	/**
392
	 * Stores the transaction ID for the subscription purchase
393
	 *
394
	 * @since  1.0.0.4
395
	 * @return bool
396
	 */
397
	public function set_transaction_id( $txn_id = '' ) {
398
		$this->update( array( 'transaction_id' => $txn_id ) );
399
		$this->transaction_id = $txn_id;
400
	}
401
402
	/**
403
	 * Renews a subscription
404
	 *
405
	 * @since  1.0.0
406
	 * @return bool
407
	 */
408
	public function renew() {
409
410
		$expires = $this->get_expiration_time();
411
412
413
		// Determine what date to use as the start for the new expiration calculation
414
		if( $expires > current_time( 'timestamp' ) && $this->is_active() ) {
415
416
			$base_date  = $expires;
417
418
		} else {
419
420
			$base_date  = current_time( 'timestamp' );
421
422
		}
423
424
		$last_day = wpinv_cal_days_in_month( CAL_GREGORIAN, date( 'n', $base_date ), date( 'Y', $base_date ) );
425
426
427
		$frequency = isset($this->frequency) ? $this->frequency : 1;
0 ignored issues
show
Documentation introduced by
The property frequency does not exist on object<WPInv_Subscription>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
428
		$expiration = date( 'Y-m-d H:i:s', strtotime( '+' . $frequency . ' ' . $this->period  . ' 23:59:59', $base_date ) );
429
430
		if( date( 'j', $base_date ) == $last_day && 'day' != $this->period ) {
431
			$expiration = date( 'Y-m-d H:i:s', strtotime( $expiration . ' +2 days' ) );
432
		}
433
434
		$expiration  = apply_filters( 'wpinv_subscription_renewal_expiration', $expiration, $this->id, $this );
435
436
		do_action( 'wpinv_subscription_pre_renew', $this->id, $expiration, $this );
437
438
		$this->status = 'active';
439
		$times_billed = $this->get_times_billed();
440
441
		// Complete subscription if applicable
442
		if ( $this->bill_times > 0 && $times_billed >= $this->bill_times ) {
443
			$this->complete();
444
			$this->status = 'completed';
445
		}
446
447
		$args = array(
448
			'expiration' => $expiration,
449
			'status'     => $this->status,
450
		);
451
452
        $this->subs_db->update( $this->id, $args );
453
454
		do_action( 'wpinv_subscription_post_renew', $this->id, $expiration, $this );
455
		do_action( 'wpinv_recurring_set_subscription_status', $this->id, $this->status, $this );
456
457
	}
458
459
	/**
460
	 * Marks a subscription as completed
461
	 *
462
	 * Subscription is completed when the number of payments matches the billing_times field
463
	 *
464
	 * @since  1.0.0
465
	 * @return void
466
	 */
467
	public function complete() {
468
469
		// Only mark a subscription as complete if it's not already cancelled.
470
		if ( 'cancelled' === $this->status ) {
471
			return;
472
		}
473
474
		$args = array(
475
			'status' => 'completed'
476
		);
477
478
		if( $this->subs_db->update( $this->id, $args ) ) {
479
480
			$this->status = 'completed';
481
482
			do_action( 'wpinv_subscription_completed', $this->id, $this );
483
484
		}
485
486
	}
487
488
	/**
489
	 * Marks a subscription as expired
490
	 *
491
	 * Subscription is completed when the billing times is reached
492
	 *
493
	 * @since  1.0.0
494
	 * @param  $check_expiration bool True if expiration date should be checked with merchant processor before expiring
495
	 * @return void
496
	 */
497
	public function expire( $check_expiration = false ) {
498
499
		$expiration = $this->expiration;
500
501
		if( $check_expiration ) {
502
503
			// check_expiration() updates $this->expiration so compare to $expiration above
504
505
			if( $expiration < $this->get_expiration() && current_time( 'timestamp' ) < $this->get_expiration_time() ) {
506
507
				return false; // Do not mark as expired since real expiration date is in the future
508
			}
509
510
		}
511
512
		$args = array(
513
			'status' => 'expired'
514
		);
515
516
		if( $this->subs_db->update( $this->id, $args ) ) {
517
518
			$this->status = 'expired';
519
520
			do_action( 'wpinv_subscription_expired', $this->id, $this );
521
522
		}
523
524
	}
525
526
	/**
527
	 * Marks a subscription as failing
528
	 *
529
	 * @since  2.4.2
530
	 * @return void
531
	 */
532
	public function failing() {
533
534
		$args = array(
535
			'status' => 'failing'
536
		);
537
538
		if( $this->subs_db->update( $this->id, $args ) ) {
539
540
			$this->status = 'failing';
541
542
			do_action( 'wpinv_subscription_failing', $this->id, $this );
543
544
545
		}
546
547
	}
548
549
    /**
550
     * Marks a subscription as cancelled
551
     *
552
     * @since  1.0.0
553
     * @return void
554
     */
555
    public function cancel() {
556
        if ( 'cancelled' === $this->status ) {
557
            return; // Already cancelled
558
        }
559
560
        $args = array(
561
            'status' => 'cancelled'
562
        );
563
564
        if ( $this->subs_db->update( $this->id, $args ) ) {
565
            if ( is_user_logged_in() ) {
566
                $userdata = get_userdata( get_current_user_id() );
567
                $user     = $userdata->display_name;
568
            } else {
569
                $user = __( 'gateway', 'invoicing' );
570
            }
571
572
            $note = sprintf( __( 'Subscription has been cancelled by %s', 'invoicing' ), $this->parent_payment_id, $user );
573
            wpinv_insert_payment_note( $this->parent_payment_id, $note, '', '', true );
0 ignored issues
show
Documentation introduced by
'' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
574
575
            $this->status = 'cancelled';
576
577
            do_action( 'wpinv_subscription_cancelled', $this->id, $this );
578
        }
579
    }
580
581
	/**
582
	 * Determines if subscription can be cancelled
583
	 *
584
	 * This method is filtered by payment gateways in order to return true on subscriptions
585
	 * that can be cancelled with a profile ID through the merchant processor
586
	 *
587
	 * @since  1.0.0
588
	 * @return bool
589
	 */
590
	public function can_cancel() {
591
        $ret = false;
592
	    if( $this->gateway === 'manual' || in_array( $this->status, $this->get_cancellable_statuses() ) ) {
593
            $ret = true;
594
        }
595
		return apply_filters( 'wpinv_subscription_can_cancel', $ret, $this );
596
	}
597
598
    /**
599
     * Returns an array of subscription statuses that can be cancelled
600
     *
601
     * @access      public
602
     * @since       1.0.0
603
     * @return      array
604
     */
605
    public function get_cancellable_statuses() {
606
        return apply_filters( 'wpinv_recurring_cancellable_statuses', array( 'active', 'trialling', 'failing' ) );
607
    }
608
609
	/**
610
	 * Retrieves the URL to cancel subscription
611
	 *
612
	 * @since  1.0.0
613
	 * @return string
614
	 */
615
	public function get_cancel_url() {
616
617
		$url = wp_nonce_url( add_query_arg( array( 'wpinv_action' => 'cancel_subscription', 'sub_id' => $this->id ) ), 'wpinv-recurring-cancel' );
618
619
		return apply_filters( 'wpinv_subscription_cancel_url', $url, $this );
620
	}
621
622
	/**
623
	 * Determines if subscription can be manually renewed
624
	 *
625
	 * This method is filtered by payment gateways in order to return true on subscriptions
626
	 * that can be renewed manually
627
	 *
628
	 * @since  2.5
629
	 * @return bool
630
	 */
631
	public function can_renew() {
632
633
		return apply_filters( 'wpinv_subscription_can_renew', true, $this );
634
	}
635
636
	/**
637
	 * Retrieves the URL to renew a subscription
638
	 *
639
	 * @since  2.5
640
	 * @return string
641
	 */
642
	public function get_renew_url() {
643
644
		$url = wp_nonce_url( add_query_arg( array( 'wpinv_action' => 'renew_subscription', 'sub_id' => $this->id ) ), 'wpinv-recurring-renew' );
645
646
		return apply_filters( 'wpinv_subscription_renew_url', $url, $this );
647
	}
648
649
	/**
650
	 * Determines if subscription can have their payment method updated
651
	 *
652
	 * @since  1.0.0
653
	 * @return bool
654
	 */
655
	public function can_update() {
656
		return apply_filters( 'wpinv_subscription_can_update', false, $this );
657
	}
658
659
	/**
660
	 * Retrieves the URL to update subscription
661
	 *
662
	 * @since  1.0.0
663
	 * @return void
664
	 */
665
	public function get_update_url() {
666
667
		$url = add_query_arg( array( 'action' => 'update', 'subscription_id' => $this->id ) );
668
669
		return apply_filters( 'wpinv_subscription_update_url', $url, $this );
670
	}
671
672
	/**
673
	 * Determines if subscription is active
674
	 *
675
	 * @since  1.0.0
676
	 * @return void
677
	 */
678
	public function is_active() {
679
680
		$ret = false;
681
682
		if( ! $this->is_expired() && ( $this->status == 'active' || $this->status == 'cancelled' || $this->status == 'trialling' ) ) {
683
			$ret = true;
684
		}
685
686
		return apply_filters( 'wpinv_subscription_is_active', $ret, $this->id, $this );
687
688
	}
689
690
	/**
691
	 * Determines if subscription is expired
692
	 *
693
	 * @since  1.0.0
694
	 * @return void
695
	 */
696
	public function is_expired() {
697
698
		$ret = false;
699
700
		if ( $this->status == 'expired' ) {
701
702
			$ret = true;
703
704
		} elseif( 'active' === $this->status || 'cancelled' === $this->status || $this->status == 'trialling'  ) {
705
706
			$ret        = false;
707
			$expiration = $this->get_expiration_time();
708
709
			if( $expiration && strtotime( 'NOW', current_time( 'timestamp' ) ) > $expiration ) {
710
				$ret = true;
711
712
				if ( 'active' === $this->status || $this->status == 'trialling'  ) {
713
					$this->expire();
714
				}
715
			}
716
717
		}
718
719
		return apply_filters( 'wpinv_subscription_is_expired', $ret, $this->id, $this );
720
721
	}
722
723
	/**
724
	 * Retrieves the expiration date
725
	 *
726
	 * @since  1.0.0
727
	 * @return string
728
	 */
729
	public function get_expiration() {
730
		return $this->expiration;
731
	}
732
733
	/**
734
	 * Retrieves the expiration date in a timestamp
735
	 *
736
	 * @since  1.0.0
737
	 * @return int
738
	 */
739
	public function get_expiration_time() {
740
		return strtotime( $this->expiration, current_time( 'timestamp' ) );
741
	}
742
743
	/**
744
	 * Retrieves the subscription status
745
	 *
746
	 * @since  1.0.0
747
	 * @return int
748
	 */
749
	public function get_status() {
750
751
		// Monitor for page load delays on pages with large subscription lists (IE: Subscriptions table in admin)
752
		$this->is_expired();
753
		return $this->status;
754
	}
755
756
	/**
757
	 * Retrieves the subscription status label
758
	 *
759
	 * @since  1.0.0
760
	 * @return int
761
	 */
762
	public function get_status_label() {
763
764
		switch( $this->get_status() ) {
765
			case 'active' :
766
				$status = __( 'Active', 'invoicing' );
767
				break;
768
769
			case 'cancelled' :
770
				$status = __( 'Cancelled', 'invoicing' );
771
				break;
772
773
			case 'expired' :
774
				$status = __( 'Expired', 'invoicing' );
775
				break;
776
777
			case 'pending' :
778
				$status = __( 'Pending', 'invoicing' );
779
				break;
780
781
			case 'failing' :
782
				$status = __( 'Failing', 'invoicing' );
783
				break;
784
785
			case 'trialling' :
786
				$status = __( 'Trialling', 'invoicing' );
787
				break;
788
789
			case 'completed' :
790
				$status = __( 'Completed', 'invoicing' );
791
				break;
792
793
			default:
794
				$status = ucfirst( $this->get_status() );
795
				break;
796
		}
797
798
		return $status;
799
	}
800
801
    /**
802
     * Retrieves the subscription status label
803
     *
804
     * @since  1.0.0
805
     * @return int
806
     */
807
    public function get_status_label_html() {
808
809
        switch( $get_status = $this->get_status() ) {
810
            case 'active' :
811
                $status = __( 'Active', 'invoicing' );
812
                $class = 'label-info';
813
                break;
814
815
            case 'cancelled' :
816
                $status = __( 'Cancelled', 'invoicing' );
817
                $class = 'label-danger';
818
                break;
819
820
            case 'expired' :
821
                $status = __( 'Expired', 'invoicing' );
822
                $class = 'label-default';
823
                break;
824
825
            case 'pending' :
826
                $status = __( 'Pending', 'invoicing' );
827
                $class = 'label-primary';
828
                break;
829
830
            case 'failing' :
831
                $status = __( 'Failing', 'invoicing' );
832
                $class = 'label-danger';
833
                break;
834
835
            case 'trialling' :
836
                $status = __( 'Trialling', 'invoicing' );
837
                $class = 'label-info';
838
                break;
839
840
            case 'completed' :
841
                $status = __( 'Completed', 'invoicing' );
842
                $class = 'label-success';
843
                break;
844
845
            default:
846
                $status = ucfirst( $this->get_status() );
847
                $class = 'label-default';
848
                break;
849
        }
850
851
        $label = '<span class="sub-status label label-sub-' . $get_status . ' ' . $class . '">' . $status . '</span>';
852
853
        return apply_filters( 'wpinv_subscription_status_label_html', $label, $get_status, $status );
854
    }
855
856
    /**
857
     * Determines if a payment exists with the specified transaction ID
858
     *
859
     * @since  2.4
860
     * @param  string $txn_id The transaction ID from the merchant processor
861
     * @return bool
862
     */
863
    public function payment_exists( $txn_id = '' ) {
864
        global $wpdb;
865
866
        if ( empty( $txn_id ) ) {
867
            return false;
868
        }
869
870
        $txn_id = esc_sql( $txn_id );
871
872
        $purchase = $wpdb->get_var( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wpinv_transaction_id' AND meta_value = '{$txn_id}' LIMIT 1" );
873
874
        if ( $purchase != null ) {
875
            return true;
876
        }
877
878
        return false;
879
    }
880
881
}
882