Passed
Pull Request — master (#116)
by
unknown
04:15
created

WPInv_Subscription::payment_exists()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 1
dl 0
loc 17
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
291
        do_action( 'wpinv_recurring_add_subscription_payment', $invoice, $this );
292
        do_action( 'wpinv_recurring_record_payment', $invoice->ID, $this->parent_payment_id, $args['amount'], $args['transaction_id'] );
293
294
        return $invoice->ID;
295
    }
296
297
	/**
298
	 * Retrieves the transaction ID from the subscription
299
	 *
300
	 * @since  1.0.0
301
	 * @return bool
302
	 */
303
	public function get_transaction_id() {
304
305
		if( empty( $this->transaction_id ) ) {
306
307
			$txn_id = wpinv_get_payment_transaction_id( $this->parent_payment_id );
308
309
			if( ! empty( $txn_id ) && (int) $this->parent_payment_id !== (int) $txn_id ) {
310
				$this->set_transaction_id( $txn_id );
311
			}
312
313
		}
314
315
		return $this->transaction_id;
316
317
	}
318
319
	/**
320
	 * Stores the transaction ID for the subscription purchase
321
	 *
322
	 * @since  1.0.0.4
323
	 * @return bool
324
	 */
325
	public function set_transaction_id( $txn_id = '' ) {
326
		$this->update( array( 'transaction_id' => $txn_id ) );
327
		$this->transaction_id = $txn_id;
328
	}
329
330
	/**
331
	 * Renews a subscription
332
	 *
333
	 * @since  1.0.0
334
	 * @return bool
335
	 */
336
	public function renew() {
337
338
		$expires = $this->get_expiration_time();
339
340
341
		// Determine what date to use as the start for the new expiration calculation
342
		if( $expires > current_time( 'timestamp' ) && $this->is_active() ) {
343
344
			$base_date  = $expires;
345
346
		} else {
347
348
			$base_date  = current_time( 'timestamp' );
349
350
		}
351
352
		$last_day = cal_days_in_month( CAL_GREGORIAN, date( 'n', $base_date ), date( 'Y', $base_date ) );
353
354
355
		$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...
356
		$expiration = date( 'Y-m-d H:i:s', strtotime( '+' . $frequency . ' ' . $this->period  . ' 23:59:59', $base_date ) );
357
358
		if( date( 'j', $base_date ) == $last_day && 'day' != $this->period ) {
359
			$expiration = date( 'Y-m-d H:i:s', strtotime( $expiration . ' +2 days' ) );
360
		}
361
362
		$expiration  = apply_filters( 'wpinv_subscription_renewal_expiration', $expiration, $this->id, $this );
363
364
		do_action( 'wpinv_subscription_pre_renew', $this->id, $expiration, $this );
365
366
		$this->status = 'active';
367
		$times_billed = $this->get_times_billed();
368
369
		// Complete subscription if applicable
370
		if ( $this->bill_times > 0 && $times_billed >= $this->bill_times ) {
371
			$this->complete();
372
			$this->status = 'completed';
373
		}
374
375
		$args = array(
376
			'expiration' => $expiration,
377
			'status'     => $this->status,
378
		);
379
380
        $this->subs_db->update( $this->id, $args );
381
382
		do_action( 'wpinv_subscription_post_renew', $this->id, $expiration, $this );
383
		do_action( 'wpinv_recurring_set_subscription_status', $this->id, $this->status, $this );
384
385
	}
386
387
	/**
388
	 * Marks a subscription as completed
389
	 *
390
	 * Subscription is completed when the number of payments matches the billing_times field
391
	 *
392
	 * @since  1.0.0
393
	 * @return void
394
	 */
395
	public function complete() {
396
397
		// Only mark a subscription as complete if it's not already cancelled.
398
		if ( 'cancelled' === $this->status ) {
399
			return;
400
		}
401
402
		$args = array(
403
			'status' => 'completed'
404
		);
405
406
		if( $this->subs_db->update( $this->id, $args ) ) {
407
408
			$this->status = 'completed';
409
410
			do_action( 'wpinv_subscription_completed', $this->id, $this );
411
412
		}
413
414
	}
415
416
	/**
417
	 * Marks a subscription as expired
418
	 *
419
	 * Subscription is completed when the billing times is reached
420
	 *
421
	 * @since  1.0.0
422
	 * @param  $check_expiration bool True if expiration date should be checked with merchant processor before expiring
423
	 * @return void
424
	 */
425
	public function expire( $check_expiration = false ) {
426
427
		$expiration = $this->expiration;
428
429
		if( $check_expiration && $this->check_expiration() ) {
0 ignored issues
show
Bug introduced by
The method check_expiration() does not seem to exist on object<WPInv_Subscription>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
430
431
			// check_expiration() updates $this->expiration so compare to $expiration above
432
433
			if( $expiration < $this->get_expiration() && current_time( 'timestamp' ) < $this->get_expiration_time() ) {
434
435
				return false; // Do not mark as expired since real expiration date is in the future
436
			}
437
438
		}
439
440
		$args = array(
441
			'status' => 'expired'
442
		);
443
444
		if( $this->subs_db->update( $this->id, $args ) ) {
445
446
			$this->status = 'expired';
447
448
			do_action( 'wpinv_subscription_expired', $this->id, $this );
449
450
		}
451
452
	}
453
454
	/**
455
	 * Marks a subscription as failing
456
	 *
457
	 * @since  2.4.2
458
	 * @return void
459
	 */
460
	public function failing() {
461
462
		$args = array(
463
			'status' => 'failing'
464
		);
465
466
		if( $this->subs_db->update( $this->id, $args ) ) {
467
468
			$this->status = 'failing';
469
470
			do_action( 'wpinv_subscription_failing', $this->id, $this );
471
472
473
		}
474
475
	}
476
477
	/**
478
	 * Marks a subscription as cancelled
479
	 *
480
	 * @since  1.0.0
481
	 * @return void
482
	 */
483
	public function cancel() {
484
485
		if( 'cancelled' === $this->status ) {
486
			return; // Already cancelled
487
		}
488
489
		$args = array(
490
			'status' => 'cancelled'
491
		);
492
493
		if( $this->subs_db->update( $this->id, $args ) ) {
494
495
            if( is_user_logged_in() ) {
496
497
                $userdata = get_userdata( get_current_user_id() );
498
                $user     = $userdata->display_name;
499
500
            } else {
501
502
                $user = __( 'gateway', 'invoicing' );
503
504
            }
505
506
            $note = sprintf( __( 'Subscription for Invoice #%d cancelled by %s', 'invoicing' ), $this->parent_payment_id, $user );
507
            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...
508
509
		    $this->status = 'cancelled';
510
511
			do_action( 'wpinv_subscription_cancelled', $this->id, $this );
512
513
514
		}
515
516
	}
517
518
	/**
519
	 * Determines if subscription can be cancelled
520
	 *
521
	 * This method is filtered by payment gateways in order to return true on subscriptions
522
	 * that can be cancelled with a profile ID through the merchant processor
523
	 *
524
	 * @since  1.0.0
525
	 * @return bool
526
	 */
527
	public function can_cancel() {
528
        $ret = false;
529
	    if( $this->gateway === 'manual' || in_array( $this->status, $this->get_cancellable_statuses() ) ) {
530
            $ret = true;
531
        }
532
		return apply_filters( 'wpinv_subscription_can_cancel', $ret, $this );
533
	}
534
535
    /**
536
     * Returns an array of subscription statuses that can be cancelled
537
     *
538
     * @access      public
539
     * @since       1.0.0
540
     * @return      array
541
     */
542
    public function get_cancellable_statuses() {
543
        return apply_filters( 'wpinv_recurring_cancellable_statuses', array( 'active', 'trialling', 'failing' ) );
544
    }
545
546
	/**
547
	 * Retrieves the URL to cancel subscription
548
	 *
549
	 * @since  1.0.0
550
	 * @return string
551
	 */
552
	public function get_cancel_url() {
553
554
		$url = wp_nonce_url( add_query_arg( array( 'wpinv_action' => 'cancel_subscription', 'sub_id' => $this->id ) ), 'wpinv-recurring-cancel' );
555
556
		return apply_filters( 'wpinv_subscription_cancel_url', $url, $this );
557
	}
558
559
	/**
560
	 * Determines if subscription can be manually renewed
561
	 *
562
	 * This method is filtered by payment gateways in order to return true on subscriptions
563
	 * that can be renewed manually
564
	 *
565
	 * @since  2.5
566
	 * @return bool
567
	 */
568
	public function can_renew() {
569
570
		return apply_filters( 'wpinv_subscription_can_renew', true, $this );
571
	}
572
573
	/**
574
	 * Retrieves the URL to renew a subscription
575
	 *
576
	 * @since  2.5
577
	 * @return string
578
	 */
579
	public function get_renew_url() {
580
581
		$url = wp_nonce_url( add_query_arg( array( 'wpinv_action' => 'renew_subscription', 'sub_id' => $this->id ) ), 'wpinv-recurring-renew' );
582
583
		return apply_filters( 'wpinv_subscription_renew_url', $url, $this );
584
	}
585
586
	/**
587
	 * Determines if subscription can have their payment method updated
588
	 *
589
	 * @since  1.0.0
590
	 * @return bool
591
	 */
592
	public function can_update() {
593
		return apply_filters( 'wpinv_subscription_can_update', false, $this );
594
	}
595
596
	/**
597
	 * Retrieves the URL to update subscription
598
	 *
599
	 * @since  1.0.0
600
	 * @return void
601
	 */
602
	public function get_update_url() {
603
604
		$url = add_query_arg( array( 'action' => 'update', 'subscription_id' => $this->id ) );
605
606
		return apply_filters( 'wpinv_subscription_update_url', $url, $this );
607
	}
608
609
	/**
610
	 * Determines if subscription is active
611
	 *
612
	 * @since  1.0.0
613
	 * @return void
614
	 */
615
	public function is_active() {
616
617
		$ret = false;
618
619
		if( ! $this->is_expired() && ( $this->status == 'active' || $this->status == 'cancelled' || $this->status == 'trialling' ) ) {
620
			$ret = true;
621
		}
622
623
		return apply_filters( 'wpinv_subscription_is_active', $ret, $this->id, $this );
624
625
	}
626
627
	/**
628
	 * Determines if subscription is expired
629
	 *
630
	 * @since  1.0.0
631
	 * @return void
632
	 */
633
	public function is_expired() {
634
635
		$ret = false;
636
637
		if ( $this->status == 'expired' ) {
638
639
			$ret = true;
640
641
		} elseif( 'active' === $this->status || 'cancelled' === $this->status || $this->status == 'trialling'  ) {
642
643
			$ret        = false;
644
			$expiration = $this->get_expiration_time();
645
646
			if( $expiration && strtotime( 'NOW', current_time( 'timestamp' ) ) > $expiration ) {
647
				$ret = true;
648
649
				if ( 'active' === $this->status || $this->status == 'trialling'  ) {
650
					$this->expire();
651
				}
652
			}
653
654
		}
655
656
		return apply_filters( 'wpinv_subscription_is_expired', $ret, $this->id, $this );
657
658
	}
659
660
	/**
661
	 * Retrieves the expiration date
662
	 *
663
	 * @since  1.0.0
664
	 * @return string
665
	 */
666
	public function get_expiration() {
667
		return $this->expiration;
668
	}
669
670
	/**
671
	 * Retrieves the expiration date in a timestamp
672
	 *
673
	 * @since  1.0.0
674
	 * @return int
675
	 */
676
	public function get_expiration_time() {
677
		return strtotime( $this->expiration, current_time( 'timestamp' ) );
678
	}
679
680
	/**
681
	 * Retrieves the subscription status
682
	 *
683
	 * @since  1.0.0
684
	 * @return int
685
	 */
686
	public function get_status() {
687
688
		// Monitor for page load delays on pages with large subscription lists (IE: Subscriptions table in admin)
689
		$this->is_expired();
690
		return $this->status;
691
	}
692
693
	/**
694
	 * Retrieves the subscription status label
695
	 *
696
	 * @since  1.0.0
697
	 * @return int
698
	 */
699
	public function get_status_label() {
700
701
		switch( $this->get_status() ) {
702
			case 'active' :
703
				$status = __( 'Active', 'invoicing' );
704
				break;
705
706
			case 'cancelled' :
707
				$status = __( 'Cancelled', 'invoicing' );
708
				break;
709
710
			case 'expired' :
711
				$status = __( 'Expired', 'invoicing' );
712
				break;
713
714
			case 'pending' :
715
				$status = __( 'Pending', 'invoicing' );
716
				break;
717
718
			case 'failing' :
719
				$status = __( 'Failing', 'invoicing' );
720
				break;
721
722
			case 'trialling' :
723
				$status = __( 'Trialling', 'invoicing' );
724
				break;
725
726
			case 'completed' :
727
				$status = __( 'Completed', 'invoicing' );
728
				break;
729
730
			default:
731
				$status = ucfirst( $this->get_status() );
732
				break;
733
		}
734
735
		return $status;
736
	}
737
738
    /**
739
     * Retrieves the subscription status label
740
     *
741
     * @since  1.0.0
742
     * @return int
743
     */
744
    public function get_status_label_html() {
745
746
        switch( $get_status = $this->get_status() ) {
747
            case 'active' :
748
                $status = __( 'Active', 'invoicing' );
749
                $class = 'label-info';
750
                break;
751
752
            case 'cancelled' :
753
                $status = __( 'Cancelled', 'invoicing' );
754
                $class = 'label-danger';
755
                break;
756
757
            case 'expired' :
758
                $status = __( 'Expired', 'invoicing' );
759
                $class = 'label-default';
760
                break;
761
762
            case 'pending' :
763
                $status = __( 'Pending', 'invoicing' );
764
                $class = 'label-primary';
765
                break;
766
767
            case 'failing' :
768
                $status = __( 'Failing', 'invoicing' );
769
                $class = 'label-danger';
770
                break;
771
772
            case 'trialling' :
773
                $status = __( 'Trialling', 'invoicing' );
774
                $class = 'label-info';
775
                break;
776
777
            case 'completed' :
778
                $status = __( 'Completed', 'invoicing' );
779
                $class = 'label-success';
780
                break;
781
782
            default:
783
                $status = ucfirst( $this->get_status() );
784
                $class = 'label-default';
785
                break;
786
        }
787
788
        $label = '<span class="sub-status label label-sub-' . $get_status . ' ' . $class . '">' . $status . '</span>';
789
790
        return apply_filters( 'wpinv_subscription_status_label_html', $label, $get_status, $status );
791
    }
792
793
    /**
794
     * Determines if a payment exists with the specified transaction ID
795
     *
796
     * @since  2.4
797
     * @param  string $txn_id The transaction ID from the merchant processor
798
     * @return bool
799
     */
800
    public function payment_exists( $txn_id = '' ) {
801
        global $wpdb;
802
803
        if ( empty( $txn_id ) ) {
804
            return false;
805
        }
806
807
        $txn_id = esc_sql( $txn_id );
808
809
        $purchase = $wpdb->get_var( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wpinv_transaction_id' AND meta_value = '{$txn_id}' LIMIT 1" );
810
811
        if ( $purchase != null ) {
812
            return true;
813
        }
814
815
        return false;
816
    }
817
818
}
819