Passed
Push — master ( 5452c3...c16653 )
by Brian
04:51 queued 19s
created

WPInv_Subscriptions::get_invoice_subscription()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 13
rs 10
cc 4
nc 4
nop 1
1
<?php
2
/**
3
 * Main Subscriptions class.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
/**
9
 * Main Subscriptions class.
10
 *
11
 */
12
class WPInv_Subscriptions {
13
14
    /**
15
	 * Class constructor.
16
	 */
17
    public function __construct(){
18
19
        // Fire gateway specific hooks when a subscription changes.
20
        add_action( 'getpaid_subscription_status_changed', array( $this, 'process_subscription_status_change' ), 10, 3 );
21
22
        // De-activate a subscription whenever the invoice changes payment statuses.
23
        add_action( 'getpaid_invoice_status_wpi-refunded', array( $this, 'maybe_deactivate_invoice_subscription' ), 20 );
24
        add_action( 'getpaid_invoice_status_wpi-failed', array( $this, 'maybe_deactivate_invoice_subscription' ), 20 );
25
        add_action( 'getpaid_invoice_status_wpi-cancelled', array( $this, 'maybe_deactivate_invoice_subscription' ), 20 );
26
        add_action( 'getpaid_invoice_status_wpi-pending', array( $this, 'maybe_deactivate_invoice_subscription' ), 20 );
27
28
        // Handles subscription cancelations.
29
        add_action( 'getpaid_authenticated_action_subscription_cancel', array( $this, 'user_cancel_single_subscription' ) );
30
31
        // Create a subscription whenever an invoice is created, (and update it when it is updated).
32
        add_action( 'getpaid_new_invoice', array( $this, 'maybe_create_invoice_subscription' ) );
33
        add_action( 'getpaid_update_invoice', array( $this, 'maybe_update_invoice_subscription' ) );
34
35
        // Handles admin subscription update actions.
36
        add_action( 'getpaid_authenticated_admin_action_update_single_subscription', array( $this, 'admin_update_single_subscription' ) );
37
        add_action( 'getpaid_authenticated_admin_action_subscription_manual_renew', array( $this, 'admin_renew_single_subscription' ) );
38
        add_action( 'getpaid_authenticated_admin_action_subscription_manual_delete', array( $this, 'admin_delete_single_subscription' ) );
39
40
        // Filter invoice item row actions.
41
        add_action( 'getpaid-invoice-page-line-item-actions', array( $this, 'filter_invoice_line_item_actions' ), 10, 3 );
42
    }
43
44
    /**
45
     * Returns an invoice's subscription.
46
     *
47
     * @param WPInv_Invoice $invoice
48
     * @return WPInv_Subscription|false
49
     */
50
    public function get_invoice_subscription( $invoice ) {
51
        $subscription_id = $invoice->get_subscription_id();
52
53
        // Fallback to the parent invoice if the child invoice has no subscription id.
54
        if ( empty( $subscription_id && $invoice->is_renewal() ) ) {
55
            $subscription_id = $invoice->get_parent_payment()->get_subscription_id();
56
        }
57
58
        // Fetch the subscription.
59
        $subscription = new WPInv_Subscription( $subscription_id );
60
61
        // Return subscription or use a fallback for backwards compatibility.
62
        return $subscription->get_id() ? $subscription : wpinv_get_subscription( $invoice );
0 ignored issues
show
Bug Best Practice introduced by
The expression return $subscription->ge..._subscription($invoice) also could return the type boolean which is incompatible with the documented return type WPInv_Subscription|false.
Loading history...
63
    }
64
65
    /**
66
     * Deactivates the invoice subscription whenever an invoice status changes.
67
     * 
68
     * @param WPInv_Invoice $invoice
69
     */
70
    public function maybe_deactivate_invoice_subscription( $invoice ) {
71
72
        $subscription = $this->get_invoice_subscription( $invoice );
73
74
        // Abort if the subscription is missing or not active.
75
        if ( empty( $subscription ) || ! $subscription->is_active() ) {
76
            return;
77
        }
78
79
        $subscription->set_status( 'pending' );
80
        $subscription->save();
81
82
    }
83
84
    /**
85
	 * Processes subscription status changes.
86
     * 
87
     * @param WPInv_Subscription $subscription
88
     * @param string $from
89
     * @param string $to
90
	 */
91
    public function process_subscription_status_change( $subscription, $from, $to ) {
92
93
        $gateway = $subscription->get_gateway();
94
95
        if ( ! empty( $gateway ) ) {
96
            $gateway = sanitize_key( $gateway );
97
            $from    = sanitize_key( $from );
98
            $to      = sanitize_key( $to );
99
            do_action( "getpaid_{$gateway}subscription_$to", $subscription, $from );
100
        }
101
102
    }
103
104
    /**
105
     * Get pretty subscription frequency
106
     *
107
     * @param $period
108
     * @param int $frequency_count The frequency of the period.
109
     * @return mixed|string|void
110
     */
111
    public static function wpinv_get_pretty_subscription_frequency( $period, $frequency_count = 1, $skip_1 = false ) {
112
113
        $frequency = '';
114
115
        //Format period details
116
        switch ( strtolower( $period ) ) {
117
            case 'day' :
118
            case 'd' :
119
                $frequency = sprintf( _n( '%d Day', '%d Days', $frequency_count, 'invoicing'), $frequency_count);
120
                break;
121
            case 'week' :
122
            case 'w' :
123
                $frequency = sprintf( _n('%d Week', '%d Weeks', $frequency_count, 'invoicing'), $frequency_count);
124
                break;
125
            case 'month' :
126
            case 'm' :
127
                $frequency = sprintf( _n('%d Month', '%d Months', $frequency_count, 'invoicing'), $frequency_count);
128
                break;
129
            case 'year' :
130
            case 'y' :
131
                $frequency = sprintf( _n('%d Year', '%d Years', $frequency_count, 'invoicing'), $frequency_count);
132
                break;
133
            default :
134
                $frequency = apply_filters( 'wpinv_recurring_subscription_frequency', $frequency, $period, $frequency_count );
135
                break;
136
        }
137
138
        if ( $skip_1 && 1 == $frequency_count ) {
139
            $frequency = str_replace( '1', '', $frequency );
140
        }
141
142
        return trim( $frequency );
143
144
    }
145
146
    /**
147
     * Handles cancellation requests for a subscription
148
     *
149
     * @access      public
150
     * @since       1.0.0
151
     * @return      void
152
     */
153
    public function user_cancel_single_subscription( $data ) {
154
155
        // Ensure there is a subscription to cancel.
156
        if ( empty( $data['subscription'] ) ) {
157
            return;
158
        }
159
160
        $subscription = new WPInv_Subscription( (int) $data['subscription'] );
161
162
        // Ensure that it exists and that it belongs to the current user.
163
        if ( ! $subscription->get_id() || $subscription->get_customer_id() != get_current_user_id() ) {
164
            wpinv_set_error( 'invalid_subscription', __( 'You do not have permission to cancel this subscription', 'invoicing' ) );
165
166
        // Can it be cancelled.
167
        } else if ( ! $subscription->can_cancel() ) {
168
            wpinv_set_error( 'cannot_cancel', __( 'This subscription cannot be cancelled as it is not active.', 'invoicing' ) );
169
            
170
171
        // Cancel it.
172
        } else {
173
174
            $subscription->cancel();
175
            wpinv_set_error( 'cancelled', __( 'This subscription has been cancelled.', 'invoicing' ), 'info' );
176
        }
177
178
        $redirect = add_query_arg(
179
            array(
180
                'getpaid-action' => false,
181
                'getpaid-nonce'  => false,
182
            )
183
        );
184
185
        wp_safe_redirect( esc_url( $redirect ) );
186
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
187
188
    }
189
190
    /**
191
     * Creates a subscription for an invoice.
192
     *
193
     * @access      public
194
     * @param       WPInv_Invoice $invoice
195
     * @since       1.0.0
196
     */
197
    public function maybe_create_invoice_subscription( $invoice ) {
198
199
        // Abort if it is not recurring.
200
        if ( $invoice->is_free() || ! $invoice->is_recurring() || $invoice->is_renewal() ) {
201
            return;
202
        }
203
204
        $subscription = new WPInv_Subscription();
205
        return $this->update_invoice_subscription( $subscription, $invoice );
206
207
    }
208
209
    /**
210
     * (Maybe) Updates a subscription for an invoice.
211
     *
212
     * @access      public
213
     * @param       WPInv_Invoice $invoice
214
     * @since       1.0.19
215
     */
216
    public function maybe_update_invoice_subscription( $invoice ) {
217
218
        // Do not process renewals.
219
        if ( $invoice->is_renewal() ) {
220
            return;
221
        }
222
223
        // (Maybe) create a new subscription.
224
        if ( ! $invoice->get_subscription_id() ) {
225
            return $this->maybe_create_invoice_subscription( $invoice );
226
        }
227
228
        $subscription = new WPInv_Subscription( $invoice->get_subscription_id() );
229
230
        // In case the subscription was deleted...
231
        if ( ! $subscription->get_id() ) {
232
            return $this->maybe_create_invoice_subscription( $invoice );
233
        }
234
235
        // Abort if an invoice is paid and already has a subscription.
236
        if ( $invoice->is_paid() || $invoice->is_refunded() ) {
237
            return;
238
        }
239
240
        return $this->update_invoice_subscription( $subscription, $invoice );
241
242
    }
243
244
    /**
245
     * Updates a subscription for an invoice.
246
     *
247
     * @access      public
248
     * @param       WPInv_Subscription $subscription
249
     * @param       WPInv_Invoice $invoice
250
     * @since       1.0.19
251
     */
252
    public function update_invoice_subscription( $subscription, $invoice ) {
253
254
        // Delete the subscription if an invoice is free or nolonger recurring.
255
        if ( $invoice->is_free() || ! $invoice->is_recurring() ) {
256
            return $subscription->delete();
257
        }
258
259
        $subscription->set_customer_id( $invoice->get_customer_id() );
260
        $subscription->set_parent_invoice_id( $invoice->get_id() );
261
        $subscription->set_initial_amount( $invoice->get_initial_total() );
262
        $subscription->set_recurring_amount( $invoice->get_recurring_total() );
263
        $subscription->set_date_created( current_time( 'mysql' ) );
264
        $subscription->set_status( $invoice->is_paid() ? 'active' : 'pending' );
265
266
        // Get the recurring item and abort if it does not exist.
267
        $subscription_item = $invoice->get_recurring( true );
268
        if ( ! $subscription_item->get_id() ) {
269
            $invoice->set_subscription_id(0);
270
            $invoice->save();
271
            return $subscription->delete();
272
        }
273
274
        $subscription->set_product_id( $subscription_item->get_id() );
275
        $subscription->set_period( $subscription_item->get_recurring_period( true ) );
276
        $subscription->set_frequency( $subscription_item->get_recurring_interval() );
277
        $subscription->set_bill_times( $subscription_item->get_recurring_limit() );
278
279
        // Calculate the next renewal date.
280
        $period       = $subscription_item->get_recurring_period( true );
281
        $interval     = $subscription_item->get_recurring_interval();
282
283
        // If the subscription item has a trial period...
284
        if ( $subscription_item->has_free_trial() ) {
285
            $period   = $subscription_item->get_trial_period( true );
286
            $interval = $subscription_item->get_trial_interval();
287
            $subscription->set_trial_period( $interval . ' ' . $period );
288
            $subscription->set_status( 'trialling' );
289
        }
290
291
        // If initial amount is free, treat it as a free trial even if the subscription item does not have a free trial.
292
        if ( $invoice->has_free_trial() ) {
293
            $subscription->set_trial_period( $interval . ' ' . $period );
294
            $subscription->set_status( 'trialling' );
295
        }
296
297
        // Calculate the next renewal date.
298
        $expiration = date( 'Y-m-d H:i:s', strtotime( "+$interval $period", strtotime( $subscription->get_date_created() ) ) );
299
300
        $subscription->set_next_renewal_date( $expiration );
301
        return $subscription->save();
302
303
    }
304
305
    /**
306
     * Fired when an admin updates a subscription via the single subscription single page.
307
     *
308
     * @param       array $data
309
     * @since       1.0.19
310
     */
311
    public function admin_update_single_subscription( $args ) {
312
313
        // Ensure the subscription exists and that a status has been given.
314
        if ( empty( $args['subscription_id'] ) || empty( $args['subscription_status'] ) ) {
315
            return;
316
        }
317
318
        // Retrieve the subscriptions.
319
        $subscription = new WPInv_Subscription( $args['subscription_id'] );
320
321
        if ( $subscription->get_id() ) {
322
323
            $subscription->set_status( $args['subscription_status'] );
324
            $subscription->save();
325
            getpaid_admin()->show_info( __( 'Your changes have been saved', 'invoicing' ) );
326
327
        }
328
329
    }
330
331
    /**
332
     * Fired when an admin manually renews a subscription.
333
     *
334
     * @param       array $data
335
     * @since       1.0.19
336
     */
337
    public function admin_renew_single_subscription( $args ) {
338
339
        // Ensure the subscription exists and that a status has been given.
340
        if ( empty( $args['id'] ) ) {
341
            return;
342
        }
343
344
        // Retrieve the subscriptions.
345
        $subscription = new WPInv_Subscription( $args['id'] );
346
347
        if ( $subscription->get_id() ) {
348
349
            $args = array( 'transaction_id', $subscription->get_parent_invoice()->generate_key( 'renewal_' ) );
350
351
            if ( $subscription->add_payment( $args ) ) {
352
                $subscription->renew();
353
                getpaid_admin()->show_info( __( 'This subscription has been renewed and extended.', 'invoicing' ) );
354
            } else {
355
                getpaid_admin()->show_error( __( 'We are unable to renew this subscription as the parent invoice does not exist.', 'invoicing' ) );
356
            }
357
    
358
            wp_safe_redirect(
359
                add_query_arg(
360
                    array(
361
                        'getpaid-admin-action' => false,
362
                        'getpaid-nonce'        => false,
363
                    )
364
                )
365
            );
366
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
367
368
        }
369
370
    }
371
372
    /**
373
     * Fired when an admin manually deletes a subscription.
374
     *
375
     * @param       array $data
376
     * @since       1.0.19
377
     */
378
    public function admin_delete_single_subscription( $args ) {
379
380
        // Ensure the subscription exists and that a status has been given.
381
        if ( empty( $args['id'] ) ) {
382
            return;
383
        }
384
385
        // Retrieve the subscriptions.
386
        $subscription = new WPInv_Subscription( $args['id'] );
387
388
        if ( $subscription->delete() ) {
389
            getpaid_admin()->show_info( __( 'This subscription has been deleted.', 'invoicing' ) );
390
        } else {
391
            getpaid_admin()->show_error( __( 'We are unable to delete this subscription. Please try again.', 'invoicing' ) );
392
        }
393
    
394
        $redirected = wp_safe_redirect(
395
            add_query_arg(
396
                array(
397
                    'getpaid-admin-action' => false,
398
                    'getpaid-nonce'        => false,
399
                    'id'                   => false,
400
                )
401
            )
402
        );
403
404
        if ( $redirected ) {
405
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
406
        }
407
408
    }
409
410
    /**
411
     * Filters the invoice line items actions.
412
     *
413
     * @param array actions
414
     * @param WPInv_Item $item
415
     * @param WPInv_Invoice $invoice
416
     */
417
    public function filter_invoice_line_item_actions( $actions, $item, $invoice ) {
418
419
        // Fetch item subscription.
420
        $args  = array(
421
            'invoice_in'  => $invoice->is_parent() ? $invoice->get_id() : $invoice->get_parent_id(),
422
            'item_in'     => $item->get_id(),
423
            'number'      => 1,
424
            'count_total' => false,
425
            'fields'      => 'id',
426
        );
427
428
        $subscription = new GetPaid_Subscriptions_Query( $args );
429
        $subscription = $subscription->get_results();
430
431
        // In case we found a match...
432
        if ( ! empty( $subscription ) ) {
433
            $url                     = esc_url( add_query_arg( 'subscription', (int) $subscription[0], get_permalink( (int) wpinv_get_option( 'invoice_subscription_page' ) ) ) );
434
            $actions['subscription'] = "<a href='$url' class='text-decoration-none'>" . __( 'Manage Subscription', 'getpaid-license-manager' ) . '</a>';
435
        }
436
437
        return $actions;
438
439
    }
440
441
}
442