Passed
Pull Request — master (#450)
by Brian
04:52
created

wpinv_is_invoice_taxable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 2
rs 10
1
<?php
2
/**
3
 * Contains the tax functions.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * Returns the tax class objet.
11
 * 
12
 * @return WPInv_EUVat
13
 */
14
function getpaid_tax() {
15
    return getpaid()->tax;
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 WPInv_EUVat::is_eu_state( $country );
25
}
26
27
/**
28
 * Checks if a given country is GST country.
29
 * 
30
 * @return bool
31
 */
32
function getpaid_is_gst_country( $country ) {
33
    return WPInv_EUVat::is_gst_country( $country );
34
}
35
36
/**
37
 * Returns the vat name.
38
 * 
39
 * @return string
40
 */
41
function getpaid_vat_name() {
42
    return getpaid_tax()->get_vat_name();
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 an item is taxable.
69
 *
70
 * @param WPInv_Item|GetPaid_Form_Item $item
71
 * @return bool
72
 */
73
function wpinv_is_item_taxable( $item ) {
74
    return '_exempt' != $item->get_vat_rule();
75
}
76
77
/**
78
 * Checks whether or not taxes are calculated based on the store address.
79
 *
80
 * @return bool
81
 */
82
function wpinv_use_store_address_as_tax_base() {
83
    $use_base = wpinv_get_option( 'tax_base', 'billing' ) == 'base';
84
    return (bool) apply_filters( 'wpinv_use_store_address_as_tax_base', $use_base );
85
}
86
87
/**
88
 * Checks whether or not prices include tax.
89
 *
90
 * @return bool
91
 */
92
function wpinv_prices_include_tax() {
93
    $is_inclusive = wpinv_get_option( 'prices_include_tax', 'no' ) == 'yes';
94
    return (bool) apply_filters( 'wpinv_prices_include_tax', $is_inclusive );
95
}
96
97
/**
98
 * Checks whether we should round per rate or per subtotal
99
 *
100
 * @return bool
101
 */
102
function wpinv_round_tax_per_tax_rate() {
103
    $subtotal_rounding = wpinv_get_option( 'tax_subtotal_rounding', 1 );
104
    return (bool) apply_filters( 'wpinv_round_tax_per_tax_rate', empty( $subtotal_rounding ) );
105
}
106
107
/**
108
 * Checks whether we should display individual tax rates.
109
 *
110
 * @return bool
111
 */
112
function wpinv_display_individual_tax_rates() {
113
    $individual = wpinv_get_option( 'tax_display_totals', 'single' ) == 'individual';
114
    return (bool) apply_filters( 'wpinv_display_individual_tax_rates', $individual );
115
}
116
117
/**
118
 * Retrieves the default tax rate.
119
 *
120
 * @return float
121
 */
122
function wpinv_get_default_tax_rate() {
123
    $rate = wpinv_get_option( 'tax_rate', false );
124
    return (float) apply_filters( 'wpinv_get_default_tax_rate', floatval( $rate ) );
125
}
126
127
/**
128
 * Retrieves an array of all tax rates.
129
 *
130
 * @return array
131
 */
132
function wpinv_get_tax_rates() {
133
    return GetPaid_Tax::get_all_tax_rates();
134
}
135
136
/**
137
 * Retrieves an item's tax rates.
138
 *
139
 * @param WPInv_Item|GetPaid_Form_Item $item
140
 * @param string $country
141
 * @param string $state
142
 * @return array
143
 */
144
function getpaid_get_item_tax_rates( $item, $country = '', $state = '' ) {
145
146
    // Abort if the item is not taxable.
147
    if ( ! wpinv_is_item_taxable( $item ) ) {
148
        return array();
149
    }
150
151
    // Maybe use the store address.
152
    if ( wpinv_use_store_address_as_tax_base() ) {
153
        $country = wpinv_get_default_country();
154
        $state   = wpinv_get_default_state();
155
    }
156
157
    // Retrieve tax rates.
158
    $tax_rates = GetPaid_Tax::get_address_tax_rates( $country, $state );
159
160
    // Fallback to the default tax rates if non were found.
161
    if ( empty( $tax_rates ) ) {
162
        $tax_rates = GetPaid_Tax::get_default_tax_rates();
163
    }
164
165
    return apply_filters( 'getpaid_get_item_tax_rates', $tax_rates, $item, $country, $state );
166
}
167
168
/**
169
 * Retrieves an item's taxes.
170
 *
171
 * @param float $amount
172
 * @param array $rates
173
 * @return array
174
 */
175
function getpaid_calculate_item_taxes( $amount, $rates ) {
176
177
    $is_inclusive = wpinv_prices_include_tax();
178
    $taxes        = GetPaid_Tax::calc_tax( $amount, $rates, $is_inclusive );
179
180
    return apply_filters( 'getpaid_calculate_taxes', $taxes, $amount, $rates );
181
}
182
183
/**
184
 * Prepares an item's tax.
185
 *
186
 * @param WPInv_Item|GetPaid_Form_Item $item
187
 * @param string $tax_name
188
 * @param float $tax_amount
189
 * @param float $recurring_tax_amount
190
 * @return array
191
 */
192
function getpaid_prepare_item_tax( $item, $tax_name, $tax_amount, $recurring_tax_amount ) {
193
194
    $initial_tax   = $tax_amount;
195
	$recurring_tax = 0;
196
197
    if ( $item->is_recurring() ) {
198
		$recurring_tax = $recurring_tax_amount;
199
	}
200
201
	return array(
202
		'name'          => sanitize_text_field( $tax_name ),
203
		'initial_tax'   => $initial_tax,
204
		'recurring_tax' => $recurring_tax,
205
    );
206
207
}
208
209
function wpinv_sales_tax_for_year( $year = null ) {
210
    return wpinv_price( wpinv_format_amount( wpinv_get_sales_tax_for_year( $year ) ) );
0 ignored issues
show
Bug introduced by
wpinv_format_amount(wpin...es_tax_for_year($year)) of type string is incompatible with the type double expected by parameter $amount of wpinv_price(). ( Ignorable by Annotation )

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

210
    return wpinv_price( /** @scrutinizer ignore-type */ wpinv_format_amount( wpinv_get_sales_tax_for_year( $year ) ) );
Loading history...
211
}
212
213
function wpinv_get_sales_tax_for_year( $year = null ) {
214
    global $wpdb;
215
216
    // Start at zero
217
    $tax = 0;
218
219
    if ( ! empty( $year ) ) {
220
        $args = array(
221
            'post_type'      => 'wpi_invoice',
222
            'post_status'    => array( 'publish' ),
223
            'posts_per_page' => -1,
224
            'year'           => $year,
225
            'fields'         => 'ids'
226
        );
227
228
        $payments    = get_posts( $args );
229
        $payment_ids = implode( ',', $payments );
230
231
        if ( count( $payments ) > 0 ) {
232
            $sql = "SELECT SUM( meta_value ) FROM $wpdb->postmeta WHERE meta_key = '_wpinv_tax' AND post_id IN( $payment_ids )";
233
            $tax = $wpdb->get_var( $sql );
234
        }
235
236
    }
237
238
    return apply_filters( 'wpinv_get_sales_tax_for_year', $tax, $year );
239
}
240
241
function wpinv_is_cart_taxed() {
242
    return wpinv_use_taxes();
243
}
244
245
function wpinv_prices_show_tax_on_checkout() {
246
    return false; // TODO
247
    $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...
248
249
    return apply_filters( 'wpinv_taxes_on_prices_on_checkout', $ret );
250
}
251
252
function wpinv_display_tax_rate() {
253
    $ret = wpinv_use_taxes() && wpinv_get_option( 'display_tax_rate', false );
254
255
    return apply_filters( 'wpinv_display_tax_rate', $ret );
256
}
257
258
function wpinv_cart_needs_tax_address_fields() {
259
    if( !wpinv_is_cart_taxed() )
260
        return false;
261
262
    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

262
    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...
263
}
264
265
function wpinv_item_is_tax_exclusive( $item_id = 0 ) {
266
    $ret = (bool)get_post_meta( $item_id, '_wpinv_tax_exclusive', false );
267
    return apply_filters( 'wpinv_is_tax_exclusive', $ret, $item_id );
268
}
269
270
function wpinv_currency_decimal_filter( $decimals = 2 ) {
271
    $currency = wpinv_get_currency();
272
273
    switch ( $currency ) {
274
        case 'RIAL' :
275
        case 'JPY' :
276
        case 'TWD' :
277
        case 'HUF' :
278
            $decimals = 0;
279
            break;
280
    }
281
282
    return apply_filters( 'wpinv_currency_decimal_count', $decimals, $currency );
283
}
284
285
function wpinv_tax_amount() {
286
    $output = 0.00;
287
    
288
    return apply_filters( 'wpinv_tax_amount', $output );
289
}
290
291
// VAT Settings
292
function wpinv_vat_rate_add_callback( $args ) {
0 ignored issues
show
Unused Code introduced by
The parameter $args 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

292
function wpinv_vat_rate_add_callback( /** @scrutinizer ignore-unused */ $args ) {

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...
293
    ?>
294
    <p class="wpi-vat-rate-actions"><input id="wpi_vat_rate_add" type="button" value="<?php esc_attr_e( 'Add', 'invoicing' );?>" class="button button-primary" />&nbsp;&nbsp;<i style="display:none;" class="fa fa-refresh fa-spin"></i></p>
295
    <?php
296
}
297
298
function wpinv_vat_rate_delete_callback( $args ) {
0 ignored issues
show
Unused Code introduced by
The parameter $args 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

298
function wpinv_vat_rate_delete_callback( /** @scrutinizer ignore-unused */ $args ) {

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...
299
    global $wpinv_euvat;
300
    
301
    $vat_classes = $wpinv_euvat->get_rate_classes();
302
    $vat_class = isset( $_REQUEST['wpi_sub'] ) && $_REQUEST['wpi_sub'] !== '' && isset( $vat_classes[$_REQUEST['wpi_sub']] )? sanitize_text_field( $_REQUEST['wpi_sub'] ) : '';
303
    if ( isset( $vat_classes[$vat_class] ) ) {
304
    ?>
305
    <p class="wpi-vat-rate-actions"><input id="wpi_vat_rate_delete" type="button" value="<?php echo wp_sprintf( esc_attr__( 'Delete class "%s"', 'invoicing' ), $vat_classes[$vat_class] );?>" class="button button-primary" />&nbsp;&nbsp;<i style="display:none;" class="fa fa-refresh fa-spin"></i></p>
306
    <?php
307
    }
308
}
309
310
function wpinv_vat_rates_callback( $args ) {
311
    global $wpinv_euvat;
312
    
313
    $vat_classes    = $wpinv_euvat->get_rate_classes();
314
    $vat_class      = isset( $_REQUEST['wpi_sub'] ) && $_REQUEST['wpi_sub'] !== '' && isset( $vat_classes[$_REQUEST['wpi_sub']] )? sanitize_text_field( $_REQUEST['wpi_sub'] ) : '_standard';
315
    
316
    $eu_states      = $wpinv_euvat->get_eu_states();
317
    $countries      = wpinv_get_country_list();
318
    $vat_groups     = $wpinv_euvat->get_vat_groups();
319
    $rates          = $wpinv_euvat->get_vat_rates( $vat_class );
320
    ob_start();
321
?>
322
</td><tr>
323
    <td colspan="2" class="wpinv_vat_tdbox">
324
    <input type="hidden" name="wpi_vat_class" value="<?php echo $vat_class;?>" />
325
    <p><?php echo ( isset( $args['desc'] ) ? $args['desc'] : '' ); ?></p>
326
    <table id="wpinv_vat_rates" class="wp-list-table widefat fixed posts">
327
        <colgroup>
328
            <col width="50px" />
329
            <col width="auto" />
330
            <col width="auto" />
331
            <col width="auto" />
332
            <col width="auto" />
333
            <col width="auto" />
334
        </colgroup>
335
        <thead>
336
            <tr>
337
                <th scope="col" colspan="2" class="wpinv_vat_country_name"><?php _e( 'Country', 'invoicing' ); ?></th>
338
                <th scope="col" class="wpinv_vat_global" title="<?php esc_attr_e( 'Apply rate to whole country', 'invoicing' ); ?>"><?php _e( 'Country Wide', 'invoicing' ); ?></th>
339
                <th scope="col" class="wpinv_vat_rate"><?php _e( 'Rate %', 'invoicing' ); ?></th> 
340
                <th scope="col" class="wpinv_vat_name"><?php _e( 'VAT Name', 'invoicing' ); ?></th>
341
                <th scope="col" class="wpinv_vat_group"><?php _e( 'Tax Group', 'invoicing' ); ?></th>
342
            </tr>
343
        </thead>
344
        <tbody>
345
        <?php if( !empty( $eu_states ) ) { ?>
346
        <?php 
347
        foreach ( $eu_states as $state ) { 
348
            $country_name = isset( $countries[$state] ) ? $countries[$state] : '';
349
            
350
            // Filter the rate for each country
351
            $country_rate = array_filter( $rates, function( $rate ) use( $state ) { return $rate['country'] === $state; } );
352
            
353
            // If one does not exist create a default
354
            $country_rate = is_array( $country_rate ) && count( $country_rate ) > 0 ? reset( $country_rate ) : array();
355
            
356
            $vat_global = isset( $country_rate['global'] ) ? !empty( $country_rate['global'] ) : true;
357
            $vat_rate = isset( $country_rate['rate'] ) ? $country_rate['rate'] : '';
358
            $vat_name = !empty( $country_rate['name'] ) ? esc_attr( stripslashes( $country_rate['name'] ) ) : '';
359
            $vat_group = !empty( $country_rate['group'] ) ? $country_rate['group'] : ( $vat_class === '_standard' ? 'standard' : 'reduced' );
360
        ?>
361
        <tr>
362
            <td class="wpinv_vat_country"><?php echo $state; ?><input type="hidden" name="vat_rates[<?php echo $state; ?>][country]" value="<?php echo $state; ?>" /><input type="hidden" name="vat_rates[<?php echo $state; ?>][state]" value="" /></td>
363
            <td class="wpinv_vat_country_name"><?php echo $country_name; ?></td>
364
            <td class="wpinv_vat_global">
365
                <input type="checkbox" name="vat_rates[<?php echo $state;?>][global]" id="vat_rates[<?php echo $state;?>][global]" value="1" <?php checked( true, $vat_global );?> disabled="disabled" />
366
                <label for="tax_rates[<?php echo $state;?>][global]"><?php _e( 'Apply to whole country', 'invoicing' ); ?></label>
367
                <input type="hidden" name="vat_rates[<?php echo $state;?>][global]" value="1" checked="checked" />
368
            </td>
369
            <td class="wpinv_vat_rate"><input type="number" class="small-text" step="any" min="0" max="99" name="vat_rates[<?php echo $state;?>][rate]" value="<?php echo $vat_rate; ?>" /></td>
370
            <td class="wpinv_vat_name"><input type="text" class="regular-text" name="vat_rates[<?php echo $state;?>][name]" value="<?php echo $vat_name; ?>" /></td>
371
            <td class="wpinv_vat_group">
372
            <?php
373
            echo wpinv_html_select( array(
374
                                        'name'             => 'vat_rates[' . $state . '][group]',
375
                                        'selected'         => $vat_group,
376
                                        'id'               => 'vat_rates[' . $state . '][group]',
377
                                        'class'            => 'wpi_select2',
378
                                        'options'          => $vat_groups,
379
                                        'multiple'         => false,
380
                                        'show_option_all'  => false,
381
                                        'show_option_none' => false
382
                                    ) );
383
            ?>
384
            </td>
385
        </tr>
386
        <?php } ?>
387
        <tr>
388
            <td colspan="6" style="background-color:#fafafa;">
389
                <span><input id="wpi_vat_get_rates_group" type="button" class="button-secondary" value="<?php esc_attr_e( 'Update EU VAT Rates', 'invoicing' ); ?>" />&nbsp;&nbsp;<i style="display:none" class="fa fa-refresh fa-spin"></i></span><span id="wpinv-rates-error-wrap" class="wpinv_errors" style="display:none;"></span>
390
            </td>
391
        </tr>
392
        <?php } ?>
393
        </tbody>
394
    </table>
395
    <?php
396
    $content = ob_get_clean();
397
    
398
    echo $content;
399
}
400
401
function wpinv_vat_number_callback( $args ) {
402
    global $wpinv_euvat;
403
    
404
    $vat_number     = $wpinv_euvat->get_vat_number();
405
    $vat_valid      = $wpinv_euvat->is_vat_validated();
406
407
    $size           = ( isset( $args['size'] ) && !is_null( $args['size'] ) ) ? $args['size'] : 'regular';
408
    $validated_text = $vat_valid ? __( 'VAT number validated', 'invoicing' ) : __( 'VAT number not validated', 'invoicing' );
409
    $disabled       = $vat_valid ? 'disabled="disabled"' : " ";
410
    
411
    $html = '<input type="text" class="' . $size . '-text" id="wpinv_settings[' . $args['id'] . ']" name="wpinv_settings[' . $args['id'] . ']" placeholder="GB123456789" value="' . esc_attr( stripslashes( $vat_number ) ) . '"/>';
412
    $html .= '<span>&nbsp;<input type="button" id="wpinv_vat_validate" class="wpinv_validate_vat_button button-secondary" ' . $disabled . ' value="' . esc_attr__( 'Validate VAT Number', 'invoicing' ) . '" /></span>';
413
    $html .= '<span class="wpinv-vat-stat wpinv-vat-stat-' . (int)$vat_valid . '"><i class="fa"></i> <font>' . $validated_text . '</font></span>';
414
    $html .= '<label for="wpinv_settings[' . $args['id'] . ']">' . '<p>' . __( 'Enter your VAT number including country identifier, eg: GB123456789 (Settings must be saved after validation)', 'invoicing' ).'</p>' . '</label>';
415
    $html .= '<input type="hidden" name="_wpi_nonce" value="' . wp_create_nonce( 'vat_validation' ) . '">';
416
417
    echo $html;
418
}
419
420
function wpinv_eu_fallback_rate_callback( $args ) {
421
    global $wpinv_options;
422
423
    $value = isset( $wpinv_options[$args['id']] ) ? $wpinv_options[ $args['id'] ] : ( isset( $args['std'] ) ? $args['std'] : '' );
424
    $size = ( isset( $args['size'] ) && !is_null( $args['size'] ) ) ? $args['size'] : 'small';
425
    
426
    $html = '<input type="number" min="0" max="99" step="any" class="' . $size . '-text" id="wpinv_settings_' . $args['section'] . '_' . $args['id'] . '" name="wpinv_settings[' . $args['id'] . ']" value="' . esc_attr( stripslashes( $value ) ) . '" />';
427
    $html .= '<span>&nbsp;<input id="wpi_add_eu_states" type="button" class="button-secondary" value="' . esc_attr__( 'Add EU Member States', 'invoicing' ) . '" /></span>';
428
    $html .= '<span>&nbsp;<input id="wpi_remove_eu_states" type="button" class="button-secondary" value="' . esc_attr__( 'Remove EU Member States', 'invoicing' ) . '" /></span>';
429
    $html .= '<span>&nbsp;<input id="wpi_vat_get_rates" type="button" class="button-secondary" value="' . esc_attr__( 'Update EU VAT Rates', 'invoicing' ) . '" />&nbsp;&nbsp;<i style="display:none" class="fa fa-refresh fa-spin"></i></span>';
430
    $html .= '<p><label for="wpinv_settings_' . $args['section'] . '_' . $args['id'] . '">' . $args['desc'] . '</label></p>';
431
    echo $html;
432
    ?>
433
    <span id="wpinv-rates-error-wrap" class="wpinv_errors" style="display:none;"></span>
434
    <?php
435
}
436
437
/**
438
 * Filters the VAT rules to ensure that each item has a VAT rule.
439
 * 
440
 * @param string|bool|null $vat_rule
441
 */
442
function getpaid_filter_vat_rule( $vat_rule ) {
443
444
    if ( empty( $vat_rule ) ) {        
445
        return getpaid_tax()->allow_vat_rules() ? 'digital' : 'physical';
446
    }
447
448
    return $vat_rule;
449
}
450
add_filter( 'wpinv_get_item_vat_rule', 'getpaid_filter_vat_rule' );
451
452
/**
453
 * Filters the VAT class to ensure that each item has a VAT class.
454
 * 
455
 * @param string|bool|null $vat_rule
456
 */
457
function getpaid_filter_vat_class( $vat_class ) {
458
    return empty( $vat_class ) ? '_standard' : $vat_class;
459
}
460
add_filter( 'wpinv_get_item_vat_class', 'getpaid_filter_vat_class' );
461