Passed
Pull Request — master (#398)
by Brian
05:25
created

wpinv_maybe_remove_cart_discount()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
c 0
b 0
f 0
dl 0
loc 11
rs 10
cc 4
nc 4
nop 0
1
<?php
2
/**
3
 * Contains discount functions.
4
 *
5
 * @since 1.0.0
6
 * @package Invoicing
7
 */
8
 
9
defined( 'ABSPATH' ) || exit;
10
11
/**
12
 * Returns an array of discount type.
13
 * 
14
 * @return array
15
 */
16
function wpinv_get_discount_types() {
17
    return apply_filters(
18
        'wpinv_discount_types',
19
        array(
20
            'percent'   => __( 'Percentage', 'invoicing' ),
21
            'flat'     => __( 'Flat Amount', 'invoicing' ),
22
        )
23
    );
24
}
25
26
/**
27
 * Returns the name of a discount type.
28
 * 
29
 * @return string
30
 */
31
function wpinv_get_discount_type_name( $type = '' ) {
32
    $types = wpinv_get_discount_types();
33
    return isset( $types[ $type ] ) ? $types[ $type ] : $type;
34
}
35
36
/**
37
 * Deletes a discount via the admin page.
38
 * 
39
 * @return string
40
 */
41
function wpinv_delete_discount( $data ) {
42
43
    if ( ! isset( $data['_wpnonce'] ) || ! wp_verify_nonce( $data['_wpnonce'], 'wpinv_discount_nonce' ) ) {
44
        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...
45
    }
46
47
    if( ! wpinv_current_user_can_manage_invoicing() ) {
48
        wp_die( __( 'You do not have permission to delete discount codes', 'invoicing' ), __( 'Error', 'invoicing' ), array( 'response' => 403 ) );
49
    }
50
51
    $discount_id = $data['discount'];
52
    wpinv_remove_discount( $discount_id );
53
}
54
add_action( 'wpinv_delete_discount', 'wpinv_delete_discount' );
55
56
function wpinv_activate_discount( $data ) {
57
    if ( ! isset( $data['_wpnonce'] ) || ! wp_verify_nonce( $data['_wpnonce'], 'wpinv_discount_nonce' ) ) {
58
        wp_die( __( 'Trying to cheat or something?', 'invoicing' ), __( 'Error', 'invoicing' ), array( 'response' => 403 ) );
59
    }
60
61
    if( ! wpinv_current_user_can_manage_invoicing() ) {
62
        wp_die( __( 'You do not have permission to edit discount codes', 'invoicing' ), __( 'Error', 'invoicing' ), array( 'response' => 403 ) );
63
    }
64
65
    $id = absint( $data['discount'] );
66
    wpinv_update_discount_status( $id, 'publish' );
67
}
68
add_action( 'wpinv_activate_discount', 'wpinv_activate_discount' );
69
70
function wpinv_deactivate_discount( $data ) {
71
    if ( ! isset( $data['_wpnonce'] ) || ! wp_verify_nonce( $data['_wpnonce'], 'wpinv_discount_nonce' ) ) {
72
        wp_die( __( 'Trying to cheat or something?', 'invoicing' ), __( 'Error', 'invoicing' ), array( 'response' => 403 ) );
73
    }
74
75
    if( ! wpinv_current_user_can_manage_invoicing() ) {
76
        wp_die( __( 'You do not have permission to create discount codes', 'invoicing' ), array( 'response' => 403 ) );
0 ignored issues
show
Bug introduced by
array('response' => 403) of type array<string,integer> is incompatible with the type integer|string expected by parameter $title of wp_die(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

76
        wp_die( __( 'You do not have permission to create discount codes', 'invoicing' ), /** @scrutinizer ignore-type */ array( 'response' => 403 ) );
Loading history...
77
    }
78
79
    $id = absint( $data['discount'] );
80
    wpinv_update_discount_status( $id, 'pending' );
81
}
82
add_action( 'wpinv_deactivate_discount', 'wpinv_deactivate_discount' );
83
84
function wpinv_get_discounts( $args = array() ) {
85
    $defaults = array(
86
        'post_type'      => 'wpi_discount',
87
        'posts_per_page' => 20,
88
        'paged'          => null,
89
        'post_status'    => array( 'publish', 'pending', 'draft', 'expired' )
90
    );
91
92
    $args = wp_parse_args( $args, $defaults );
93
94
    $discounts = get_posts( $args );
95
96
    if ( $discounts ) {
97
        return $discounts;
98
    }
99
100
    if( ! $discounts && ! empty( $args['s'] ) ) {
101
        $args['meta_key']     = '_wpi_discount_code';
102
        $args['meta_value']   = $args['s'];
103
        $args['meta_compare'] = 'LIKE';
104
        unset( $args['s'] );
105
        $discounts = get_posts( $args );
106
    }
107
108
    if( $discounts ) {
109
        return $discounts;
110
    }
111
112
    return false;
113
}
114
115
function wpinv_get_all_discounts( $args = array() ) {
116
117
    $args = wp_parse_args( $args, array(
118
        'status'         => array( 'publish' ),
119
        'limit'          => get_option( 'posts_per_page' ),
120
        'page'           => 1,
121
        'exclude'        => array(),
122
        'orderby'        => 'date',
123
        'order'          => 'DESC',
124
        'type'           => array_keys( wpinv_get_discount_types() ),
125
        'meta_query'     => array(),
126
        'return'         => 'objects',
127
        'paginate'       => false,
128
    ) );
129
130
    $wp_query_args = array(
131
        'post_type'      => 'wpi_discount',
132
        'post_status'    => $args['status'],
133
        'posts_per_page' => $args['limit'],
134
        'meta_query'     => $args['meta_query'],
135
        'fields'         => 'ids',
136
        'orderby'        => $args['orderby'],
137
        'order'          => $args['order'],
138
        'paged'          => absint( $args['page'] ),
139
    );
140
141
    if ( ! empty( $args['exclude'] ) ) {
142
        $wp_query_args['post__not_in'] = array_map( 'absint', $args['exclude'] );
143
    }
144
145
    if ( ! $args['paginate' ] ) {
146
        $wp_query_args['no_found_rows'] = true;
147
    }
148
149
    if ( ! empty( $args['search'] ) ) {
150
151
        $wp_query_args['meta_query'][] = array(
152
            'key'     => '_wpi_discount_code',
153
            'value'   => $args['search'],
154
            'compare' => 'LIKE',
155
        );
156
157
    }
158
159
    if ( ! empty( $args['type'] ) ) {
160
        $types = wpinv_parse_list( $args['type'] );
161
        $wp_query_args['meta_query'][] = array(
162
            'key'     => '_wpi_discount_type',
163
            'value'   => implode( ',', $types ),
164
            'compare' => 'IN',
165
        );
166
    }
167
168
    $wp_query_args = apply_filters('wpinv_get_discount_args', $wp_query_args, $args);
169
170
    // Get results.
171
    $discounts = new WP_Query( $wp_query_args );
172
173
    if ( 'objects' === $args['return'] ) {
174
        $return = array_map( 'get_post', $discounts->posts );
175
    } elseif ( 'self' === $args['return'] ) {
176
        return $discounts;
177
    } else {
178
        $return = $discounts->posts;
179
    }
180
181
    if ( $args['paginate' ] ) {
182
        return (object) array(
183
            'discounts'      => $return,
184
            'total'         => $discounts->found_posts,
185
            'max_num_pages' => $discounts->max_num_pages,
186
        );
187
    } else {
188
        return $return;
189
    }
190
191
}
192
193
function wpinv_has_active_discounts() {
194
    $has_active = false;
195
196
    $discounts  = wpinv_get_discounts();
197
198
    if ( $discounts) {
199
        foreach ( $discounts as $discount ) {
200
            if ( wpinv_is_discount_active( $discount->ID, true ) ) {
201
                $has_active = true;
202
                break;
203
            }
204
        }
205
    }
206
    return $has_active;
207
}
208
209
function wpinv_get_discount( $discount_id = 0 ) {
210
    if( empty( $discount_id ) ) {
211
        return false;
212
    }
213
214
    if ( get_post_type( $discount_id ) != 'wpi_discount' ) {
215
        return false;
216
    }
217
218
    $discount = get_post( $discount_id );
219
220
    return $discount;
221
}
222
223
/**
224
 * Fetches a discount object.
225
 *
226
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
227
 * @since 1.0.15
228
 * @return WPInv_Discount
229
 */
230
function wpinv_get_discount_obj( $discount = 0 ) {
231
    return new WPInv_Discount( $discount );
232
}
233
234
/**
235
 * Fetch a discount from the db/cache using its discount code.
236
 *
237
 * @param string $code The discount code.
238
 * @return bool|WPInv_Discount
239
 */
240
function wpinv_get_discount_by_code( $code = '' ) {
241
    return wpinv_get_discount_by( null, $code );
242
}
243
244
/**
245
 * Fetch a discount from the db/cache using a given field.
246
 *
247
 * @param string $deprecated deprecated
248
 * @param string|int $value The field value
249
 * @return bool|WPInv_Discount
250
 */
251
function wpinv_get_discount_by( $deprecated = null, $value = '' ) {
252
    $discount = new WPInv_Discount( $value );
253
254
    if ( $discount->get_id() != 0 ) {
255
        return $discount;
256
    }
257
258
    return  false;
259
}
260
261
/**
262
 * Updates a discount in the database.
263
 *
264
 * @param int $post_id The discount's ID.
265
 * @param array $data The discount's properties.
266
 * @return bool
267
 */
268
function wpinv_store_discount( $post_id, $data, $post, $update = false ) {
269
    $meta = array(
270
        'code'              => isset( $data['code'] )             ? sanitize_text_field( $data['code'] )              : '',
271
        'type'              => isset( $data['type'] )             ? sanitize_text_field( $data['type'] )              : 'percent',
272
        'amount'            => isset( $data['amount'] )           ? wpinv_sanitize_amount( $data['amount'] )          : '',
273
        'start'             => isset( $data['start'] )            ? sanitize_text_field( $data['start'] )             : '',
274
        'expiration'        => isset( $data['expiration'] )       ? sanitize_text_field( $data['expiration'] )        : '',
275
        'min_total'         => isset( $data['min_total'] )        ? wpinv_sanitize_amount( $data['min_total'] )       : '',
276
        'max_total'         => isset( $data['max_total'] )        ? wpinv_sanitize_amount( $data['max_total'] )       : '',
277
        'max_uses'          => isset( $data['max_uses'] )         ? absint( $data['max_uses'] )                       : '',
278
        'items'             => isset( $data['items'] )            ? $data['items']                                    : array(),
279
        'excluded_items'    => isset( $data['excluded_items'] )   ? $data['excluded_items']                           : array(),
280
        'is_recurring'      => isset( $data['recurring'] )        ? (bool)$data['recurring']                          : false,
281
        'is_single_use'     => isset( $data['single_use'] )       ? (bool)$data['single_use']                         : false,
282
        'uses'              => isset( $data['uses'] )             ? (int)$data['uses']                                : false,
283
    );
284
285
    if ( $meta['type'] == 'percent' && (float)$meta['amount'] > 100 ) {
286
        $meta['amount'] = 100;
287
    }
288
289
    if ( !empty( $meta['start'] ) ) {
290
        $meta['start']      = date_i18n( 'Y-m-d H:i:s', strtotime( $meta['start'] ) );
291
    }
292
293
    if ( !empty( $meta['expiration'] ) ) {
294
        $meta['expiration'] = date_i18n( 'Y-m-d H:i:s', strtotime( $meta['expiration'] ) );
295
296
        if ( !empty( $meta['start'] ) && strtotime( $meta['start'] ) > strtotime( $meta['expiration'] ) ) {
297
            $meta['expiration'] = $meta['start'];
298
        }
299
    }
300
301
    if ( $meta['uses'] === false ) {
302
        unset( $meta['uses'] );
303
    }
304
305
    if ( ! empty( $meta['items'] ) ) {
306
        foreach ( $meta['items'] as $key => $item ) {
307
            if ( 0 === intval( $item ) ) {
308
                unset( $meta['items'][ $key ] );
309
            }
310
        }
311
    }
312
313
    if ( ! empty( $meta['excluded_items'] ) ) {
314
        foreach ( $meta['excluded_items'] as $key => $item ) {
315
            if ( 0 === intval( $item ) ) {
316
                unset( $meta['excluded_items'][ $key ] );
317
            }
318
        }
319
    }
320
321
    $meta = apply_filters( 'wpinv_update_discount', $meta, $post_id, $post );
322
323
    do_action( 'wpinv_pre_update_discount', $meta, $post_id, $post );
324
325
    foreach( $meta as $key => $value ) {
326
        update_post_meta( $post_id, '_wpi_discount_' . $key, $value );
327
    }
328
329
    do_action( 'wpinv_post_update_discount', $meta, $post_id, $post );
330
331
    return $post_id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $post_id returns the type integer which is incompatible with the documented return type boolean.
Loading history...
332
}
333
334
/**
335
 * Delectes a discount from the database.
336
 *
337
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
338
 * @return bool
339
 */
340
function wpinv_remove_discount( $discount = 0 ) {
341
342
    $discount = wpinv_get_discount_obj( $discount );
343
    if( ! $discount->exists() ) {
344
        return false;
345
    }
346
347
    $discount->remove();
348
    return true;
349
}
350
351
/**
352
 * Updates a discount status.
353
 *
354
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
355
 * @param string $new_status
356
 * @return bool
357
 */
358
function wpinv_update_discount_status( $discount = 0, $new_status = 'publish' ) {
359
    $discount = wpinv_get_discount_obj( $discount );
360
    return $discount->update_status( $new_status );
0 ignored issues
show
Deprecated Code introduced by
The function WPInv_Discount::update_status() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

360
    return /** @scrutinizer ignore-deprecated */ $discount->update_status( $new_status );
Loading history...
Bug introduced by
Are you sure the usage of $discount->update_status($new_status) targeting WPInv_Discount::update_status() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
361
}
362
363
/**
364
 * Checks if a discount exists.
365
 *
366
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
367
 * @return bool
368
 */
369
function wpinv_discount_exists( $discount ) {
370
    $discount = wpinv_get_discount_obj( $discount );
371
    return $discount->exists();
372
}
373
374
function wpinv_is_discount_active( $code_id = null, $silent = false ) {
375
    $discount = wpinv_get_discount(  $code_id );
376
    $return   = false;
377
378
    if ( $discount ) {
379
        if ( wpinv_is_discount_expired( $code_id, $silent ) ) {
380
            if( defined( 'DOING_AJAX' ) && ! $silent ) {
381
                wpinv_set_error( 'wpinv-discount-error', __( 'This discount is expired.', 'invoicing' ) );
382
            }
383
        } elseif ( $discount->post_status == 'publish' ) {
384
            $return = true;
385
        } else {
386
            if( defined( 'DOING_AJAX' ) && ! $silent ) {
387
                wpinv_set_error( 'wpinv-discount-error', __( 'This discount is not active.', 'invoicing' ) );
388
            }
389
        }
390
    }
391
392
    return apply_filters( 'wpinv_is_discount_active', $return, $code_id );
393
}
394
395
function wpinv_get_discount_code( $code_id = null ) {
396
    $code = get_post_meta( $code_id, '_wpi_discount_code', true );
397
398
    return apply_filters( 'wpinv_get_discount_code', $code, $code_id );
399
}
400
401
function wpinv_get_discount_start_date( $code_id = null ) {
402
    $start_date = get_post_meta( $code_id, '_wpi_discount_start', true );
403
404
    return apply_filters( 'wpinv_get_discount_start_date', $start_date, $code_id );
405
}
406
407
function wpinv_get_discount_expiration( $code_id = null ) {
408
    $expiration = get_post_meta( $code_id, '_wpi_discount_expiration', true );
409
410
    return apply_filters( 'wpinv_get_discount_expiration', $expiration, $code_id );
411
}
412
413
/**
414
 * Returns the number of maximum number of times a discount can been used.
415
 *
416
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
417
 * @return int
418
 */
419
function wpinv_get_discount_max_uses( $discount = array() ) {
420
    $discount = wpinv_get_discount_obj( $discount );
421
    return (int) $discount->max_uses;
0 ignored issues
show
Bug Best Practice introduced by
The property max_uses does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
422
}
423
424
/**
425
 * Returns the number of times a discount has been used.
426
 *
427
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
428
 * @return int
429
 */
430
function wpinv_get_discount_uses( $discount = array() ) {
431
    $discount = wpinv_get_discount_obj( $discount );
432
    return (int) $discount->uses;
0 ignored issues
show
Bug Best Practice introduced by
The property uses does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
433
}
434
435
/**
436
 * Returns the minimum invoice amount required to use a discount.
437
 *
438
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
439
 * @return float
440
 */
441
function wpinv_get_discount_min_total( $discount = array() ) {
442
    $discount = wpinv_get_discount_obj( $discount );
443
    return (float) $discount->min_total;
0 ignored issues
show
Bug Best Practice introduced by
The property min_total does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
444
}
445
446
/**
447
 * Returns the maximum invoice amount required to use a discount.
448
 *
449
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
450
 * @return float
451
 */
452
function wpinv_get_discount_max_total( $discount = array() ) {
453
    $discount = wpinv_get_discount_obj( $discount );
454
    return (float) $discount->max_total;
0 ignored issues
show
Bug Best Practice introduced by
The property max_total does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
455
}
456
457
/**
458
 * Returns a discount's amount.
459
 *
460
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
461
 * @return float
462
 */
463
function wpinv_get_discount_amount( $discount = array() ) {
464
    $discount = wpinv_get_discount_obj( $discount );
465
    return (float) $discount->amount;
0 ignored issues
show
Bug Best Practice introduced by
The property amount does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
466
}
467
468
/**
469
 * Returns a discount's type.
470
 *
471
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
472
 * @param bool $name
473
 * @return string
474
 */
475
function wpinv_get_discount_type( $discount = array(), $name = false ) {
476
    $discount = wpinv_get_discount_obj( $discount );
477
478
    // Are we returning the name or just the type.
479
    if( $name ) {
480
        return $discount->type_name;
0 ignored issues
show
Bug Best Practice introduced by
The property type_name does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
481
    }
482
483
    return $discount->type;
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
484
}
485
486
function wpinv_discount_status( $status ) {
487
    switch( $status ){
488
        case 'expired' :
489
            $name = __( 'Expired', 'invoicing' );
490
            break;
491
        case 'publish' :
492
        case 'active' :
493
            $name = __( 'Active', 'invoicing' );
494
            break;
495
        default :
496
            $name = __( 'Inactive', 'invoicing' );
497
            break;
498
    }
499
    return $name;
500
}
501
502
/**
503
 * Returns a discount's excluded items.
504
 *
505
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
506
 * @return array
507
 */
508
function wpinv_get_discount_excluded_items( $discount = array() ) {
509
    $discount = wpinv_get_discount_obj( $discount );
510
    return $discount->excluded_items;
0 ignored issues
show
Bug Best Practice introduced by
The property excluded_items does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
511
}
512
513
/**
514
 * Returns a discount's required items.
515
 *
516
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
517
 * @return array
518
 */
519
function wpinv_get_discount_item_reqs( $discount = array() ) {
520
    $discount = wpinv_get_discount_obj( $discount );
521
    return $discount->items;
0 ignored issues
show
Bug Best Practice introduced by
The property items does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
522
}
523
524
function wpinv_get_discount_item_condition( $code_id = 0 ) {
525
    return get_post_meta( $code_id, '_wpi_discount_item_condition', true );
526
}
527
528
function wpinv_is_discount_not_global( $code_id = 0 ) {
529
    return (bool) get_post_meta( $code_id, '_wpi_discount_is_not_global', true );
530
}
531
532
/**
533
 * Checks if a given discount has expired.
534
 *
535
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
536
 * @return bool
537
 */
538
function wpinv_is_discount_expired( $discount = array(), $silent = false ) {
539
    $discount = wpinv_get_discount_obj( $discount );
540
541
    if ( $discount->is_expired() ) {
542
        $discount->update_status( 'pending' );
0 ignored issues
show
Deprecated Code introduced by
The function WPInv_Discount::update_status() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

542
        /** @scrutinizer ignore-deprecated */ $discount->update_status( 'pending' );
Loading history...
543
544
        if( empty( $silent ) ) {
545
            wpinv_set_error( 'wpinv-discount-error', __( 'This discount has expired.', 'invoicing' ) );
546
        }
547
        return true;
548
    }
549
550
    return false;
551
}
552
553
/**
554
 * Checks if a given discount has started.
555
 *
556
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
557
 * @return bool
558
 */
559
function wpinv_is_discount_started( $discount = array() ) {
560
    $discount = wpinv_get_discount_obj( $discount );
561
    $started  = $discount->has_started();
562
563
    if( empty( $started ) ) {
564
        wpinv_set_error( 'wpinv-discount-error', __( 'This discount is not active yet.', 'invoicing' ) );
565
    }
566
567
    return $started;
568
}
569
570
/**
571
 * Checks discount dates.
572
 *
573
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
574
 * @return bool
575
 */
576
function wpinv_check_discount_dates( $discount ) {
577
    $discount = wpinv_get_discount_obj( $discount );
578
    $return   = wpinv_is_discount_started( $discount ) && ! wpinv_is_discount_expired( $discount );
579
    return apply_filters( 'wpinv_check_discount_dates', $return, $discount->ID, $discount, $discount->code );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
580
}
581
582
/**
583
 * Checks if a discount is maxed out.
584
 *
585
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
586
 * @return bool
587
 */
588
function wpinv_is_discount_maxed_out( $discount ) {
589
    $discount    = wpinv_get_discount_obj( $discount );
590
    $maxed_out   = $discount->has_exceeded_limit();
591
592
    if ( $maxed_out ) {
593
        wpinv_set_error( 'wpinv-discount-error', __( 'This discount has reached its maximum usage.', 'invoicing' ) );
594
    }
595
596
    return $maxed_out;
597
}
598
599
/**
600
 * Checks if an amount meets a discount's minimum amount.
601
 *
602
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
603
 * @param float $amount The amount to check for.
604
 * @return bool
605
 */
606
function wpinv_discount_is_min_met( $discount, $amount = 0 ) {
607
    $discount = wpinv_get_discount_obj( $discount );
608
    return $discount->is_minimum_amount_met( $amount );
609
}
610
611
/**
612
 * Checks if an amount meets a discount's maximum amount.
613
 *
614
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
615
 * @return bool
616
 */
617
function wpinv_discount_is_max_met( $discount ) {
618
    $discount    = wpinv_get_discount_obj( $discount );
619
    $cart_amount = (float)wpinv_get_cart_discountable_subtotal( $discount->ID );
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_get_cart_discountable_subtotal() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

619
    $cart_amount = (float)/** @scrutinizer ignore-deprecated */ wpinv_get_cart_discountable_subtotal( $discount->ID );
Loading history...
Unused Code introduced by
The call to wpinv_get_cart_discountable_subtotal() has too many arguments starting with $discount->ID. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

619
    $cart_amount = (float)/** @scrutinizer ignore-call */ wpinv_get_cart_discountable_subtotal( $discount->ID );

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
620
    $max_met     = $discount->is_maximum_amount_met( $cart_amount );
621
622
    if ( ! $max_met ) {
623
        wpinv_set_error( 'wpinv-discount-error', sprintf( __( 'Maximum invoice amount should be %s', 'invoicing' ), wpinv_price( wpinv_format_amount( $discount->max_total ) ) ) );
0 ignored issues
show
Bug Best Practice introduced by
The property max_total does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
624
    }
625
626
    return $max_met;
627
}
628
629
/**
630
 * Checks if a discount can only be used once per user.
631
 *
632
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
633
 * @return bool
634
 */
635
function wpinv_discount_is_single_use( $discount ) {
636
    $discount    = wpinv_get_discount_obj( $discount );
637
    return $discount->is_single_use;
0 ignored issues
show
Bug Best Practice introduced by
The property is_single_use does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
638
}
639
640
/**
641
 * Checks if a discount is recurring.
642
 *
643
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
644
 * @param int|array|string|WPInv_Discount $code discount data, object, ID or code.
645
 * @return bool
646
 */
647
function wpinv_discount_is_recurring( $discount = 0, $code = 0 ) {
648
649
    if( ! empty( $discount ) ) {
650
        $discount    = wpinv_get_discount_obj( $discount );
651
    } else {
652
        $discount    = wpinv_get_discount_obj( $code );
653
    }
654
655
    return $discount->get_is_recurring();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $discount->get_is_recurring() also could return the type integer|string which is incompatible with the documented return type boolean.
Loading history...
656
}
657
658
function wpinv_discount_item_reqs_met( $code_id = null ) {
659
    $item_reqs    = wpinv_get_discount_item_reqs( $code_id );
660
    $condition    = wpinv_get_discount_item_condition( $code_id );
661
    $excluded_ps  = wpinv_get_discount_excluded_items( $code_id );
662
    $cart_items   = wpinv_get_cart_contents();
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_get_cart_contents() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

662
    $cart_items   = /** @scrutinizer ignore-deprecated */ wpinv_get_cart_contents();
Loading history...
663
    $cart_ids     = $cart_items ? wp_list_pluck( $cart_items, 'id' ) : null;
0 ignored issues
show
introduced by
$cart_items is an empty array, thus is always false.
Loading history...
664
    $ret          = false;
665
666
    if ( empty( $item_reqs ) && empty( $excluded_ps ) ) {
667
        $ret = true;
668
    }
669
670
    // Normalize our data for item requirements, exclusions and cart data
671
    // First absint the items, then sort, and reset the array keys
672
    $item_reqs = array_map( 'absint', $item_reqs );
673
    asort( $item_reqs );
674
    $item_reqs = array_values( $item_reqs );
675
676
    $excluded_ps  = array_map( 'absint', $excluded_ps );
677
    asort( $excluded_ps );
678
    $excluded_ps  = array_values( $excluded_ps );
679
680
    $cart_ids     = array_map( 'absint', $cart_ids );
0 ignored issues
show
Bug introduced by
$cart_ids of type null is incompatible with the type array expected by parameter $arr1 of array_map(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

680
    $cart_ids     = array_map( 'absint', /** @scrutinizer ignore-type */ $cart_ids );
Loading history...
681
    asort( $cart_ids );
682
    $cart_ids     = array_values( $cart_ids );
683
684
    // Ensure we have requirements before proceeding
685
    if ( !$ret && ! empty( $item_reqs ) ) {
686
        switch( $condition ) {
687
            case 'all' :
688
                // Default back to true
689
                $ret = true;
690
691
                foreach ( $item_reqs as $item_id ) {
692
                    if ( !wpinv_item_in_cart( $item_id ) ) {
693
                        wpinv_set_error( 'wpinv-discount-error', __( 'The item requirements for this discount are not met.', 'invoicing' ) );
694
                        $ret = false;
695
                        break;
696
                    }
697
                }
698
699
                break;
700
701
            default : // Any
702
                foreach ( $item_reqs as $item_id ) {
703
                    if ( wpinv_item_in_cart( $item_id ) ) {
704
                        $ret = true;
705
                        break;
706
                    }
707
                }
708
709
                if( ! $ret ) {
710
                    wpinv_set_error( 'wpinv-discount-error', __( 'The item requirements for this discount are not met.', 'invoicing' ) );
711
                }
712
713
                break;
714
        }
715
    } else {
716
        $ret = true;
717
    }
718
719
    if( ! empty( $excluded_ps ) ) {
720
        // Check that there are items other than excluded ones in the cart
721
        if( $cart_ids == $excluded_ps ) {
722
            wpinv_set_error( 'wpinv-discount-error', __( 'This discount is not valid for the cart contents.', 'invoicing' ) );
723
            $ret = false;
724
        }
725
    }
726
727
    return (bool) apply_filters( 'wpinv_is_discount_item_req_met', $ret, $code_id, $condition );
728
}
729
730
/**
731
 * Checks if a discount has already been used by the user.
732
 *
733
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
734
 * @param int|string $user The user id, login or email
735
 * @param int|array|string|WPInv_Discount $code_id discount data, object, ID or code.
736
 * @return bool
737
 */
738
function wpinv_is_discount_used( $discount = array(), $user = '', $code_id = array() ) {
739
740
    if( ! empty( $discount ) ) {
741
        $discount = wpinv_get_discount_obj( $discount );
742
    } else {
743
        $discount = wpinv_get_discount_obj( $code_id );
744
    }
745
746
    $is_used = ! $discount->is_valid_for_user( $user );
747
    $is_used = apply_filters( 'wpinv_is_discount_used', $is_used, $discount->code, $user, $discount->ID, $discount );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
748
749
    if( $is_used ) {
750
        wpinv_set_error( 'wpinv-discount-error', __( 'This discount has already been redeemed.', 'invoicing' ) );
751
    }
752
753
    return $is_used;
754
}
755
756
function wpinv_is_discount_valid( $code = '', $user = '', $set_error = true ) {
757
758
    // Abort early if there is no discount code.
759
    if ( empty( $code ) ) {
760
        return false;
761
    }
762
763
    $return      = false;
764
    $discount_id = wpinv_get_discount_id_by_code( $code );
765
    $user        = trim( $user );
766
767
    if ( wpinv_get_cart_contents() ) {
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_get_cart_contents() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

767
    if ( /** @scrutinizer ignore-deprecated */ wpinv_get_cart_contents() ) {
Loading history...
768
        if ( $discount_id !== false ) {
769
            if (
770
                wpinv_is_discount_active( $discount_id ) &&
771
                wpinv_check_discount_dates( $discount_id ) &&
772
                !wpinv_is_discount_maxed_out( $discount_id ) &&
773
                !wpinv_is_discount_used( $code, $user, $discount_id ) &&
774
                wpinv_discount_is_min_met( $discount_id ) &&
775
                wpinv_discount_is_max_met( $discount_id ) &&
776
                wpinv_discount_item_reqs_met( $discount_id )
777
            ) {
778
                $return = true;
779
            }
780
        } elseif( $set_error ) {
781
            wpinv_set_error( 'wpinv-discount-error', __( 'This discount is invalid.', 'invoicing' ) );
782
        }
783
    }
784
785
    return apply_filters( 'wpinv_is_discount_valid', $return, $discount_id, $code, $user );
786
}
787
788
/**
789
 * Given a discount code, this function returns the discount's id.
790
 * 
791
 * @param string $code
792
 * @return bool|false
793
 */
794
function wpinv_get_discount_id_by_code( $code ) {
795
    $discount = wpinv_get_discount_by_code( $code );
796
    if ( $discount ) {
797
        return $discount->get_id();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $discount->get_id() returns the type integer which is incompatible with the documented return type boolean.
Loading history...
798
    }
799
    return false;
800
}
801
802
/**
803
 * Calculates the discounted amount.
804
 *
805
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
806
 * @param float $base_price The number of usages to increase by
807
 * @return float
808
 */
809
function wpinv_get_discounted_amount( $discount, $base_price ) {
810
    $discount = wpinv_get_discount_obj( $discount );
811
    return $discount->get_discounted_amount( $base_price );
812
}
813
814
/**
815
 * Increases a discount's usage count.
816
 *
817
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
818
 * @param int $by The number of usages to increase by.
819
 * @return int the new number of uses.
820
 */
821
function wpinv_increase_discount_usage( $discount, $by = 1 ) {
822
    $discount   = wpinv_get_discount_obj( $discount );
823
    return $discount->increase_usage( $by );
824
}
825
826
/**
827
 * Decreases a discount's usage count.
828
 *
829
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
830
 * @param int $by The number of usages to decrease by.
831
 * @return int the new number of uses.
832
 */
833
function wpinv_decrease_discount_usage( $discount, $by = 1 ) {
834
    $discount   = wpinv_get_discount_obj( $discount );
835
    return $discount->increase_usage( 0 - $by );
836
}
837
838
function wpinv_format_discount_rate( $type, $amount ) {
839
    if ( $type == 'flat' ) {
840
        $rate = wpinv_price( wpinv_format_amount( $amount ) );
841
    } else {
842
        $rate = $amount . '%';
843
    }
844
845
    return apply_filters( 'wpinv_format_discount_rate', $rate, $type, $amount );
846
}
847
848
function wpinv_unset_all_cart_discounts() {
849
    $data = wpinv_get_checkout_session();
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_get_checkout_session() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

849
    $data = /** @scrutinizer ignore-deprecated */ wpinv_get_checkout_session();
Loading history...
850
851
    if ( !empty( $data ) && isset( $data['cart_discounts'] ) ) {
852
        unset( $data['cart_discounts'] );
853
854
         wpinv_set_checkout_session( $data );
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_set_checkout_session() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

854
         /** @scrutinizer ignore-deprecated */ wpinv_set_checkout_session( $data );
Loading history...
Unused Code introduced by
The call to wpinv_set_checkout_session() has too many arguments starting with $data. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

854
         /** @scrutinizer ignore-call */ 
855
         wpinv_set_checkout_session( $data );

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
855
         return true;
856
    }
857
858
    return false;
859
}
860
861
function wpinv_get_cart_discounts() {
862
    $session = wpinv_get_checkout_session();
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_get_checkout_session() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

862
    $session = /** @scrutinizer ignore-deprecated */ wpinv_get_checkout_session();
Loading history...
863
    return empty( $session['cart_discounts'] ) ? false : $session['cart_discounts'];
864
}
865
866
function wpinv_cart_has_discounts( $items = array() ) {
867
    $ret = false;
868
869
    if ( wpinv_get_cart_discounts( $items ) ) {
0 ignored issues
show
Unused Code introduced by
The call to wpinv_get_cart_discounts() has too many arguments starting with $items. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

869
    if ( /** @scrutinizer ignore-call */ wpinv_get_cart_discounts( $items ) ) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
870
        $ret = true;
871
    }
872
873
    /*
874
    $invoice = wpinv_get_invoice_cart();
875
    if ( !empty( $invoice ) && ( $invoice->get_discount() > 0 || $invoice->get_discount_code() ) ) {
876
        $ret = true;
877
    }
878
    */
879
880
    return apply_filters( 'wpinv_cart_has_discounts', $ret );
881
}
882
883
function wpinv_get_cart_discounted_amount( $items = array(), $discounts = false ) {
884
    $amount = 0.00;
885
    $items  = !empty( $items ) ? $items : wpinv_get_cart_content_details();
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_get_cart_content_details() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

885
    $items  = !empty( $items ) ? $items : /** @scrutinizer ignore-deprecated */ wpinv_get_cart_content_details();
Loading history...
886
887
    if ( $items ) {
888
        $discounts = wp_list_pluck( $items, 'discount' );
889
890
        if ( is_array( $discounts ) ) {
0 ignored issues
show
introduced by
The condition is_array($discounts) is always true.
Loading history...
891
            $discounts = array_map( 'floatval', $discounts );
892
            $amount    = array_sum( $discounts );
893
        }
894
    }
895
896
    return apply_filters( 'wpinv_get_cart_discounted_amount', $amount );
897
}
898
899
function wpinv_get_discount_label( $code, $echo = true ) {
900
    $label = wp_sprintf( __( 'Discount%1$s', 'invoicing' ), ( $code != '' && $code != 'none' ? ' (<code>' . $code . '</code>)': '' ) );
901
    $label = apply_filters( 'wpinv_get_discount_label', $label, $code );
902
903
    if ( $echo ) {
904
        echo $label;
905
    } else {
906
        return $label;
907
    }
908
}
909
910
function wpinv_cart_discount_label( $code, $rate, $echo = true ) {
911
    $label = wp_sprintf( __( 'Discount: %s', 'invoicing' ), $code );
912
    $label = apply_filters( 'wpinv_cart_discount_label', $label, $code, $rate );
913
914
    if ( $echo ) {
915
        echo $label;
916
    } else {
917
        return $label;
918
    }
919
}
920
921
function wpinv_check_delete_discount( $check, $post ) {
922
    if ( $post->post_type == 'wpi_discount' && wpinv_get_discount_uses( $post->ID ) > 0 ) {
923
        return true;
924
    }
925
926
    return $check;
927
}
928
929
function wpinv_discount_amount() {
930
    $output = 0.00;
931
932
    return apply_filters( 'wpinv_discount_amount', $output );
933
}
934