Passed
Pull Request — master (#116)
by
unknown
03:57
created

WPInv_Subscription::complete()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 0
dl 0
loc 20
rs 9.4285
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
202
		return $this->parent_payment_id;
203
204
	}
205
206
	/**
207
	 * Retrieve renewal payments for a subscription
208
	 *
209
	 * @since  1.0.0
210
	 * @return array
211
	 */
212
	public function get_child_payments() {
213
214
		$payments = get_posts( array(
215
			'post_parent'    => (int) $this->parent_payment_id,
216
			'posts_per_page' => '999',
217
			'post_status'    => array( 'publish', 'wpi-processing', 'wpi-renewal' ),
218
			'post_type'      => 'wpi_invoice'
219
		) );
220
221
		return $payments;
222
223
	}
224
225
	/**
226
	 * Counts the number of payments made to the subscription
227
	 *
228
	 * @since  2.4
229
	 * @return int
230
	 */
231
	public function get_total_payments() {
232
233
		if('pending' != $this->status){
234
            return count( $this->get_child_payments() ) + 1;
235
        } else {
236
            return count($this->get_child_payments());
237
        }
238
239
	}
240
241
	/**
242
	 * Returns the number of times the subscription has been billed
243
	 *
244
	 * @since  2.6
245
	 * @return int
246
	 */
247
	public function get_times_billed() {
248
249
		$times_billed = $this->get_total_payments();
250
251
		if( ! empty( $this->trial_period ) ) {
252
            if('pending' != $this->status){
253
                $times_billed = 0;
254
            } else {
255
                $times_billed -= 1;
256
            }
257
		}
258
259
		return $times_billed;
260
261
	}
262
263
    /**
264
     * Records a new payment on the subscription
265
     *
266
     * @since  2.4
267
     * @param  array $args Array of values for the payment, including amount and transaction ID
268
     * @return bool
269
     */
270
    public function add_payment( $args = array() ) {
271
272
        $args = wp_parse_args( $args, array(
273
            'amount'         => '',
274
            'transaction_id' => '',
275
            'gateway'        => ''
276
        ) );
277
278
        if ( $this->payment_exists( $args['transaction_id'] ) ) {
279
            return false;
280
        }
281
282
        if(!$this->parent_payment_id){
283
            return false;
284
        }
285
286
        $invoice = new WPInv_Invoice($this->parent_payment_id);
0 ignored issues
show
Documentation introduced by
$this->parent_payment_id is of type integer, 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...
287
        $invoice->ID = $invoice->title = $invoice->number ='';
0 ignored issues
show
Documentation Bug introduced by
The property $ID was declared of type integer, but $invoice->title = $invoice->number = '' is of type string. 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...
288
        $invoice->parent_invoice = $this->parent_payment_id;
289
        $invoice->save();
290
        update_post_meta($invoice->ID, '_wpinv_transaction_id', $args['transaction_id']);
291
        update_post_meta($invoice->ID, '_wpinv_gateway', $args['gateway']);
292
293
        do_action( 'wpinv_recurring_add_subscription_payment', $invoice, $this );
294
        do_action( 'wpinv_recurring_record_payment', $invoice->ID, $this->parent_payment_id, $args['amount'], $args['transaction_id'] );
295
296
        return $invoice->ID;
297
    }
298
299
	/**
300
	 * Retrieves the transaction ID from the subscription
301
	 *
302
	 * @since  1.0.0
303
	 * @return bool
304
	 */
305
	public function get_transaction_id() {
306
307
		if( empty( $this->transaction_id ) ) {
308
309
			$txn_id = wpinv_get_payment_transaction_id( $this->parent_payment_id );
310
311
			if( ! empty( $txn_id ) && (int) $this->parent_payment_id !== (int) $txn_id ) {
312
				$this->set_transaction_id( $txn_id );
313
			}
314
315
		}
316
317
		return $this->transaction_id;
318
319
	}
320
321
	/**
322
	 * Stores the transaction ID for the subscription purchase
323
	 *
324
	 * @since  1.0.0.4
325
	 * @return bool
326
	 */
327
	public function set_transaction_id( $txn_id = '' ) {
328
		$this->update( array( 'transaction_id' => $txn_id ) );
329
		$this->transaction_id = $txn_id;
330
	}
331
332
	/**
333
	 * Renews a subscription
334
	 *
335
	 * @since  1.0.0
336
	 * @return bool
337
	 */
338
	public function renew() {
339
340
		$expires = $this->get_expiration_time();
341
342
343
		// Determine what date to use as the start for the new expiration calculation
344
		if( $expires > current_time( 'timestamp' ) && $this->is_active() ) {
345
346
			$base_date  = $expires;
347
348
		} else {
349
350
			$base_date  = current_time( 'timestamp' );
351
352
		}
353
354
		$last_day = cal_days_in_month( CAL_GREGORIAN, date( 'n', $base_date ), date( 'Y', $base_date ) );
355
356
357
		$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...
358
		$expiration = date( 'Y-m-d H:i:s', strtotime( '+' . $frequency . ' ' . $this->period  . ' 23:59:59', $base_date ) );
359
360
		if( date( 'j', $base_date ) == $last_day && 'day' != $this->period ) {
361
			$expiration = date( 'Y-m-d H:i:s', strtotime( $expiration . ' +2 days' ) );
362
		}
363
364
		$expiration  = apply_filters( 'wpinv_subscription_renewal_expiration', $expiration, $this->id, $this );
365
366
		do_action( 'wpinv_subscription_pre_renew', $this->id, $expiration, $this );
367
368
		$this->status = 'active';
369
		$times_billed = $this->get_times_billed();
370
371
		// Complete subscription if applicable
372
		if ( $this->bill_times > 0 && $times_billed >= $this->bill_times ) {
373
			$this->complete();
374
			$this->status = 'completed';
375
		}
376
377
		$args = array(
378
			'expiration' => $expiration,
379
			'status'     => $this->status,
380
		);
381
382
        $this->subs_db->update( $this->id, $args );
383
384
		do_action( 'wpinv_subscription_post_renew', $this->id, $expiration, $this );
385
		do_action( 'wpinv_recurring_set_subscription_status', $this->id, $this->status, $this );
386
387
	}
388
389
	/**
390
	 * Marks a subscription as completed
391
	 *
392
	 * Subscription is completed when the number of payments matches the billing_times field
393
	 *
394
	 * @since  1.0.0
395
	 * @return void
396
	 */
397
	public function complete() {
398
399
		// Only mark a subscription as complete if it's not already cancelled.
400
		if ( 'cancelled' === $this->status ) {
401
			return;
402
		}
403
404
		$args = array(
405
			'status' => 'completed'
406
		);
407
408
		if( $this->subs_db->update( $this->id, $args ) ) {
409
410
			$this->status = 'completed';
411
412
			do_action( 'wpinv_subscription_completed', $this->id, $this );
413
414
		}
415
416
	}
417
418
	/**
419
	 * Marks a subscription as expired
420
	 *
421
	 * Subscription is completed when the billing times is reached
422
	 *
423
	 * @since  1.0.0
424
	 * @param  $check_expiration bool True if expiration date should be checked with merchant processor before expiring
425
	 * @return void
426
	 */
427
	public function expire( $check_expiration = false ) {
428
429
		$expiration = $this->expiration;
430
431
		if( $check_expiration ) {
432
433
			// check_expiration() updates $this->expiration so compare to $expiration above
434
435
			if( $expiration < $this->get_expiration() && current_time( 'timestamp' ) < $this->get_expiration_time() ) {
436
437
				return false; // Do not mark as expired since real expiration date is in the future
438
			}
439
440
		}
441
442
		$args = array(
443
			'status' => 'expired'
444
		);
445
446
		if( $this->subs_db->update( $this->id, $args ) ) {
447
448
			$this->status = 'expired';
449
450
			do_action( 'wpinv_subscription_expired', $this->id, $this );
451
452
		}
453
454
	}
455
456
	/**
457
	 * Marks a subscription as failing
458
	 *
459
	 * @since  2.4.2
460
	 * @return void
461
	 */
462
	public function failing() {
463
464
		$args = array(
465
			'status' => 'failing'
466
		);
467
468
		if( $this->subs_db->update( $this->id, $args ) ) {
469
470
			$this->status = 'failing';
471
472
			do_action( 'wpinv_subscription_failing', $this->id, $this );
473
474
475
		}
476
477
	}
478
479
	/**
480
	 * Marks a subscription as cancelled
481
	 *
482
	 * @since  1.0.0
483
	 * @return void
484
	 */
485
	public function cancel() {
486
487
		if( 'cancelled' === $this->status ) {
488
			return; // Already cancelled
489
		}
490
491
		$args = array(
492
			'status' => 'cancelled'
493
		);
494
495
		if( $this->subs_db->update( $this->id, $args ) ) {
496
497
            if( is_user_logged_in() ) {
498
499
                $userdata = get_userdata( get_current_user_id() );
500
                $user     = $userdata->display_name;
501
502
            } else {
503
504
                $user = __( 'gateway', 'invoicing' );
505
506
            }
507
508
            $note = sprintf( __( 'Subscription for Invoice #%d cancelled by %s', 'invoicing' ), $this->parent_payment_id, $user );
509
            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...
510
511
		    $this->status = 'cancelled';
512
513
			do_action( 'wpinv_subscription_cancelled', $this->id, $this );
514
515
516
		}
517
518
	}
519
520
	/**
521
	 * Determines if subscription can be cancelled
522
	 *
523
	 * This method is filtered by payment gateways in order to return true on subscriptions
524
	 * that can be cancelled with a profile ID through the merchant processor
525
	 *
526
	 * @since  1.0.0
527
	 * @return bool
528
	 */
529
	public function can_cancel() {
530
        $ret = false;
531
	    if( $this->gateway === 'manual' || in_array( $this->status, $this->get_cancellable_statuses() ) ) {
532
            $ret = true;
533
        }
534
		return apply_filters( 'wpinv_subscription_can_cancel', $ret, $this );
535
	}
536
537
    /**
538
     * Returns an array of subscription statuses that can be cancelled
539
     *
540
     * @access      public
541
     * @since       1.0.0
542
     * @return      array
543
     */
544
    public function get_cancellable_statuses() {
545
        return apply_filters( 'wpinv_recurring_cancellable_statuses', array( 'active', 'trialling', 'failing' ) );
546
    }
547
548
	/**
549
	 * Retrieves the URL to cancel subscription
550
	 *
551
	 * @since  1.0.0
552
	 * @return string
553
	 */
554
	public function get_cancel_url() {
555
556
		$url = wp_nonce_url( add_query_arg( array( 'wpinv_action' => 'cancel_subscription', 'sub_id' => $this->id ) ), 'wpinv-recurring-cancel' );
557
558
		return apply_filters( 'wpinv_subscription_cancel_url', $url, $this );
559
	}
560
561
	/**
562
	 * Determines if subscription can be manually renewed
563
	 *
564
	 * This method is filtered by payment gateways in order to return true on subscriptions
565
	 * that can be renewed manually
566
	 *
567
	 * @since  2.5
568
	 * @return bool
569
	 */
570
	public function can_renew() {
571
572
		return apply_filters( 'wpinv_subscription_can_renew', true, $this );
573
	}
574
575
	/**
576
	 * Retrieves the URL to renew a subscription
577
	 *
578
	 * @since  2.5
579
	 * @return string
580
	 */
581
	public function get_renew_url() {
582
583
		$url = wp_nonce_url( add_query_arg( array( 'wpinv_action' => 'renew_subscription', 'sub_id' => $this->id ) ), 'wpinv-recurring-renew' );
584
585
		return apply_filters( 'wpinv_subscription_renew_url', $url, $this );
586
	}
587
588
	/**
589
	 * Determines if subscription can have their payment method updated
590
	 *
591
	 * @since  1.0.0
592
	 * @return bool
593
	 */
594
	public function can_update() {
595
		return apply_filters( 'wpinv_subscription_can_update', false, $this );
596
	}
597
598
	/**
599
	 * Retrieves the URL to update subscription
600
	 *
601
	 * @since  1.0.0
602
	 * @return void
603
	 */
604
	public function get_update_url() {
605
606
		$url = add_query_arg( array( 'action' => 'update', 'subscription_id' => $this->id ) );
607
608
		return apply_filters( 'wpinv_subscription_update_url', $url, $this );
609
	}
610
611
	/**
612
	 * Determines if subscription is active
613
	 *
614
	 * @since  1.0.0
615
	 * @return void
616
	 */
617
	public function is_active() {
618
619
		$ret = false;
620
621
		if( ! $this->is_expired() && ( $this->status == 'active' || $this->status == 'cancelled' || $this->status == 'trialling' ) ) {
622
			$ret = true;
623
		}
624
625
		return apply_filters( 'wpinv_subscription_is_active', $ret, $this->id, $this );
626
627
	}
628
629
	/**
630
	 * Determines if subscription is expired
631
	 *
632
	 * @since  1.0.0
633
	 * @return void
634
	 */
635
	public function is_expired() {
636
637
		$ret = false;
638
639
		if ( $this->status == 'expired' ) {
640
641
			$ret = true;
642
643
		} elseif( 'active' === $this->status || 'cancelled' === $this->status || $this->status == 'trialling'  ) {
644
645
			$ret        = false;
646
			$expiration = $this->get_expiration_time();
647
648
			if( $expiration && strtotime( 'NOW', current_time( 'timestamp' ) ) > $expiration ) {
649
				$ret = true;
650
651
				if ( 'active' === $this->status || $this->status == 'trialling'  ) {
652
					$this->expire();
653
				}
654
			}
655
656
		}
657
658
		return apply_filters( 'wpinv_subscription_is_expired', $ret, $this->id, $this );
659
660
	}
661
662
	/**
663
	 * Retrieves the expiration date
664
	 *
665
	 * @since  1.0.0
666
	 * @return string
667
	 */
668
	public function get_expiration() {
669
		return $this->expiration;
670
	}
671
672
	/**
673
	 * Retrieves the expiration date in a timestamp
674
	 *
675
	 * @since  1.0.0
676
	 * @return int
677
	 */
678
	public function get_expiration_time() {
679
		return strtotime( $this->expiration, current_time( 'timestamp' ) );
680
	}
681
682
	/**
683
	 * Retrieves the subscription status
684
	 *
685
	 * @since  1.0.0
686
	 * @return int
687
	 */
688
	public function get_status() {
689
690
		// Monitor for page load delays on pages with large subscription lists (IE: Subscriptions table in admin)
691
		$this->is_expired();
692
		return $this->status;
693
	}
694
695
	/**
696
	 * Retrieves the subscription status label
697
	 *
698
	 * @since  1.0.0
699
	 * @return int
700
	 */
701
	public function get_status_label() {
702
703
		switch( $this->get_status() ) {
704
			case 'active' :
705
				$status = __( 'Active', 'invoicing' );
706
				break;
707
708
			case 'cancelled' :
709
				$status = __( 'Cancelled', 'invoicing' );
710
				break;
711
712
			case 'expired' :
713
				$status = __( 'Expired', 'invoicing' );
714
				break;
715
716
			case 'pending' :
717
				$status = __( 'Pending', 'invoicing' );
718
				break;
719
720
			case 'failing' :
721
				$status = __( 'Failing', 'invoicing' );
722
				break;
723
724
			case 'trialling' :
725
				$status = __( 'Trialling', 'invoicing' );
726
				break;
727
728
			case 'completed' :
729
				$status = __( 'Completed', 'invoicing' );
730
				break;
731
732
			default:
733
				$status = ucfirst( $this->get_status() );
734
				break;
735
		}
736
737
		return $status;
738
	}
739
740
    /**
741
     * Retrieves the subscription status label
742
     *
743
     * @since  1.0.0
744
     * @return int
745
     */
746
    public function get_status_label_html() {
747
748
        switch( $get_status = $this->get_status() ) {
749
            case 'active' :
750
                $status = __( 'Active', 'invoicing' );
751
                $class = 'label-info';
752
                break;
753
754
            case 'cancelled' :
755
                $status = __( 'Cancelled', 'invoicing' );
756
                $class = 'label-danger';
757
                break;
758
759
            case 'expired' :
760
                $status = __( 'Expired', 'invoicing' );
761
                $class = 'label-default';
762
                break;
763
764
            case 'pending' :
765
                $status = __( 'Pending', 'invoicing' );
766
                $class = 'label-primary';
767
                break;
768
769
            case 'failing' :
770
                $status = __( 'Failing', 'invoicing' );
771
                $class = 'label-danger';
772
                break;
773
774
            case 'trialling' :
775
                $status = __( 'Trialling', 'invoicing' );
776
                $class = 'label-info';
777
                break;
778
779
            case 'completed' :
780
                $status = __( 'Completed', 'invoicing' );
781
                $class = 'label-success';
782
                break;
783
784
            default:
785
                $status = ucfirst( $this->get_status() );
786
                $class = 'label-default';
787
                break;
788
        }
789
790
        $label = '<span class="sub-status label label-sub-' . $get_status . ' ' . $class . '">' . $status . '</span>';
791
792
        return apply_filters( 'wpinv_subscription_status_label_html', $label, $get_status, $status );
793
    }
794
795
    /**
796
     * Determines if a payment exists with the specified transaction ID
797
     *
798
     * @since  2.4
799
     * @param  string $txn_id The transaction ID from the merchant processor
800
     * @return bool
801
     */
802
    public function payment_exists( $txn_id = '' ) {
803
        global $wpdb;
804
805
        if ( empty( $txn_id ) ) {
806
            return false;
807
        }
808
809
        $txn_id = esc_sql( $txn_id );
810
811
        $purchase = $wpdb->get_var( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wpinv_transaction_id' AND meta_value = '{$txn_id}' LIMIT 1" );
812
813
        if ( $purchase != null ) {
814
            return true;
815
        }
816
817
        return false;
818
    }
819
820
}
821