Passed
Pull Request — master (#257)
by
unknown
06:36
created

wpinv_check_discount_dates()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 4
rs 10
1
<?php
2
/**
3
 * Contains functions related to Invoicing plugin.
4
 *
5
 * @since 1.0.0
6
 * @package Invoicing
7
 */
8
 
9
// MUST have WordPress.
10
if ( !defined( 'WPINC' ) ) {
11
    exit( 'Do NOT access this file directly: ' . basename( __FILE__ ) );
12
}
13
14
function wpinv_get_discount_types() {
15
    $discount_types = array(
16
                        'percent'   => __( 'Percentage', 'invoicing' ),
17
                        'flat'     => __( 'Flat Amount', 'invoicing' ),
18
                    );
19
    return (array)apply_filters( 'wpinv_discount_types', $discount_types );
20
}
21
22
function wpinv_get_discount_type_name( $type = '' ) {
23
    $types = wpinv_get_discount_types();
24
    return isset( $types[ $type ] ) ? $types[ $type ] : '';
25
}
26
27
function wpinv_delete_discount( $data ) {
28
    if ( ! isset( $data['_wpnonce'] ) || ! wp_verify_nonce( $data['_wpnonce'], 'wpinv_discount_nonce' ) ) {
29
        wp_die( __( 'Trying to cheat or something?', 'invoicing' ), __( 'Error', 'invoicing' ), array( 'response' => 403 ) );
30
    }
31
32
    if( ! wpinv_current_user_can_manage_invoicing() ) {
33
        wp_die( __( 'You do not have permission to delete discount codes', 'invoicing' ), __( 'Error', 'invoicing' ), array( 'response' => 403 ) );
34
    }
35
36
    $discount_id = $data['discount'];
37
    wpinv_remove_discount( $discount_id );
38
}
39
add_action( 'wpinv_delete_discount', 'wpinv_delete_discount' );
40
41
function wpinv_activate_discount( $data ) {
42
    if ( ! isset( $data['_wpnonce'] ) || ! wp_verify_nonce( $data['_wpnonce'], 'wpinv_discount_nonce' ) ) {
43
        wp_die( __( 'Trying to cheat or something?', 'invoicing' ), __( 'Error', 'invoicing' ), array( 'response' => 403 ) );
44
    }
45
46
    if( ! wpinv_current_user_can_manage_invoicing() ) {
47
        wp_die( __( 'You do not have permission to edit discount codes', 'invoicing' ), __( 'Error', 'invoicing' ), array( 'response' => 403 ) );
48
    }
49
50
    $id = absint( $data['discount'] );
51
    wpinv_update_discount_status( $id, 'publish' );
52
}
53
add_action( 'wpinv_activate_discount', 'wpinv_activate_discount' );
54
55
function wpinv_deactivate_discount( $data ) {
56
    if ( ! isset( $data['_wpnonce'] ) || ! wp_verify_nonce( $data['_wpnonce'], 'wpinv_discount_nonce' ) ) {
57
        wp_die( __( 'Trying to cheat or something?', 'invoicing' ), __( 'Error', 'invoicing' ), array( 'response' => 403 ) );
58
    }
59
60
    if( ! wpinv_current_user_can_manage_invoicing() ) {
61
        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

61
        wp_die( __( 'You do not have permission to create discount codes', 'invoicing' ), /** @scrutinizer ignore-type */ array( 'response' => 403 ) );
Loading history...
62
    }
63
64
    $id = absint( $data['discount'] );
65
    wpinv_update_discount_status( $id, 'pending' );
66
}
67
add_action( 'wpinv_deactivate_discount', 'wpinv_deactivate_discount' );
68
69
function wpinv_get_discounts( $args = array() ) {
70
    $defaults = array(
71
        'post_type'      => 'wpi_discount',
72
        'posts_per_page' => 20,
73
        'paged'          => null,
74
        'post_status'    => array( 'publish', 'pending', 'draft', 'expired' )
75
    );
76
77
    $args = wp_parse_args( $args, $defaults );
78
79
    $discounts = get_posts( $args );
80
81
    if ( $discounts ) {
82
        return $discounts;
83
    }
84
85
    if( ! $discounts && ! empty( $args['s'] ) ) {
86
        $args['meta_key']     = '_wpi_discount_code';
87
        $args['meta_value']   = $args['s'];
88
        $args['meta_compare'] = 'LIKE';
89
        unset( $args['s'] );
90
        $discounts = get_posts( $args );
91
    }
92
93
    if( $discounts ) {
94
        return $discounts;
95
    }
96
97
    return false;
98
}
99
100
function wpinv_get_all_discounts( $args = array() ) {
101
102
    $args = wp_parse_args( $args, array(
103
        'status'         => array( 'publish' ),
104
        'limit'          => get_option( 'posts_per_page' ),
105
        'page'           => 1,
106
        'exclude'        => array(),
107
        'orderby'        => 'date',
108
        'order'          => 'DESC',
109
        'type'           => array_keys( wpinv_get_discount_types() ),
110
        'meta_query'     => array(),
111
        'return'         => 'objects',
112
        'paginate'       => false,
113
    ) );
114
115
    $wp_query_args = array(
116
        'post_type'      => 'wpi_discount',
117
        'post_status'    => $args['status'],
118
        'posts_per_page' => $args['limit'],
119
        'meta_query'     => $args['meta_query'],
120
        'fields'         => 'ids',
121
        'orderby'        => $args['orderby'],
122
        'order'          => $args['order'],
123
        'paged'          => absint( $args['page'] ),
124
    );
125
126
    if ( ! empty( $args['exclude'] ) ) {
127
        $wp_query_args['post__not_in'] = array_map( 'absint', $args['exclude'] );
128
    }
129
130
    if ( ! $args['paginate' ] ) {
131
        $wp_query_args['no_found_rows'] = true;
132
    }
133
134
    if ( ! empty( $args['search'] ) ) {
135
136
        $wp_query_args['meta_query'][] = array(
137
            'key'     => '_wpi_discount_code',
138
            'value'   => $args['search'],
139
            'compare' => 'LIKE',
140
        );
141
142
    }
143
    
144
    if ( ! empty( $args['type'] ) ) {
145
        $types = wpinv_parse_list( $args['type'] );
146
        $wp_query_args['meta_query'][] = array(
147
            'key'     => '_wpi_discount_type',
148
            'value'   => implode( ',', $types ),
149
            'compare' => 'IN',
150
        );
151
    }
152
153
    $wp_query_args = apply_filters('wpinv_get_discount_args', $wp_query_args, $args);
154
155
    // Get results.
156
    $discounts = new WP_Query( $wp_query_args );
157
158
    if ( 'objects' === $args['return'] ) {
159
        $return = array_map( 'get_post', $discounts->posts );
160
    } elseif ( 'self' === $args['return'] ) {
161
        return $discounts;
162
    } else {
163
        $return = $discounts->posts;
164
    }
165
166
    if ( $args['paginate' ] ) {
167
        return (object) array(
168
            'discounts'      => $return,
169
            'total'         => $discounts->found_posts,
170
            'max_num_pages' => $discounts->max_num_pages,
171
        );
172
    } else {
173
        return $return;
174
    }
175
176
}
177
178
function wpinv_has_active_discounts() {
179
    $has_active = false;
180
181
    $discounts  = wpinv_get_discounts();
182
183
    if ( $discounts) {
184
        foreach ( $discounts as $discount ) {
185
            if ( wpinv_is_discount_active( $discount->ID ) ) {
186
                $has_active = true;
187
                break;
188
            }
189
        }
190
    }
191
    return $has_active;
192
}
193
194
function wpinv_get_discount( $discount_id = 0 ) {
195
    if( empty( $discount_id ) ) {
196
        return false;
197
    }
198
    
199
    if ( get_post_type( $discount_id ) != 'wpi_discount' ) {
200
        return false;
201
    }
202
203
    $discount = get_post( $discount_id );
204
205
    return $discount;
206
}
207
208
/**
209
 * Fetches a discount object.
210
 * 
211
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
212
 * @since 1.0.14
213
 * @return WPInv_Discount
214
 */
215
function wpinv_get_discount_obj( $discount = 0 ) {
216
    return new WPInv_Discount( $discount );
217
}
218
219
/**
220
 * Fetch a discount from the db/cache using its discount code.
221
 * 
222
 * @param string $code The discount code.
223
 * @return bool|WP_Post
224
 */
225
function wpinv_get_discount_by_code( $code = '' ) {
226
    return wpinv_get_discount_by( 'code', $code );
227
}
228
229
/**
230
 * Fetch a discount from the db/cache using a given field.
231
 * 
232
 * @param string $field The field to query against: 'ID', 'discount_code', 'code', 'name'
233
 * @param string|int $value The field value
234
 * @return bool|WP_Post
235
 */
236
function wpinv_get_discount_by( $field = '', $value = '' ) {
237
    $data = WPInv_Discount::get_data_by( $field, $value );
238
    if( empty( $data ) ) {
239
        return false;
240
    }
241
242
    return get_post( $data['ID'] );
243
}
244
245
/**
246
 * Updates a discount in the database.
247
 * 
248
 * @param int $post_id The discount's ID.
249
 * @param array $data The discount's properties.
250
 * @return bool
251
 */
252
function wpinv_store_discount( $post_id, $data ) {
253
254
    // Fetch existing data.
255
    $existing_data = WPInv_Discount::get_data_by( 'id', $post_id );
256
    if( empty( $existing_data ) ) {
257
        return false;
258
    }
259
260
    // Merge it into the new data and save.
261
    $data          = wp_parse_args( $data, $existing_data );
0 ignored issues
show
Security Variable Injection introduced by
$data can contain request data and is used in variable name context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_POST, and wpinv_store_discount() is called
    in includes/admin/admin-meta-boxes.php on line 379
  2. Enters via parameter $data
    in includes/wpinv-discount-functions.php on line 252

Used in variable context

  1. wp_parse_args() is called
    in includes/wpinv-discount-functions.php on line 261
  2. Enters via parameter $args
    in wordpress/wp-includes/functions.php on line 4294
  3. wp_parse_str() is called
    in wordpress/wp-includes/functions.php on line 4300
  4. Enters via parameter $string
    in wordpress/wp-includes/formatting.php on line 4865
  5. parse_str() is called
    in wordpress/wp-includes/formatting.php on line 4866

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
262
    $discount      = wpinv_get_discount_obj( $data );
263
    return $discount->save();
264
}
265
266
/**
267
 * Delectes a discount from the database.
268
 * 
269
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
270
 * @return bool
271
 */
272
function wpinv_remove_discount( $discount = 0 ) {
273
274
    $discount = wpinv_get_discount_obj( $discount );
275
    if( ! $discount->exists() ) {
276
        return false;
277
    }
278
279
    $discount->remove();
280
    return true;
281
}
282
283
/**
284
 * Updates a discount status.
285
 * 
286
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
287
 * @param string $new_status
288
 * @return bool
289
 */
290
function wpinv_update_discount_status( $discount = 0, $new_status = 'publish' ) {
291
    $discount = wpinv_get_discount_obj( $discount );
292
    return $discount->update_status( $new_status );
293
}
294
295
/**
296
 * Checks if a discount exists.
297
 * 
298
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
299
 * @return bool
300
 */
301
function wpinv_discount_exists( $discount ) {
302
    $discount = wpinv_get_discount_obj( $discount );
303
    return $discount->exists();
304
}
305
306
function wpinv_is_discount_active( $code_id = null ) {
307
    $discount = wpinv_get_discount(  $code_id );
308
    $return   = false;
309
310
    if ( $discount ) {
311
        if ( wpinv_is_discount_expired( $code_id ) ) {
312
            if( defined( 'DOING_AJAX' ) ) {
313
                wpinv_set_error( 'wpinv-discount-error', __( 'This discount is expired.', 'invoicing' ) );
314
            }
315
        } elseif ( $discount->post_status == 'publish' ) {
316
            $return = true;
317
        } else {
318
            if( defined( 'DOING_AJAX' ) ) {
319
                wpinv_set_error( 'wpinv-discount-error', __( 'This discount is not active.', 'invoicing' ) );
320
            }
321
        }
322
    }
323
324
    return apply_filters( 'wpinv_is_discount_active', $return, $code_id );
325
}
326
327
function wpinv_get_discount_code( $code_id = null ) {
328
    $code = get_post_meta( $code_id, '_wpi_discount_code', true );
329
330
    return apply_filters( 'wpinv_get_discount_code', $code, $code_id );
331
}
332
333
function wpinv_get_discount_start_date( $code_id = null ) {
334
    $start_date = get_post_meta( $code_id, '_wpi_discount_start', true );
335
336
    return apply_filters( 'wpinv_get_discount_start_date', $start_date, $code_id );
337
}
338
339
function wpinv_get_discount_expiration( $code_id = null ) {
340
    $expiration = get_post_meta( $code_id, '_wpi_discount_expiration', true );
341
342
    return apply_filters( 'wpinv_get_discount_expiration', $expiration, $code_id );
343
}
344
345
/**
346
 * Returns the number of maximum number of times a discount can been used.
347
 * 
348
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
349
 * @return int
350
 */
351
function wpinv_get_discount_max_uses( $discount = array() ) {
352
    $discount = wpinv_get_discount_obj( $discount );
353
    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...
354
}
355
356
/**
357
 * Returns the number of times a discount has been used.
358
 * 
359
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
360
 * @return int
361
 */
362
function wpinv_get_discount_uses( $discount = array() ) {
363
    $discount = wpinv_get_discount_obj( $discount );
364
    return (int) $discount->uses;
365
}
366
367
/**
368
 * Returns the minimum invoice amount required to use a discount.
369
 * 
370
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
371
 * @return float
372
 */
373
function wpinv_get_discount_min_total( $discount = array() ) {
374
    $discount = wpinv_get_discount_obj( $discount );
375
    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...
376
}
377
378
/**
379
 * Returns the maximum invoice amount required to use a discount.
380
 * 
381
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
382
 * @return float
383
 */
384
function wpinv_get_discount_max_total( $discount = array() ) {
385
    $discount = wpinv_get_discount_obj( $discount );
386
    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...
387
}
388
389
/**
390
 * Returns a discount's amount.
391
 * 
392
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
393
 * @return float
394
 */
395
function wpinv_get_discount_amount( $discount = array() ) {
396
    $discount = wpinv_get_discount_obj( $discount );
397
    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...
398
}
399
400
/**
401
 * Returns a discount's type.
402
 * 
403
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
404
 * @param bool $name 
405
 * @return string
406
 */
407
function wpinv_get_discount_type( $discount = array(), $name = false ) {
408
    $discount = wpinv_get_discount_obj( $discount );
409
410
    // Are we returning the name or just the type.
411
    if( $name ) {
412
        return $discount->discount_type_name;
0 ignored issues
show
Bug Best Practice introduced by
The property discount_type_name does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
413
    }
414
415
    return $discount->discount_type;
0 ignored issues
show
Bug Best Practice introduced by
The property discount_type does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
416
}
417
418
function wpinv_discount_status( $status ) {
419
    switch( $status ){
420
        case 'expired' :
421
            $name = __( 'Expired', 'invoicing' );
422
            break;
423
        case 'publish' :
424
        case 'active' :
425
            $name = __( 'Active', 'invoicing' );
426
            break;
427
        default :
428
            $name = __( 'Inactive', 'invoicing' );
429
            break;
430
    }
431
    return $name;
432
}
433
434
/**
435
 * Returns a discount's excluded items.
436
 * 
437
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
438
 * @return array
439
 */
440
function wpinv_get_discount_excluded_items( $discount = array() ) {
441
    $discount = wpinv_get_discount_obj( $discount );
442
    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...
443
}
444
445
/**
446
 * Returns a discount's required items.
447
 * 
448
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
449
 * @return array
450
 */
451
function wpinv_get_discount_item_reqs( $discount = array() ) {
452
    $discount = wpinv_get_discount_obj( $discount );
453
    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...
454
}
455
456
function wpinv_get_discount_item_condition( $code_id = 0 ) {
457
    return get_post_meta( $code_id, '_wpi_discount_item_condition', true );
458
}
459
460
function wpinv_is_discount_not_global( $code_id = 0 ) {
461
    return (bool) get_post_meta( $code_id, '_wpi_discount_is_not_global', true );
462
}
463
464
/**
465
 * Checks if a given discount has expired.
466
 * 
467
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
468
 * @return bool
469
 */
470
function wpinv_is_discount_expired( $discount = array() ) {
471
    $discount = wpinv_get_discount_obj( $discount );
472
473
    if ( $discount->is_expired() ) {
474
        $discount->update_status( 'pending' );
475
        return true;
476
    }
477
478
    return false;
479
}
480
481
/**
482
 * Checks if a given discount has started.
483
 * 
484
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
485
 * @return bool
486
 */
487
function wpinv_is_discount_started( $discount = array() ) {
488
    $discount = wpinv_get_discount_obj( $discount );
489
    $started  = $discount->has_started();
490
491
    if( empty( $started ) ) {
492
        wpinv_set_error( 'wpinv-discount-error', __( 'This discount is not active yet.', 'invoicing' ) );
493
    }
494
495
    return $started;
496
}
497
498
/**
499
 * Checks discount dates.
500
 * 
501
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
502
 * @return bool
503
 */
504
function wpinv_check_discount_dates( $discount ) {
505
    $discount = wpinv_get_discount_obj( $discount );
506
    $return   = wpinv_is_discount_started( $discount ) && wpinv_is_discount_expired( $discount );
507
    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...
508
}
509
510
/**
511
 * Checks if a discount is maxed out.
512
 * 
513
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
514
 * @return bool
515
 */
516
function wpinv_is_discount_maxed_out( $discount ) {
517
    $discount    = wpinv_get_discount_obj( $discount );
518
    $maxed_out   = $discount->has_exceeded_limit();
519
520
    if ( $maxed_out ) {
521
        wpinv_set_error( 'wpinv-discount-error', __( 'This discount has reached its maximum usage.', 'invoicing' ) );
522
    }
523
524
    return $maxed_out;
525
} 
526
527
/**
528
 * Checks if an amount meets a discount's minimum amount.
529
 * 
530
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
531
 * @return bool
532
 */
533
function wpinv_discount_is_min_met( $discount ) {
534
    $discount    = wpinv_get_discount_obj( $discount );
535
    $cart_amount = (float)wpinv_get_cart_discountable_subtotal( $discount->ID );
536
    $min_met     = $discount->is_minimum_amount_met( $cart_amount );
537
538
    if ( ! $min_met ) {
539
        wpinv_set_error( 'wpinv-discount-error', sprintf( __( 'Minimum invoice amount should be %s', 'invoicing' ), wpinv_price( wpinv_format_amount( $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...
540
    }
541
542
    return $min_met;
543
}
544
545
/**
546
 * Checks if an amount meets a discount's maximum amount.
547
 * 
548
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
549
 * @return bool
550
 */
551
function wpinv_discount_is_max_met( $discount ) {
552
    $discount    = wpinv_get_discount_obj( $discount );
553
    $cart_amount = (float)wpinv_get_cart_discountable_subtotal( $discount->ID );
554
    $max_met     = $discount->is_maximum_amount_met( $cart_amount );
555
556
    if ( ! $max_met ) {
557
        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...
558
    }
559
560
    return $max_met;
561
}
562
563
/**
564
 * Checks if a discount can only be used once per user.
565
 * 
566
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
567
 * @return bool
568
 */
569
function wpinv_discount_is_single_use( $discount ) {
570
    $discount    = wpinv_get_discount_obj( $discount );
571
    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...
572
}
573
574
/**
575
 * Checks if a discount is recurring.
576
 * 
577
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
578
 * @param int|array|string|WPInv_Discount $code discount data, object, ID or code.
579
 * @return bool
580
 */
581
function wpinv_discount_is_recurring( $discount = 0, $code = 0 ) {
582
583
    if( ! empty( $discount ) ) {
584
        $discount    = wpinv_get_discount_obj( $discount );
585
    } else {
586
        $discount    = wpinv_get_discount_obj( $code );
587
    }
588
    
589
    return $discount->is_recurring;
0 ignored issues
show
Bug Best Practice introduced by
The property is_recurring does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
590
}
591
592
function wpinv_discount_item_reqs_met( $code_id = null ) {
593
    $item_reqs    = wpinv_get_discount_item_reqs( $code_id );
594
    $condition    = wpinv_get_discount_item_condition( $code_id );
595
    $excluded_ps  = wpinv_get_discount_excluded_items( $code_id );
596
    $cart_items   = wpinv_get_cart_contents();
597
    $cart_ids     = $cart_items ? wp_list_pluck( $cart_items, 'id' ) : null;
598
    $ret          = false;
599
600
    if ( empty( $item_reqs ) && empty( $excluded_ps ) ) {
601
        $ret = true;
602
    }
603
604
    // Normalize our data for item requirements, exclusions and cart data
605
    // First absint the items, then sort, and reset the array keys
606
    $item_reqs = array_map( 'absint', $item_reqs );
607
    asort( $item_reqs );
608
    $item_reqs = array_values( $item_reqs );
609
610
    $excluded_ps  = array_map( 'absint', $excluded_ps );
611
    asort( $excluded_ps );
612
    $excluded_ps  = array_values( $excluded_ps );
613
614
    $cart_ids     = array_map( 'absint', $cart_ids );
0 ignored issues
show
Bug introduced by
It seems like $cart_ids can also be of type null; however, parameter $arr1 of array_map() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

614
    $cart_ids     = array_map( 'absint', /** @scrutinizer ignore-type */ $cart_ids );
Loading history...
615
    asort( $cart_ids );
616
    $cart_ids     = array_values( $cart_ids );
617
618
    // Ensure we have requirements before proceeding
619
    if ( !$ret && ! empty( $item_reqs ) ) {
620
        switch( $condition ) {
621
            case 'all' :
622
                // Default back to true
623
                $ret = true;
624
625
                foreach ( $item_reqs as $item_id ) {
626
                    if ( !wpinv_item_in_cart( $item_id ) ) {
627
                        wpinv_set_error( 'wpinv-discount-error', __( 'The item requirements for this discount are not met.', 'invoicing' ) );
628
                        $ret = false;
629
                        break;
630
                    }
631
                }
632
633
                break;
634
635
            default : // Any
636
                foreach ( $item_reqs as $item_id ) {
637
                    if ( wpinv_item_in_cart( $item_id ) ) {
638
                        $ret = true;
639
                        break;
640
                    }
641
                }
642
643
                if( ! $ret ) {
644
                    wpinv_set_error( 'wpinv-discount-error', __( 'The item requirements for this discount are not met.', 'invoicing' ) );
645
                }
646
647
                break;
648
        }
649
    } else {
650
        $ret = true;
651
    }
652
653
    if( ! empty( $excluded_ps ) ) {
654
        // Check that there are items other than excluded ones in the cart
655
        if( $cart_ids == $excluded_ps ) {
656
            wpinv_set_error( 'wpinv-discount-error', __( 'This discount is not valid for the cart contents.', 'invoicing' ) );
657
            $ret = false;
658
        }
659
    }
660
661
    return (bool) apply_filters( 'wpinv_is_discount_item_req_met', $ret, $code_id, $condition );
662
}
663
664
/**
665
 * Checks if a discount has already been used by the user.
666
 * 
667
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
668
 * @param int|string $user The user id, login or email
669
 * @param int|array|string|WPInv_Discount $code_id discount data, object, ID or code.
670
 * @return boll
0 ignored issues
show
Bug introduced by
The type boll was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
671
 */
672
function wpinv_is_discount_used( $discount = array(), $user = '', $code_id = array() ) {
673
    
674
    if( ! empty( $discount ) ) {
675
        $discount = wpinv_get_discount_obj( $discount );
676
    } else {
677
        $discount = wpinv_get_discount_obj( $code_id );
678
    }
679
680
    $is_used = ! $discount->is_valid_for_user( $user );
681
    $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 id does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
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...
682
683
    if( $is_used ) {
684
        wpinv_set_error( 'wpinv-discount-error', __( 'This discount has already been redeemed.', 'invoicing' ) );
685
    }
686
687
    return $is_used();
688
}
689
690
function wpinv_is_discount_valid( $code = '', $user = '', $set_error = true ) {
691
    $return      = false;
692
    $discount_id = wpinv_get_discount_id_by_code( $code );
693
    $user        = trim( $user );
694
695
    if ( wpinv_get_cart_contents() ) {
696
        if ( $discount_id ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $discount_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
697
            if (
698
                wpinv_is_discount_active( $discount_id ) &&
699
                wpinv_check_discount_dates( $discount_id ) &&
700
                !wpinv_is_discount_maxed_out( $discount_id ) &&
701
                !wpinv_is_discount_used( $code, $user, $discount_id ) &&
702
                wpinv_discount_is_min_met( $discount_id ) &&
703
                wpinv_discount_is_max_met( $discount_id ) &&
704
                wpinv_discount_item_reqs_met( $discount_id )
705
            ) {
706
                $return = true;
707
            }
708
        } elseif( $set_error ) {
709
            wpinv_set_error( 'wpinv-discount-error', __( 'This discount is invalid.', 'invoicing' ) );
710
        }
711
    }
712
713
    return apply_filters( 'wpinv_is_discount_valid', $return, $discount_id, $code, $user );
714
}
715
716
function wpinv_get_discount_id_by_code( $code ) {
717
    $discount = wpinv_get_discount_by_code( $code );
718
    if( $discount ) {
719
        return $discount->ID;
720
    }
721
    return false;
722
}
723
724
/**
725
 * Calculates the discounted amount.
726
 * 
727
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
728
 * @param float $base_price The number of usages to increase by
729
 * @return float
730
 */
731
function wpinv_get_discounted_amount( $discount, $base_price ) {
732
    $discount = wpinv_get_discount_obj( $discount );
733
    return $discount->get_discounted_amount( $base_price );
734
}
735
736
/**
737
 * Increases a discount's usage count.
738
 * 
739
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
740
 * @param int $by The number of usages to increase by.
741
 * @return int the new number of uses.
742
 */
743
function wpinv_increase_discount_usage( $discount, $by = 1 ) {
744
    $discount   = wpinv_get_discount_obj( $discount );
745
    return $discount->increase_usage( $by );
0 ignored issues
show
Bug Best Practice introduced by
The expression return $discount->increase_usage($by) returns the type boolean which is incompatible with the documented return type integer.
Loading history...
746
}
747
748
/**
749
 * Decreases a discount's usage count.
750
 * 
751
 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
752
 * @param int $by The number of usages to decrease by.
753
 * @return int the new number of uses.
754
 */
755
function wpinv_decrease_discount_usage( $discount, $by = 1 ) {
756
    $discount   = wpinv_get_discount_obj( $discount );
757
    return $discount->increase_usage( 0 - $by );
0 ignored issues
show
Bug Best Practice introduced by
The expression return $discount->increase_usage(0 - $by) returns the type boolean which is incompatible with the documented return type integer.
Loading history...
758
}
759
760
function wpinv_format_discount_rate( $type, $amount ) {
761
    if ( $type == 'flat' ) {
762
        return wpinv_price( wpinv_format_amount( $amount ) );
763
    } else {
764
        return $amount . '%';
765
    }
766
}
767
768
function wpinv_set_cart_discount( $code = '' ) {    
769
    if ( wpinv_multiple_discounts_allowed() ) {
770
        // Get all active cart discounts
771
        $discounts = wpinv_get_cart_discounts();
772
    } else {
773
        $discounts = false; // Only one discount allowed per purchase, so override any existing
774
    }
775
776
    if ( $discounts ) {
777
        $key = array_search( strtolower( $code ), array_map( 'strtolower', $discounts ) );
778
        if( false !== $key ) {
779
            unset( $discounts[ $key ] ); // Can't set the same discount more than once
780
        }
781
        $discounts[] = $code;
782
    } else {
783
        $discounts = array();
784
        $discounts[] = $code;
785
    }
786
    $discounts = array_values( $discounts );
787
    
788
    $data = wpinv_get_checkout_session();
789
    if ( empty( $data ) ) {
790
        $data = array();
791
    } else {
792
        if ( !empty( $data['invoice_id'] ) && $payment_meta = wpinv_get_invoice_meta( $data['invoice_id'] ) ) {
793
            $payment_meta['user_info']['discount']  = implode( ',', $discounts );
794
            update_post_meta( $data['invoice_id'], '_wpinv_payment_meta', $payment_meta );
795
        }
796
    }
797
    $data['cart_discounts'] = $discounts;
798
    
799
    wpinv_set_checkout_session( $data );
800
    
801
    return $discounts;
802
}
803
804
function wpinv_unset_cart_discount( $code = '' ) {    
805
    $discounts = wpinv_get_cart_discounts();
806
807
    if ( $code && !empty( $discounts ) && in_array( $code, $discounts ) ) {
808
        $key = array_search( $code, $discounts );
809
        unset( $discounts[ $key ] );
810
            
811
        $data = wpinv_get_checkout_session();
812
        $data['cart_discounts'] = $discounts;
813
        if ( !empty( $data['invoice_id'] ) && $payment_meta = wpinv_get_invoice_meta( $data['invoice_id'] ) ) {
814
            $payment_meta['user_info']['discount']  = !empty( $discounts ) ? implode( ',', $discounts ) : '';
815
            update_post_meta( $data['invoice_id'], '_wpinv_payment_meta', $payment_meta );
816
        }
817
        
818
        wpinv_set_checkout_session( $data );
819
    }
820
821
    return $discounts;
822
}
823
824
function wpinv_unset_all_cart_discounts() {
825
    $data = wpinv_get_checkout_session();
826
    
827
    if ( !empty( $data ) && isset( $data['cart_discounts'] ) ) {
828
        unset( $data['cart_discounts'] );
829
        
830
         wpinv_set_checkout_session( $data );
831
         return true;
832
    }
833
    
834
    return false;
835
}
836
837
function wpinv_get_cart_discounts( $items = array() ) {
0 ignored issues
show
Unused Code introduced by
The parameter $items is not used and could be removed. ( Ignorable by Annotation )

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

837
function wpinv_get_cart_discounts( /** @scrutinizer ignore-unused */ $items = array() ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
838
    $session = wpinv_get_checkout_session();
839
    
840
    $discounts = !empty( $session['cart_discounts'] ) ? $session['cart_discounts'] : false;
841
    return $discounts;
842
}
843
844
function wpinv_cart_has_discounts( $items = array() ) {
845
    $ret = false;
846
847
    if ( wpinv_get_cart_discounts( $items ) ) {
848
        $ret = true;
849
    }
850
    
851
    /*
852
    $invoice = wpinv_get_invoice_cart();
853
    if ( !empty( $invoice ) && ( $invoice->get_discount() > 0 || $invoice->get_discount_code() ) ) {
854
        $ret = true;
855
    }
856
    */
857
858
    return apply_filters( 'wpinv_cart_has_discounts', $ret );
859
}
860
861
function wpinv_get_cart_discounted_amount( $items = array(), $discounts = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $discounts is not used and could be removed. ( Ignorable by Annotation )

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

861
function wpinv_get_cart_discounted_amount( $items = array(), /** @scrutinizer ignore-unused */ $discounts = false ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
862
    $amount = 0.00;
863
    $items  = !empty( $items ) ? $items : wpinv_get_cart_content_details();
864
865
    if ( $items ) {
866
        $discounts = wp_list_pluck( $items, 'discount' );
867
868
        if ( is_array( $discounts ) ) {
0 ignored issues
show
introduced by
The condition is_array($discounts) is always true.
Loading history...
869
            $discounts = array_map( 'floatval', $discounts );
870
            $amount    = array_sum( $discounts );
871
        }
872
    }
873
874
    return apply_filters( 'wpinv_get_cart_discounted_amount', $amount );
875
}
876
877
function wpinv_get_cart_items_discount_amount( $items = array(), $discount = false ) {
878
    $items  = !empty( $items ) ? $items : wpinv_get_cart_content_details();
879
    
880
    if ( empty( $discount ) || empty( $items ) ) {
881
        return 0;
882
    }
883
884
    $amount = 0;
885
    
886
    foreach ( $items as $item ) {
887
        $amount += wpinv_get_cart_item_discount_amount( $item, $discount );
888
    }
889
    
890
    $amount = wpinv_round_amount( $amount );
891
892
    return $amount;
893
}
894
895
function wpinv_get_cart_item_discount_amount( $item = array(), $discount = false ) {
896
    global $wpinv_is_last_cart_item, $wpinv_flat_discount_total;
897
    
898
    $amount = 0;
899
900
    if ( empty( $item ) || empty( $item['id'] ) ) {
901
        return $amount;
902
    }
903
904
    if ( empty( $item['quantity'] ) ) {
905
        return $amount;
906
    }
907
908
    if ( empty( $item['options'] ) ) {
909
        $item['options'] = array();
910
    }
911
912
    $price            = wpinv_get_cart_item_price( $item['id'], $item, $item['options'] );
913
    $discounted_price = $price;
914
915
    $discounts = false === $discount ? wpinv_get_cart_discounts() : $discount;
916
    if ( empty( $discounts ) ) {
917
        return $amount;
918
    }
919
920
    if ( $discounts ) {
921
        if ( is_array( $discounts ) ) {
922
            $discounts = array_values( $discounts );
923
        } else {
924
            $discounts = explode( ',', $discounts );
925
        }
926
    }
927
928
    if( $discounts ) {
929
        foreach ( $discounts as $discount ) {
930
            $code_id = wpinv_get_discount_id_by_code( $discount );
931
932
            // Check discount exists
933
            if( ! $code_id ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $code_id of type false|integer is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
934
                continue;
935
            }
936
937
            $reqs           = wpinv_get_discount_item_reqs( $code_id );
938
            $excluded_items = wpinv_get_discount_excluded_items( $code_id );
939
940
            // Make sure requirements are set and that this discount shouldn't apply to the whole cart
941
            if ( !empty( $reqs ) && wpinv_is_discount_not_global( $code_id ) ) {
942
                foreach ( $reqs as $item_id ) {
943
                    if ( $item_id == $item['id'] && ! in_array( $item['id'], $excluded_items ) ) {
944
                        $discounted_price -= $price - wpinv_get_discounted_amount( $discount, $price );
945
                    }
946
                }
947
            } else {
948
                // This is a global cart discount
949
                if ( !in_array( $item['id'], $excluded_items ) ) {
950
                    if ( 'flat' === wpinv_get_discount_type( $code_id ) ) {
951
                        $items_subtotal    = 0.00;
952
                        $cart_items        = wpinv_get_cart_contents();
953
                        
954
                        foreach ( $cart_items as $cart_item ) {
955
                            if ( ! in_array( $cart_item['id'], $excluded_items ) ) {
956
                                $options = !empty( $cart_item['options'] ) ? $cart_item['options'] : array();
957
                                $item_price      = wpinv_get_cart_item_price( $cart_item['id'], $cart_item, $options );
958
                                $items_subtotal += $item_price * $cart_item['quantity'];
959
                            }
960
                        }
961
962
                        $subtotal_percent  = ( ( $price * $item['quantity'] ) / $items_subtotal );
963
                        $code_amount       = wpinv_get_discount_amount( $code_id );
964
                        $discounted_amount = $code_amount * $subtotal_percent;
965
                        $discounted_price -= $discounted_amount;
966
967
                        $wpinv_flat_discount_total += round( $discounted_amount, wpinv_currency_decimal_filter() );
968
969
                        if ( $wpinv_is_last_cart_item && $wpinv_flat_discount_total < $code_amount ) {
970
                            $adjustment = $code_amount - $wpinv_flat_discount_total;
971
                            $discounted_price -= $adjustment;
972
                        }
973
                    } else {
974
                        $discounted_price -= $price - wpinv_get_discounted_amount( $discount, $price );
975
                    }
976
                }
977
            }
978
        }
979
980
        $amount = ( $price - apply_filters( 'wpinv_get_cart_item_discounted_amount', $discounted_price, $discounts, $item, $price ) );
981
982
        if ( 'flat' !== wpinv_get_discount_type( $code_id ) ) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $code_id seems to be defined by a foreach iteration on line 929. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
983
            $amount = $amount * $item['quantity'];
984
        }
985
    }
986
987
    return $amount;
988
}
989
990
function wpinv_cart_discounts_html( $items = array() ) {
991
    echo wpinv_get_cart_discounts_html( $items );
992
}
993
994
function wpinv_get_cart_discounts_html( $items = array(), $discounts = false ) {
995
    global $wpi_cart_columns;
996
    
997
    $items  = !empty( $items ) ? $items : wpinv_get_cart_content_details();
998
    
999
    if ( !$discounts ) {
1000
        $discounts = wpinv_get_cart_discounts( $items );
1001
    }
1002
1003
    if ( !$discounts ) {
1004
        return;
1005
    }
1006
    
1007
    $discounts = is_array( $discounts ) ? $discounts : array( $discounts );
1008
    
1009
    $html = '';
1010
1011
    foreach ( $discounts as $discount ) {
1012
        $discount_id    = wpinv_get_discount_id_by_code( $discount );
1013
        $discount_value = wpinv_get_discount_amount( $discount_id );
1014
        $rate           = wpinv_format_discount_rate( wpinv_get_discount_type( $discount_id ), $discount_value );
1015
        $amount         = wpinv_get_cart_items_discount_amount( $items, $discount );
1016
        $remove_btn     = '<a title="' . esc_attr__( 'Remove discount', 'invoicing' ) . '" data-code="' . $discount . '" data-value="' . $discount_value . '" class="wpi-discount-remove" href="javascript:void(0);">[<i class="fa fa-times" aria-hidden="true"></i>]</a> ';
1017
        
1018
        $html .= '<tr class="wpinv_cart_footer_row wpinv_cart_discount_row">';
1019
        ob_start();
1020
        do_action( 'wpinv_checkout_table_discount_first', $items );
1021
        $html .= ob_get_clean();
1022
        $html .= '<td class="wpinv_cart_discount_label text-right" colspan="' . $wpi_cart_columns . '">' . $remove_btn . '<strong>' . wpinv_cart_discount_label( $discount, $rate, false ) . '</strong></td><td class="wpinv_cart_discount text-right"><span data-discount="' . $amount . '" class="wpinv_cart_discount_amount">&ndash;' . wpinv_price( wpinv_format_amount( $amount ) ) . '</span></td>';
1023
        ob_start();
1024
        do_action( 'wpinv_checkout_table_discount_last', $items );
1025
        $html .= ob_get_clean();
1026
        $html .= '</tr>';
1027
    }
1028
1029
    return apply_filters( 'wpinv_get_cart_discounts_html', $html, $discounts, $rate );
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $rate seems to be defined by a foreach iteration on line 1011. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
1030
}
1031
1032
function wpinv_display_cart_discount( $formatted = false, $echo = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $formatted is not used and could be removed. ( Ignorable by Annotation )

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

1032
function wpinv_display_cart_discount( /** @scrutinizer ignore-unused */ $formatted = false, $echo = false ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1033
    $discounts = wpinv_get_cart_discounts();
1034
1035
    if ( empty( $discounts ) ) {
1036
        return false;
1037
    }
1038
1039
    $discount_id  = wpinv_get_discount_id_by_code( $discounts[0] );
1040
    $amount       = wpinv_format_discount_rate( wpinv_get_discount_type( $discount_id ), wpinv_get_discount_amount( $discount_id ) );
1041
1042
    if ( $echo ) {
1043
        echo $amount;
1044
    }
1045
1046
    return $amount;
1047
}
1048
1049
function wpinv_remove_cart_discount() {
1050
    if ( !isset( $_GET['discount_id'] ) || ! isset( $_GET['discount_code'] ) ) {
1051
        return;
1052
    }
1053
1054
    do_action( 'wpinv_pre_remove_cart_discount', absint( $_GET['discount_id'] ) );
1055
1056
    wpinv_unset_cart_discount( urldecode( $_GET['discount_code'] ) );
1057
1058
    do_action( 'wpinv_post_remove_cart_discount', absint( $_GET['discount_id'] ) );
1059
1060
    wp_redirect( wpinv_get_checkout_uri() ); wpinv_die();
0 ignored issues
show
Bug introduced by
It seems like wpinv_get_checkout_uri() can also be of type false; however, parameter $location of wp_redirect() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1060
    wp_redirect( /** @scrutinizer ignore-type */ wpinv_get_checkout_uri() ); wpinv_die();
Loading history...
1061
}
1062
add_action( 'wpinv_remove_cart_discount', 'wpinv_remove_cart_discount' );
1063
1064
function wpinv_maybe_remove_cart_discount( $cart_key = 0 ) {
0 ignored issues
show
Unused Code introduced by
The parameter $cart_key is not used and could be removed. ( Ignorable by Annotation )

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

1064
function wpinv_maybe_remove_cart_discount( /** @scrutinizer ignore-unused */ $cart_key = 0 ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1065
    $discounts = wpinv_get_cart_discounts();
1066
1067
    if ( !$discounts ) {
1068
        return;
1069
    }
1070
1071
    foreach ( $discounts as $discount ) {
1072
        if ( !wpinv_is_discount_valid( $discount ) ) {
1073
            wpinv_unset_cart_discount( $discount );
1074
        }
1075
    }
1076
}
1077
add_action( 'wpinv_post_remove_from_cart', 'wpinv_maybe_remove_cart_discount' );
1078
1079
function wpinv_multiple_discounts_allowed() {
1080
    $ret = wpinv_get_option( 'allow_multiple_discounts', false );
1081
    return (bool) apply_filters( 'wpinv_multiple_discounts_allowed', $ret );
1082
}
1083
1084
function wpinv_get_discount_label( $code, $echo = true ) {
1085
    $label = wp_sprintf( __( 'Discount%1$s', 'invoicing' ), ( $code != '' && $code != 'none' ? ' (<code>' . $code . '</code>)': '' ) );
1086
    $label = apply_filters( 'wpinv_get_discount_label', $label, $code );
1087
1088
    if ( $echo ) {
1089
        echo $label;
1090
    } else {
1091
        return $label;
1092
    }
1093
}
1094
1095
function wpinv_cart_discount_label( $code, $rate, $echo = true ) {
1096
    $label = wp_sprintf( __( 'Discount: %s', 'invoicing' ), $code );
1097
    $label = apply_filters( 'wpinv_cart_discount_label', $label, $code, $rate );
1098
1099
    if ( $echo ) {
1100
        echo $label;
1101
    } else {
1102
        return $label;
1103
    }
1104
}
1105
1106
function wpinv_check_delete_discount( $check, $post ) {
1107
    if ( $post->post_type == 'wpi_discount' && wpinv_get_discount_uses( $post->ID ) > 0 ) {
1108
        return true;
1109
    }
1110
    
1111
    return $check;
1112
}
1113
add_filter( 'pre_delete_post', 'wpinv_check_delete_discount', 10, 2 );
1114
1115
function wpinv_checkout_form_validate_discounts() {
1116
    global $wpi_checkout_id;
1117
    
1118
    $discounts = wpinv_get_cart_discounts();
1119
    
1120
    if ( !empty( $discounts ) ) {
1121
        $invalid = false;
1122
        
1123
        foreach ( $discounts as $key => $code ) {
1124
            if ( !wpinv_is_discount_valid( $code, (int)wpinv_get_user_id( $wpi_checkout_id ) ) ) {
1125
                $invalid = true;
1126
                
1127
                wpinv_unset_cart_discount( $code );
1128
            }
1129
        }
1130
        
1131
        if ( $invalid ) {
1132
            $errors = wpinv_get_errors();
1133
            $error  = !empty( $errors['wpinv-discount-error'] ) ? $errors['wpinv-discount-error'] . ' ' : '';
1134
            $error  .= __( 'The discount has been removed from cart.', 'invoicing' );
1135
            wpinv_set_error( 'wpinv-discount-error', $error );
1136
            
1137
            wpinv_recalculate_tax( true );
1138
        }
1139
    }
1140
}
1141
add_action( 'wpinv_before_checkout_form', 'wpinv_checkout_form_validate_discounts', -10 );
1142
1143
function wpinv_discount_amount() {
1144
    $output = 0.00;
1145
    
1146
    return apply_filters( 'wpinv_discount_amount', $output );
1147
}