Passed
Push — master ( 2d8bbf...270aff )
by Brian
05:20 queued 12s
created

wpinv_get_vat_same_country_rule()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 3
eloc 5
nc 3
nop 1
dl 0
loc 9
rs 10
c 1
b 1
f 0
1
<?php
2
/**
3
 * Contains the tax functions.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * Returns an array of eu states.
11
 *
12
 * @return array
13
 */
14
function getpaid_get_eu_states() {
15
    return wpinv_get_data( 'eu-states' );
16
}
17
18
/**
19
 * Checks if a given country is an EU state.
20
 *
21
 * @return bool
22
 */
23
function getpaid_is_eu_state( $country ) {
24
    return ! empty( $country ) && in_array( strtoupper( $country ), getpaid_get_eu_states() ) ? true : false;
25
}
26
27
/**
28
 * Returns an array of gst states.
29
 *
30
 * @return array
31
 */
32
function getpaid_get_gst_states() {
33
    return array( 'AU', 'NZ', 'CA', 'CN' );
34
}
35
36
/**
37
 * Checks if a given country is GST country.
38
 *
39
 * @return bool
40
 */
41
function getpaid_is_gst_country( $country ) {
42
    return ! empty( $country ) && in_array( strtoupper( $country ), getpaid_get_gst_states() ) ? true : false;
43
}
44
45
/**
46
 * Checks whether or not taxes are enabled.
47
 *
48
 * @return bool
49
 */
50
function wpinv_use_taxes() {
51
52
    $ret = wpinv_get_option( 'enable_taxes', false );
53
    return (bool) apply_filters( 'wpinv_use_taxes', ! empty( $ret ) );
54
55
}
56
57
/**
58
 * Checks whether or not an invoice is taxable.
59
 *
60
 * @param WPInv_Invoice $invoice
61
 * @return bool
62
 */
63
function wpinv_is_invoice_taxable( $invoice ) {
64
    return $invoice->is_taxable();
65
}
66
67
/**
68
 * Checks whether or not a given country is taxable.
69
 *
70
 * @param string $country
71
 * @return bool
72
 */
73
function wpinv_is_country_taxable( $country ) {
74
    $is_eu     = getpaid_is_eu_state( $country );
75
    $is_exempt = ! $is_eu && wpinv_is_base_country( $country ) && wpinv_same_country_exempt_vat();
76
77
    return (bool) apply_filters( 'wpinv_is_country_taxable', ! $is_exempt, $country );
78
79
}
80
81
/**
82
 * Checks whether or not an item is taxable.
83
 *
84
 * @param WPInv_Item|GetPaid_Form_Item $item
85
 * @return bool
86
 */
87
function wpinv_is_item_taxable( $item ) {
88
    return '_exempt' != $item->get_vat_rule();
89
}
90
91
/**
92
 * Checks whether or not taxes are calculated based on the store address.
93
 *
94
 * @return bool
95
 */
96
function wpinv_use_store_address_as_tax_base( $tax_rule = false ) {
97
    $use_base = wpinv_get_option( 'tax_base', 'billing' ) === 'base';
98
99
    if ( $tax_rule ) {
100
        $rules    = getpaid_get_tax_rules( 'tax_base' );
101
        $use_base = isset( $rules[ $tax_rule ] ) ? 'base' === $rules[ $tax_rule ] : $use_base;
102
    }
103
104
    return (bool) apply_filters( 'wpinv_use_store_address_as_tax_base', $use_base, $tax_rule );
105
}
106
107
/**
108
 * Retrieves the same country rule.
109
 *
110
 * @return bool
111
 */
112
function wpinv_get_vat_same_country_rule( $tax_rule = false ) {
113
    $rule = wpinv_get_option( 'vat_same_country_rule', 'vat_too' );
114
115
    if ( $tax_rule ) {
116
        $rules = getpaid_get_tax_rules( 'same_country_rule' );
117
        $rule  = isset( $rules[ $tax_rule ] ) ? $rules[ $tax_rule ] : $rule;
118
    }
119
120
    return (bool) apply_filters( 'wpinv_get_vat_same_country_rule', $rule, $tax_rule );
121
}
122
123
/**
124
 * Checks whether or not prices include tax.
125
 *
126
 * @return bool
127
 */
128
function wpinv_prices_include_tax() {
129
    $is_inclusive = wpinv_get_option( 'prices_include_tax', 'no' ) == 'yes';
130
    return (bool) apply_filters( 'wpinv_prices_include_tax', $is_inclusive );
131
}
132
133
/**
134
 * Checks whether we should round per rate or per subtotal
135
 *
136
 * @return bool
137
 */
138
function wpinv_round_tax_per_tax_rate() {
139
    $subtotal_rounding = wpinv_get_option( 'tax_subtotal_rounding', 1 );
140
    return (bool) apply_filters( 'wpinv_round_tax_per_tax_rate', empty( $subtotal_rounding ) );
141
}
142
143
/**
144
 * Checks whether we should display individual tax rates.
145
 *
146
 * @return bool
147
 */
148
function wpinv_display_individual_tax_rates() {
149
    $individual = wpinv_get_option( 'tax_display_totals', 'single' ) == 'individual';
150
    return (bool) apply_filters( 'wpinv_display_individual_tax_rates', $individual );
151
}
152
153
/**
154
 * Retrieves the default tax rate.
155
 *
156
 * @return float
157
 */
158
function wpinv_get_default_tax_rate() {
159
    $rate = wpinv_get_option( 'tax_rate', 0 );
160
    return (float) apply_filters( 'wpinv_get_default_tax_rate', floatval( $rate ) );
161
}
162
163
/**
164
 * Checks if we should exempt same country vat.
165
 *
166
 * @return bool
167
 */
168
function wpinv_same_country_exempt_vat() {
169
    return 'no' == wpinv_get_option( 'vat_same_country_rule', 'vat_too' );
170
}
171
172
/**
173
 * Retrieves an array of all tax rates.
174
 *
175
 * @return array
176
 */
177
function wpinv_get_tax_rates() {
178
    return GetPaid_Tax::get_all_tax_rates();
179
}
180
181
/**
182
 * Retrieves an item's tax rates.
183
 *
184
 * @param WPInv_Item|GetPaid_Form_Item $item
185
 * @param string $country
186
 * @param string $state
187
 * @return array
188
 */
189
function getpaid_get_item_tax_rates( $item, $country = '', $state = '' ) {
190
191
    // Abort if the item is not taxable.
192
    if ( ! wpinv_is_item_taxable( $item ) ) {
193
        return array();
194
    }
195
196
    // Maybe use the store address.
197
    if ( wpinv_use_store_address_as_tax_base( $item->get_vat_rule() ) ) {
198
        $country = wpinv_get_default_country();
199
        $state   = wpinv_get_default_state();
200
    }
201
202
    // Retrieve tax rates.
203
    $tax_rates = GetPaid_Tax::get_address_tax_rates( $country, $state );
204
205
    // Fallback to the default tax rates if non were found.
206
    if ( empty( $tax_rates ) ) {
207
        $tax_rates = GetPaid_Tax::get_default_tax_rates();
208
    }
209
210
    return apply_filters( 'getpaid_get_item_tax_rates', $tax_rates, $item, $country, $state );
211
}
212
213
/**
214
 * Filters an item's tax rate.
215
 *
216
 * @param WPInv_Item|GetPaid_Form_Item $item
217
 * @param array $rates
218
 * @return array
219
 */
220
function getpaid_filter_item_tax_rates( $item, $rates ) {
221
222
    $tax_class = $item->get_vat_class();
223
224
    foreach ( $rates as $i => $rate ) {
225
226
        if ( $tax_class == '_reduced' ) {
227
            $rates[ $i ]['rate'] = empty( $rate['reduced_rate'] ) ? 0 : $rate['reduced_rate'];
228
        }
229
230
        if ( $tax_class == '_exempt' ) {
231
            $rates[ $i ]['rate'] = 0;
232
        }
233
}
234
235
    return apply_filters( 'getpaid_filter_item_tax_rates', $rates, $item );
236
}
237
238
/**
239
 * Retrieves an item's taxes.
240
 *
241
 * @param float $amount
242
 * @param array $rates
243
 * @return array
244
 */
245
function getpaid_calculate_item_taxes( $amount, $rates ) {
246
247
    $is_inclusive = wpinv_prices_include_tax();
248
    $taxes        = GetPaid_Tax::calc_tax( $amount, $rates, $is_inclusive );
249
250
    return apply_filters( 'getpaid_calculate_taxes', $taxes, $amount, $rates );
251
}
252
253
/**
254
 * Prepares an item's tax.
255
 *
256
 * @param WPInv_Item|GetPaid_Form_Item $item
257
 * @param string $tax_name
258
 * @param float $tax_amount
259
 * @param float $recurring_tax_amount
260
 * @return array
261
 */
262
function getpaid_prepare_item_tax( $item, $tax_name, $tax_amount, $recurring_tax_amount ) {
263
264
    $initial_tax   = $tax_amount;
265
	$recurring_tax = 0;
266
267
    if ( $item->is_recurring() ) {
268
		$recurring_tax = $recurring_tax_amount;
269
	}
270
271
	return array(
272
		'name'          => sanitize_text_field( $tax_name ),
273
		'initial_tax'   => $initial_tax,
274
		'recurring_tax' => $recurring_tax,
275
    );
276
277
}
278
279
/**
280
 * Sanitizes a VAT number.
281
 *
282
 * @param string $vat_number
283
 * @return string
284
 */
285
function wpinv_sanitize_vat_number( $vat_number ) {
286
    return str_replace( array( ' ', '.', '-', '_', ',' ), '', strtoupper( trim( $vat_number ) ) );
287
}
288
289
/**
290
 * Validates a vat number via a REGEX.
291
 *
292
 * @param string $vat_number
293
 * @return bool
294
 */
295
function wpinv_regex_validate_vat_number( $vat_number ) {
296
297
    $country    = substr( $vat_number, 0, 2 );
298
    $vatin      = substr( $vat_number, 2 );
299
    $regexes    = wpinv_get_data( 'vat-number-regexes' );
300
301
    if ( isset( $regexes[ $country ] ) ) {
302
303
        $regex = $regexes[ $country ];
304
        $regex = '/^(?:' . $regex . ')$/';
305
        return 1 === preg_match( $regex, $vatin );
306
307
    }
308
309
    // Not an EU state, use filters to validate the number.
310
    return apply_filters( 'wpinv_regex_validate_vat_number', true, $vat_number );
311
}
312
313
/**
314
 * Validates a vat number via a VIES.
315
 *
316
 * @param string $vat_number
317
 * @return bool
318
 */
319
function wpinv_vies_validate_vat_number( $vat_number ) {
320
321
    $country    = substr( $vat_number, 0, 2 );
322
    $vatin      = substr( $vat_number, 2 );
323
324
    $url        = add_query_arg(
325
        array(
326
            'ms'  => urlencode( $country ),
327
            'iso' => urlencode( $country ),
328
            'vat' => urlencode( $vatin ),
329
        ),
330
        'http://ec.europa.eu/taxation_customs/vies/viesquer.do'
331
    );
332
333
    $response   = wp_remote_get( $url );
334
    $response   = wp_remote_retrieve_body( $response );
335
336
    // Fallback gracefully if the VIES website is down.
337
    if ( empty( $response ) ) {
338
        return true;
339
    }
340
341
    return 1 !== preg_match( '/invalid VAT number/i', $response );
342
343
}
344
345
/**
346
 * Validates a vat number.
347
 *
348
 * @param string $vat_number
349
 * @param string $country
350
 * @return bool
351
 */
352
function wpinv_validate_vat_number( $vat_number, $country ) {
353
354
    // In case the vat number does not have a country code...
355
    $vat_number = wpinv_sanitize_vat_number( $vat_number );
356
    $_country   = substr( $vat_number, 0, 2 );
357
    $_country   = $_country == wpinv_country_name( $_country );
358
359
    if ( $_country ) {
360
        $vat_number = strtoupper( $country ) . $vat_number;
361
    }
362
363
    return wpinv_regex_validate_vat_number( $vat_number ) && wpinv_vies_validate_vat_number( $vat_number );
364
}
365
366
/**
367
 * Checks whether or not we should validate vat numbers.
368
 *
369
 * @return bool
370
 */
371
function wpinv_should_validate_vat_number() {
372
    $validate = wpinv_get_option( 'validate_vat_number' );
373
	return ! empty( $validate );
374
}
375
376
function wpinv_sales_tax_for_year( $year = null ) {
377
    return wpinv_price( wpinv_get_sales_tax_for_year( $year ) );
378
}
379
380
function wpinv_get_sales_tax_for_year( $year = null ) {
381
    global $wpdb;
382
383
    // Start at zero
384
    $tax = 0;
385
386
    if ( ! empty( $year ) ) {
387
        $args = array(
388
            'post_type'      => 'wpi_invoice',
389
            'post_status'    => array( 'publish' ),
390
            'posts_per_page' => -1,
391
            'year'           => $year,
392
            'fields'         => 'ids',
393
        );
394
395
        $payments    = get_posts( $args );
396
        $payment_ids = implode( ',', $payments );
397
398
        if ( count( $payments ) > 0 ) {
399
            $sql = "SELECT SUM( meta_value ) FROM $wpdb->postmeta WHERE meta_key = '_wpinv_tax' AND post_id IN( $payment_ids )";
400
            $tax = $wpdb->get_var( $sql );
401
        }
402
}
403
404
    return apply_filters( 'wpinv_get_sales_tax_for_year', $tax, $year );
405
}
406
407
function wpinv_is_cart_taxed() {
408
    return wpinv_use_taxes();
409
}
410
411
function wpinv_prices_show_tax_on_checkout() {
412
    return false; // TODO
413
    $ret = ( wpinv_get_option( 'checkout_include_tax', false ) == 'yes' && wpinv_use_taxes() );
0 ignored issues
show
Unused Code introduced by
$ret = wpinv_get_option(...s' && wpinv_use_taxes() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
414
415
    return apply_filters( 'wpinv_taxes_on_prices_on_checkout', $ret );
416
}
417
418
function wpinv_display_tax_rate() {
419
    $ret = wpinv_use_taxes() && wpinv_get_option( 'display_tax_rate', false );
420
421
    return apply_filters( 'wpinv_display_tax_rate', $ret );
422
}
423
424
function wpinv_cart_needs_tax_address_fields() {
425
    if ( ! wpinv_is_cart_taxed() ) {
426
        return false;
427
    }
428
429
    return ! did_action( 'wpinv_after_cc_fields', 'wpinv_default_cc_address_fields' );
0 ignored issues
show
Unused Code introduced by
The call to did_action() has too many arguments starting with 'wpinv_default_cc_address_fields'. ( Ignorable by Annotation )

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

429
    return ! /** @scrutinizer ignore-call */ did_action( 'wpinv_after_cc_fields', 'wpinv_default_cc_address_fields' );

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...
430
}
431
432
function wpinv_item_is_tax_exclusive( $item_id = 0 ) {
433
    $ret = (bool)get_post_meta( $item_id, '_wpinv_tax_exclusive', false );
434
    return apply_filters( 'wpinv_is_tax_exclusive', $ret, $item_id );
435
}
436
437
function wpinv_currency_decimal_filter( $decimals = 2 ) {
438
    $currency = wpinv_get_currency();
439
440
    switch ( $currency ) {
441
        case 'RIAL':
442
        case 'JPY':
443
        case 'TWD':
444
        case 'HUF':
445
            $decimals = 0;
446
            break;
447
    }
448
449
    return apply_filters( 'wpinv_currency_decimal_count', $decimals, $currency );
450
}
451
452
function wpinv_tax_amount() {
453
    $output = 0.00;
454
455
    return apply_filters( 'wpinv_tax_amount', $output );
456
}
457
458
/**
459
 * Filters the VAT rules to ensure that each item has a VAT rule.
460
 *
461
 * @param string|bool|null $vat_rule
462
 */
463
function getpaid_filter_vat_rule( $vat_rule ) {
464
465
    if ( empty( $vat_rule ) ) {
466
        return 'digital';
467
    }
468
469
    return $vat_rule;
470
}
471
add_filter( 'wpinv_get_item_vat_rule', 'getpaid_filter_vat_rule' );
472
473
/**
474
 * Filters the VAT class to ensure that each item has a VAT class.
475
 *
476
 * @param string|bool|null $vat_rule
477
 */
478
function getpaid_filter_vat_class( $vat_class ) {
479
    return empty( $vat_class ) ? '_standard' : $vat_class;
480
}
481
add_filter( 'wpinv_get_item_vat_class', 'getpaid_filter_vat_class' );
482
483
/**
484
 * Returns a list of all tax classes.
485
 *
486
 * @return array
487
 */
488
function getpaid_get_tax_classes() {
489
490
    return apply_filters(
491
        'getpaid_tax_classes',
492
        array(
493
            '_standard' => __( 'Standard Tax Rate', 'invoicing' ),
494
            '_reduced'  => __( 'Reduced Tax Rate', 'invoicing' ),
495
            '_exempt'   => __( 'Tax Exempt', 'invoicing' ),
496
        )
497
    );
498
499
}
500
501
/**
502
 * Returns a list of all tax rules.
503
 *
504
 * @return array
505
 */
506
function getpaid_get_tax_rules( $return = 'label' ) {
507
    return wp_list_pluck( GetPaid_Tax::get_all_tax_rules(), $return, 'key' );
508
}
509
510
/**
511
 * Returns the label of a tax class.
512
 *
513
 * @param string $tax_class
514
 * @return string
515
 */
516
function getpaid_get_tax_class_label( $tax_class ) {
517
518
    $classes = getpaid_get_tax_classes();
519
520
    if ( isset( $classes[ $tax_class ] ) ) {
521
        return sanitize_text_field( $classes[ $tax_class ] );
522
    }
523
524
    return sanitize_text_field( $tax_class );
525
526
}
527
528
/**
529
 * Returns the label of a tax rule.
530
 *
531
 * @param string $tax_rule
532
 * @return string
533
 */
534
function getpaid_get_tax_rule_label( $tax_rule ) {
535
536
    $rules = getpaid_get_tax_rules();
537
538
    if ( isset( $rules[ $tax_rule ] ) ) {
539
        return sanitize_text_field( $rules[ $tax_rule ] );
540
    }
541
542
    return sanitize_text_field( $tax_rule );
543
544
}
545
546
/**
547
 * Returns the taxable amount
548
 *
549
 * @param GetPaid_Form_Item $item
550
 * @param string $recurring
551
 * @return string
552
 */
553
function getpaid_get_taxable_amount( $item, $recurring = false ) {
554
555
    $taxable_amount  = $recurring ? $item->get_recurring_sub_total() : $item->get_sub_total();
556
    $taxable_amount -= $recurring ? $item->recurring_item_discount : $item->item_discount;
557
    $taxable_amount  = max( 0, $taxable_amount );
558
    return apply_filters( 'getpaid_taxable_amount', $taxable_amount, $item, $recurring );
559
560
}
561