Passed
Push — master ( 1ce22f...41fbb9 )
by Brian
09:44 queued 04:28
created

WPInv_EUVat::load_vat_scripts()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 41
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 36
c 0
b 0
f 0
dl 0
loc 41
rs 9.0328
cc 5
nc 16
nop 0
1
<?php
2
/**
3
 * Tax calculation and rate finding class.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
class WPInv_EUVat {
10
11
    /**
12
     * Retrieves an instance of this class.
13
     * 
14
     * @deprecated
15
     * @return WPInv_EUVat
16
     */
17
    public static function get_instance() {
18
        return new self();
19
    }
20
21
    /**
22
     * Inits tax hooks.
23
     */
24
    public function init() {
25
26
        // If this is an admin page...
27
        if ( is_admin() ) {
28
29
            // Register our scripts.
30
            add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
31
            add_action( 'wpinv_settings_sections_taxes', array( $this, 'section_vat_settings' ) );
32
            add_action( 'wpinv_settings_taxes', array( $this, 'vat_settings' ) );
33
            add_filter( 'wpinv_settings_taxes-vat_sanitize', array( $this, 'sanitize_vat_settings' ) );
34
            add_filter( 'wpinv_settings_taxes-vat_rates_sanitize', array( $this, 'sanitize_vat_rates' ) );
35
            add_action( 'wp_ajax_wpinv_add_vat_class', array( $this, 'add_class' ) );
36
            add_action( 'wp_ajax_nopriv_wpinv_add_vat_class', array( $this, 'add_class' ) );
37
            add_action( 'wp_ajax_wpinv_delete_vat_class', array( $this, 'delete_class' ) );
38
            add_action( 'wp_ajax_nopriv_wpinv_delete_vat_class', array( $this, 'delete_class' ) );
39
            add_action( 'wp_ajax_wpinv_update_vat_rates', array( $this, 'update_eu_rates' ) );
40
            add_action( 'wp_ajax_nopriv_wpinv_update_vat_rates', array( $this, 'update_eu_rates' ) );
41
        }
42
43
        add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_vat_scripts' ) );
44
        add_filter( 'wpinv_default_billing_country', array( $this, 'get_user_country' ), 10 );
45
        add_filter( 'wpinv_get_user_country', array( $this, 'set_user_country' ), 10 );
46
        add_action( 'wp_ajax_wpinv_vat_validate', array( $this, 'ajax_vat_validate' ) );
47
        add_action( 'wp_ajax_nopriv_wpinv_vat_validate', array( $this, 'ajax_vat_validate' ) );
48
49
        if ( wpinv_use_taxes() && self::allow_vat_rules() ) {
50
            add_filter( 'wpinv_tax_rate', array( $this, 'get_rate' ), 10, 4 );
51
        }
52
    }
53
54
    public static function get_eu_states( $sort = true ) {
55
        $eu_states = array( 'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GB', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE' );
56
        if ( $sort ) {
57
            $sort = sort( $eu_states );
58
        }
59
60
        return apply_filters( 'wpinv_get_eu_states', $eu_states, $sort );
61
    }
62
63
    public static function get_gst_countries( $sort = true ) {
64
        $gst_countries  = array( 'AU', 'NZ', 'CA', 'CN' );
65
66
        if ( $sort ) {
67
            $sort = sort( $gst_countries );
68
        }
69
70
        return apply_filters( 'wpinv_get_gst_countries', $gst_countries, $sort );
71
    }
72
73
    public static function is_eu_state( $country_code ) {
74
        $return = !empty( $country_code ) && in_array( strtoupper( $country_code ), self::get_eu_states() ) ? true : false;
75
76
        return apply_filters( 'wpinv_is_eu_state', $return, $country_code );
77
    }
78
79
    public static function is_gst_country( $country_code ) {
80
        $return = !empty( $country_code ) && in_array( strtoupper( $country_code ), self::get_gst_countries() ) ? true : false;
81
82
        return apply_filters( 'wpinv_is_gst_country', $return, $country_code );
83
    }
84
85
    public function enqueue_vat_scripts() {
86
        if( wpinv_use_taxes() && wpinv_get_option( 'apply_vat_rules' ) ) {
87
            $this->load_vat_scripts();
88
        }
89
    }
90
91
    public function load_vat_scripts(){
92
        $suffix     = '';//defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
93
94
        wp_register_script( 'wpinv-vat-validation-script', WPINV_PLUGIN_URL . 'assets/js/jsvat' . $suffix . '.js', array( 'jquery' ),  WPINV_VERSION );
95
        wp_register_script( 'wpinv-vat-script', WPINV_PLUGIN_URL . 'assets/js/euvat' . $suffix . '.js', array( 'jquery' ),  WPINV_VERSION );
96
97
        $vat_name   = $this->get_vat_name();
98
99
        $vars = array();
100
        $vars['UseTaxes'] = wpinv_use_taxes();
101
        $vars['EUStates'] = self::get_eu_states();
102
        $vars['NoRateSet'] = __( 'You have not set a rate. Do you want to continue?', 'invoicing' );
103
        $vars['EmptyCompany'] = __( 'Please enter your registered company name!', 'invoicing' );
104
        $vars['EmptyVAT'] = wp_sprintf( __( 'Please enter your %s number!', 'invoicing' ), $vat_name );
105
        $vars['TotalsRefreshed'] = wp_sprintf( __( 'The invoice totals will be refreshed to update the %s.', 'invoicing' ), $vat_name );
106
        $vars['ErrValidateVAT'] = wp_sprintf( __( 'Fail to validate the %s number!', 'invoicing' ), $vat_name );
107
        $vars['ErrResetVAT'] = wp_sprintf( __( 'Fail to reset the %s number!', 'invoicing' ), $vat_name );
108
        $vars['ErrInvalidVat'] = wp_sprintf( __( 'The %s number supplied does not have a valid format!', 'invoicing' ), $vat_name );
109
        $vars['ErrInvalidResponse'] = __( 'An invalid response has been received from the server!', 'invoicing' );
110
        $vars['ApplyVATRules'] = $vars['UseTaxes'] ? self::allow_vat_rules() : false;
111
        $vars['ErrResponse'] = __( 'The request response is invalid!', 'invoicing' );
112
        $vars['ErrRateResponse'] = __( 'The get rate request response is invalid', 'invoicing' );
113
        $vars['PageRefresh'] = __( 'The page will be refreshed in 10 seconds to show the new options.', 'invoicing' );
114
        $vars['RequestResponseNotValidJSON'] = __( 'The get rate request response is not valid JSON', 'invoicing' );
115
        $vars['GetRateRequestFailed'] = __( 'The get rate request failed: ', 'invoicing' );
116
        $vars['NoRateInformationInResponse'] = __( 'The get rate request response does not contain any rate information', 'invoicing' );
117
        $vars['RatesUpdated'] = __( 'The rates have been updated. Press the save button to record these new rates.', 'invoicing' );
118
        $vars['IPAddressInformation'] = __( 'IP Address Information', 'invoicing' );
119
        $vars['VatValidating'] = wp_sprintf( __( 'Validating %s number...', 'invoicing' ), $vat_name );
120
        $vars['VatReseting'] = __( 'Reseting...', 'invoicing' );
121
        $vars['VatValidated'] = wp_sprintf( __( '%s number validated', 'invoicing' ), $vat_name );
122
        $vars['VatNotValidated'] = wp_sprintf( __( '%s number not validated', 'invoicing' ), $vat_name );
123
        $vars['ConfirmDeleteClass'] = __( 'Are you sure you wish to delete this rates class?', 'invoicing' );
124
        $vars['isFront'] = is_admin() ? false : true;
125
        $vars['baseCountry'] = wpinv_get_default_country();
126
        $vars['disableVATSameCountry'] = ( self::same_country_rule() == 'no' ? true : false );
127
        $vars['disableVATSimpleCheck'] = wpinv_get_option( 'vat_offline_check' ) ? true : false;
128
129
        wp_enqueue_script( 'wpinv-vat-validation-script' );
130
        wp_enqueue_script( 'wpinv-vat-script' );
131
        wp_localize_script( 'wpinv-vat-script', 'WPInv_VAT_Vars', $vars );
132
    }
133
134
    public static function enqueue_admin_scripts() {
135
        if( isset( $_GET['page'] ) && 'wpinv-settings' == $_GET['page'] ) {
136
            self::load_vat_scripts();
0 ignored issues
show
Bug Best Practice introduced by
The method WPInv_EUVat::load_vat_scripts() is not static, but was called statically. ( Ignorable by Annotation )

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

136
            self::/** @scrutinizer ignore-call */ 
137
                  load_vat_scripts();
Loading history...
137
        }
138
    }
139
140
    public static function section_vat_settings( $sections ) {
141
        if ( !empty( $sections ) ) {
142
            $sections['vat'] = __( 'EU VAT Settings', 'invoicing' );
143
144
            if ( self::allow_vat_classes() ) {
145
                $sections['vat_rates'] = __( 'EU VAT Rates', 'invoicing' );
146
            }
147
        }
148
        return $sections;
149
    }
150
151
    public static function vat_rates_settings() {
152
        $vat_classes = self::get_rate_classes();
153
        $vat_rates = array();
154
        $vat_class = isset( $_REQUEST['wpi_sub'] ) && $_REQUEST['wpi_sub'] !== '' && isset( $vat_classes[$_REQUEST['wpi_sub']] )? sanitize_text_field( $_REQUEST['wpi_sub'] ) : '_new';
155
        $current_url = remove_query_arg( 'wpi_sub' );
156
157
        $vat_rates['vat_rates_header'] = array(
158
            'id' => 'vat_rates_header',
159
            'name' => '<h3>' . __( 'Manage VAT Rates', 'invoicing' ) . '</h3>',
160
            'desc' => '',
161
            'type' => 'header',
162
            'size' => 'regular'
163
        );
164
        $vat_rates['vat_rates_class'] = array(
165
            'id'          => 'vat_rates_class',
166
            'name'        => __( 'Edit VAT Rates', 'invoicing' ),
167
            'desc'        => __( 'The standard rate will apply where no explicit rate is provided.', 'invoicing' ),
168
            'type'        => 'select',
169
            'options'     => array_merge( $vat_classes, array( '_new' => __( 'Add New Rate Class', 'invoicing' ) ) ),
170
            'placeholder' => __( 'Select a VAT Rate', 'invoicing' ),
171
            'selected'    => $vat_class,
172
            'class'       => 'wpi_select2',
173
            'onchange'    => 'document.location.href="' . $current_url . '&wpi_sub=" + this.value;',
174
        );
175
176
        if ( $vat_class != '_standard' && $vat_class != '_new' ) {
177
            $vat_rates['vat_rate_delete'] = array(
178
                'id'   => 'vat_rate_delete',
179
                'type' => 'vat_rate_delete',
180
            );
181
        }
182
183
        if ( $vat_class == '_new' ) {
184
            $vat_rates['vat_rates_settings'] = array(
185
                'id' => 'vat_rates_settings',
186
                'name' => '<h3>' . __( 'Add New Rate Class', 'invoicing' ) . '</h3>',
187
                'type' => 'header',
188
            );
189
            $vat_rates['vat_rate_name'] = array(
190
                'id'   => 'vat_rate_name',
191
                'name' => __( 'Name', 'invoicing' ),
192
                'desc' => __( 'A short name for the new VAT Rate class', 'invoicing' ),
193
                'type' => 'text',
194
                'size' => 'regular',
195
            );
196
            $vat_rates['vat_rate_desc'] = array(
197
                'id'   => 'vat_rate_desc',
198
                'name' => __( 'Description', 'invoicing' ),
199
                'desc' => __( 'Manage VAT Rate class', 'invoicing' ),
200
                'type' => 'text',
201
                'size' => 'regular',
202
            );
203
            $vat_rates['vat_rate_add'] = array(
204
                'id'   => 'vat_rate_add',
205
                'type' => 'vat_rate_add',
206
            );
207
        } else {
208
            $vat_rates['vat_rates'] = array(
209
                'id'   => 'vat_rates',
210
                'name' => '<h3>' . $vat_classes[$vat_class] . '</h3>',
211
                'desc' => self::get_class_desc( $vat_class ),
212
                'type' => 'vat_rates',
213
            );
214
        }
215
216
        return $vat_rates;
217
    }
218
219
    public static function vat_settings( $settings ) {
220
        if ( !empty( $settings ) ) {
221
            $vat_settings = array();
222
            $vat_settings['vat_company_title'] = array(
223
                'id' => 'vat_company_title',
224
                'name' => '<h3>' . __( 'Your Company Details', 'invoicing' ) . '</h3>',
225
                'desc' => '',
226
                'type' => 'header',
227
                'size' => 'regular'
228
            );
229
230
            $vat_settings['vat_company_name'] = array(
231
                'id' => 'vat_company_name',
232
                'name' => __( 'Your Company Name', 'invoicing' ),
233
                'desc' => wp_sprintf(__( 'Your company name as it appears on your VAT return, you can verify it via your VAT ID on the %sEU VIES System.%s', 'invoicing' ), '<a href="http://ec.europa.eu/taxation_customs/vies/" target="_blank">', '</a>' ),
234
                'type' => 'text',
235
                'size' => 'regular',
236
            );
237
238
            $vat_settings['vat_number'] = array(
239
                'id'   => 'vat_number',
240
                'name' => __( 'Your VAT Number', 'invoicing' ),
241
                'type' => 'vat_number',
242
                'size' => 'regular',
243
            );
244
245
            $vat_settings['vat_settings_title'] = array(
246
                'id' => 'vat_settings_title',
247
                'name' => '<h3>' . __( 'Apply VAT Settings', 'invoicing' ) . '</h3>',
248
                'desc' => '',
249
                'type' => 'header',
250
                'size' => 'regular'
251
            );
252
253
            $vat_settings['apply_vat_rules'] = array(
254
                'id' => 'apply_vat_rules',
255
                'name' => __( 'Enable VAT Rules', 'invoicing' ),
256
                'desc' => __( 'Apply VAT to consumer sales from IP addresses within the EU, even if the billing address is outside the EU.', 'invoicing' ) . '<br><font style="color:red">' . __( 'Do not disable unless you know what you are doing.', 'invoicing' ) . '</font>',
257
                'type' => 'checkbox',
258
                'std' => '1'
259
            );
260
261
            /*
262
            $vat_settings['vat_allow_classes'] = array(
263
                'id' => 'vat_allow_classes',
264
                'name' => __( 'Allow the use of VAT rate classes', 'invoicing' ),
265
                'desc' =>  __( 'When enabled this option makes it possible to define alternative rate classes so rates for items that do not use the standard VAT rate in all member states can be defined.<br>A menu option will appear under the "Invoicing -> Settings -> Taxes -> EU VAT Rates" menu heading that will take you to a page on which new classes can be defined and rates entered. A meta-box will appear in the invoice page in which you are able to select one of the alternative classes you create so the rates associated with the class will be applied to invoice.<br>By default the standard rates class will be used just as they are when this option is not enabled.', 'invoicing' ),
266
                'type' => 'checkbox'
267
            );
268
            */
269
270
            $vat_settings['vat_prevent_b2c_purchase'] = array(
271
                'id' => 'vat_prevent_b2c_purchase',
272
                'name' => __( 'Prevent EU B2C Sales', 'invoicing' ),
273
                'desc' => __( 'Enable this option if you are not registered for VAT in the EU.', 'invoicing' ),
274
                'type' => 'checkbox'
275
            );
276
277
278
279
            $vat_settings['vat_same_country_rule'] = array(
280
                'id'          => 'vat_same_country_rule',
281
                'name'        => __( 'Same Country Rule', 'invoicing' ),
282
                'desc'        => __( 'Select how you want to handle VAT charge if sales are in the same country as the base country.', 'invoicing' ),
283
                'type'        => 'select',
284
                'options'     => array(
285
                    ''          => __( 'Normal', 'invoicing' ),
286
                    'no'        => __( 'No VAT', 'invoicing' ),
287
                    'always'    => __( 'Always apply VAT', 'invoicing' ),
288
                ),
289
                'placeholder' => __( 'Select an option', 'invoicing' ),
290
                'std'         => '',
291
                'class'   => 'wpi_select2',
292
            );
293
294
            $vat_settings['vat_checkout_title'] = array(
295
                'id' => 'vat_checkout_title',
296
                'name' => '<h3>' . __( 'Checkout Fields', 'invoicing' ) . '</h3>',
297
                'desc' => '',
298
                'type' => 'header',
299
                'size' => 'regular'
300
            );
301
302
            $vat_settings['vies_validation_title'] = array(
303
                'id' => 'vies_validation_title',
304
                'name' => '<h3>' . __( 'VIES Validation', 'invoicing' ) . '</h3>',
305
                'desc' => '',
306
                'type' => 'header',
307
                'size' => 'regular'
308
            );
309
310
            $vat_settings['vat_vies_check'] = array(
311
                'id' => 'vat_vies_check',
312
                'name' => __( 'Disable VIES VAT ID Check', 'invoicing' ),
313
                'desc' => wp_sprintf( __( 'Prevent VAT numbers from being validated by the %sEU VIES System.%s', 'invoicing' ), '<a href="http://ec.europa.eu/taxation_customs/vies/" target="_blank">', '</a>' ),
314
                'type' => 'checkbox'
315
            );
316
317
            $vat_settings['vat_disable_company_name_check'] = array(
318
                'id' => 'vat_disable_company_name_check',
319
                'name' => __( 'Disable VIES Name Check', 'invoicing' ),
320
                'desc' => wp_sprintf( __( 'Prevent company name from being validated by the %sEU VIES System.%s', 'invoicing' ), '<a href="http://ec.europa.eu/taxation_customs/vies/" target="_blank">', '</a>' ),
321
                'type' => 'checkbox'
322
            );
323
324
            $vat_settings['vat_offline_check'] = array(
325
                'id' => 'vat_offline_check',
326
                'name' => __( 'Disable Basic Checks', 'invoicing' ),
327
                'desc' => __( 'Disable basic JS checks for correct format of VAT number. (Not Recommended)', 'invoicing' ),
328
                'type' => 'checkbox'
329
            );
330
331
332
            $settings['vat'] = $vat_settings;
333
334
            if ( self::allow_vat_classes() ) {
335
                $settings['vat_rates'] = self::vat_rates_settings();
336
            }
337
338
            $eu_fallback_rate = array(
339
                'id'   => 'eu_fallback_rate',
340
                'name' => '<h3>' . __( 'VAT rate for EU member states', 'invoicing' ) . '</h3>',
341
                'type' => 'eu_fallback_rate',
342
                'desc' => __( 'Enter the VAT rate to be charged for EU member states. You can edit the rates for each member state when a country rate has been set up by pressing this button.', 'invoicing' ),
343
                'std'  => '20',
344
                'size' => 'small'
345
            );
346
            $settings['rates']['eu_fallback_rate'] = $eu_fallback_rate;
347
        }
348
349
        return $settings;
350
    }
351
352
    /**
353
	 *
354
	 * @deprecated
355
	 */
356
    public static function maxmind_folder() {
357
        return false;
358
    }
359
360
    /**
361
	 *
362
	 * @deprecated
363
	 */
364
    public static function geoip2_download_database() {}
365
366
    /**
367
	 *
368
	 * @deprecated
369
	 */
370
    public static function geoip2_download_file() {}
371
372
    /**
373
     * @deprecated
374
     */
375
    public static function load_geoip2() {}
376
377
    /**
378
     * @deprecated
379
     */
380
    public static function geoip2_country_dbfile() {
381
        return false;
382
    }
383
384
    /**
385
     * @deprecated
386
     */
387
    public static function geoip2_city_dbfile() {
388
        return false;
389
    }
390
391
    /**
392
     * @deprecated
393
     */
394
    public static function geoip2_country_reader() {
395
        return false;
396
    }
397
398
    /**
399
     * @deprecated
400
     */
401
    public static function geoip2_city_reader() {
402
        return false;
403
    }
404
405
    /**
406
     * @deprecated
407
     */
408
    public static function geoip2_country_record() {
409
        return false;
410
    }
411
412
    /**
413
     * @deprecated
414
     */
415
    public static function geoip2_city_record() {
416
        return false;
417
    }
418
419
    /**
420
     * @deprecated
421
     */
422
    public static function geoip2_country_code() {
423
        wpinv_get_default_country();
424
    }
425
426
    /**
427
     * @deprecated
428
     */
429
    public static function get_country_by_ip() {
430
        return getpaid_get_ip_country();
431
    }
432
433
    public static function sanitize_vat_settings( $input ) {
434
        global $wpinv_options;
435
436
        $valid      = false;
437
        $message    = '';
438
439
        if ( !empty( $wpinv_options['vat_vies_check'] ) ) {
440
            if ( empty( $wpinv_options['vat_offline_check'] ) ) {
441
                $valid = self::offline_check( $input['vat_number'] );
442
            } else {
443
                $valid = true;
444
            }
445
446
            $message = $valid ? '' : __( 'VAT number not validated', 'invoicing' );
447
        } else {
448
            $result = self::check_vat( $input['vat_number'] );
449
450
            if ( empty( $result['valid'] ) ) {
451
                $valid      = false;
452
                $message    = $result['message'];
453
            } else {
454
                $valid      = ( isset( $result['company'] ) && ( $result['company'] == '---' || ( strcasecmp( trim( $result['company'] ), trim( $input['vat_company_name'] ) ) == 0 ) ) ) || !empty( $wpinv_options['vat_disable_company_name_check'] );
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: $valid = (IssetNode && $..._company_name_check'])), Probably Intended Meaning: $valid = IssetNode && ($..._company_name_check']))
Loading history...
455
                $message    = $valid ? '' : __( 'The company name associated with the VAT number provided is not the same as the company name provided.', 'invoicing' );
456
            }
457
        }
458
459
        if ( $message && self::is_vat_validated() != $valid ) {
460
            add_settings_error( 'wpinv-notices', '', $message, ( $valid ? 'updated' : 'error' ) );
461
        }
462
463
        $input['vat_valid'] = $valid;
464
        return $input;
465
    }
466
467
    public static function sanitize_vat_rates( $input ) {
468
        if( !wpinv_current_user_can_manage_invoicing() ) {
469
            add_settings_error( 'wpinv-notices', '', __( 'Your account does not have permission to add rate classes.', 'invoicing' ), 'error' );
470
            return $input;
471
        }
472
473
        $vat_classes = self::get_rate_classes();
474
        $vat_class = !empty( $_REQUEST['wpi_vat_class'] ) && isset( $vat_classes[$_REQUEST['wpi_vat_class']] )? sanitize_text_field( $_REQUEST['wpi_vat_class'] ) : '';
475
476
        if ( empty( $vat_class ) ) {
477
            add_settings_error( 'wpinv-notices', '', __( 'No valid VAT rates class contained in the request to save rates.', 'invoicing' ), 'error' );
478
479
            return $input;
480
        }
481
482
        $new_rates = ! empty( $_POST['vat_rates'] ) ? array_values( $_POST['vat_rates'] ) : array();
483
484
        if ( $vat_class === '_standard' ) {
485
            // Save the active rates in the invoice settings
486
            update_option( 'wpinv_tax_rates', $new_rates );
487
        } else {
488
            // Get the existing set of rates
489
            $rates = self::get_non_standard_rates();
490
            $rates[$vat_class] = $new_rates;
491
492
            update_option( 'wpinv_vat_rates', $rates );
493
        }
494
495
        return $input;
496
    }
497
498
    public static function add_class() {
499
        $response = array();
500
        $response['success'] = false;
501
502
        if ( !wpinv_current_user_can_manage_invoicing() ) {
503
            $response['error'] = __( 'Invalid access!', 'invoicing' );
504
            wp_send_json( $response );
505
        }
506
507
        $vat_class_name = !empty( $_POST['name'] ) ? sanitize_text_field( $_POST['name'] ) : false;
508
        $vat_class_desc = !empty( $_POST['desc'] ) ? sanitize_text_field( $_POST['desc'] ) : false;
509
510
        if ( empty( $vat_class_name ) ) {
511
            $response['error'] = __( 'Select the VAT rate name', 'invoicing' );
512
            wp_send_json( $response );
513
        }
514
515
        $vat_classes = (array)self::get_rate_classes();
516
517
        if ( !empty( $vat_classes ) && in_array( strtolower( $vat_class_name ), array_map( 'strtolower', array_values( $vat_classes ) ) ) ) {
518
            $response['error'] = wp_sprintf( __( 'A VAT Rate name "%s" already exists', 'invoicing' ), $vat_class_name );
519
            wp_send_json( $response );
520
        }
521
522
        $rate_class_key = normalize_whitespace( 'wpi-' . $vat_class_name );
523
        $rate_class_key = sanitize_key( str_replace( " ", "-", $rate_class_key ) );
524
525
        $vat_classes = (array)self::get_rate_classes( true );
526
        $vat_classes[$rate_class_key] = array( 'name' => $vat_class_name, 'desc' => $vat_class_desc );
527
528
        update_option( '_wpinv_vat_rate_classes', $vat_classes );
529
530
        $response['success'] = true;
531
        $response['redirect'] = admin_url( 'admin.php?page=wpinv-settings&tab=taxes&section=vat_rates&wpi_sub=' . $rate_class_key );
532
533
        wp_send_json( $response );
534
    }
535
536
    public static function delete_class() {
537
        $response = array();
538
        $response['success'] = false;
539
540
        if ( !wpinv_current_user_can_manage_invoicing() || !isset( $_POST['class'] ) ) {
541
            $response['error'] = __( 'Invalid access!', 'invoicing' );
542
            wp_send_json( $response );
543
        }
544
545
        $vat_class = isset( $_POST['class'] ) && $_POST['class'] !== '' ? sanitize_text_field( $_POST['class'] ) : false;
546
        $vat_classes = (array)self::get_rate_classes();
547
548
        if ( !isset( $vat_classes[$vat_class] ) ) {
549
            $response['error'] = __( 'Requested class does not exists', 'invoicing' );
550
            wp_send_json( $response );
551
        }
552
553
        if ( $vat_class == '_new' || $vat_class == '_standard' ) {
554
            $response['error'] = __( 'You can not delete standard rates class', 'invoicing' );
555
            wp_send_json( $response );
556
        }
557
558
        $vat_classes = (array)self::get_rate_classes( true );
559
        unset( $vat_classes[$vat_class] );
560
561
        update_option( '_wpinv_vat_rate_classes', $vat_classes );
562
563
        $response['success'] = true;
564
        $response['redirect'] = admin_url( 'admin.php?page=wpinv-settings&tab=taxes&section=vat_rates&wpi_sub=_new' );
565
566
        wp_send_json( $response );
567
    }
568
569
    public static function update_eu_rates() {
570
        $response               = array();
571
        $response['success']    = false;
572
        $response['error']      = null;
573
        $response['data']       = null;
574
575
        if ( !wpinv_current_user_can_manage_invoicing() ) {
576
            $response['error'] = __( 'Invalid access!', 'invoicing' );
577
            wp_send_json( $response );
578
        }
579
580
        $group      = !empty( $_POST['group'] ) ? sanitize_text_field( $_POST['group'] ) : '';
581
        $euvatrates = self::request_euvatrates( $group );
582
583
        if ( !empty( $euvatrates ) ) {
584
            if ( !empty( $euvatrates['success'] ) && !empty( $euvatrates['rates'] ) ) {
585
                $response['success']        = true;
586
                $response['data']['rates']  = $euvatrates['rates'];
587
            } else if ( !empty( $euvatrates['error'] ) ) {
588
                $response['error']          = $euvatrates['error'];
589
            }
590
        }
591
592
        wp_send_json( $response );
593
    }
594
595
    /**
596
     * @deprecated
597
     */
598
    public static function hide_vat_fields() {}
599
600
    public static function same_country_rule() {
601
        $same_country_rule = wpinv_get_option( 'vat_same_country_rule' );
602
603
        return apply_filters( 'wpinv_vat_same_country_rule', $same_country_rule );
604
    }
605
606
    /**
607
     * Retrieves the vat name.
608
     */
609
    public function get_vat_name() {
610
        $vat_name = wpinv_get_option( 'vat_name' );
611
        return empty( $vat_name ) ? __( 'VAT', 'invoicing' ) : sanitize_text_field( $vat_name );
612
    }
613
614
    public static function get_company_name() {
615
        $company_name = wpinv_get_option( 'vat_company_name' );
616
617
        return apply_filters( 'wpinv_get_owner_company_name', $company_name );
618
    }
619
620
    public static function get_vat_number() {
621
        $vat_number = wpinv_get_option( 'vat_number' );
622
623
        return apply_filters( 'wpinv_get_owner_vat_number', $vat_number );
624
    }
625
626
    public static function is_vat_validated() {
627
        $validated = self::get_vat_number() && wpinv_get_option( 'vat_valid' );
628
629
        return apply_filters( 'wpinv_is_owner_vat_validated', $validated );
630
    }
631
632
    public static function sanitize_vat( $vat_number, $country_code = '' ) {
633
        $vat_number = str_replace( array(' ', '.', '-', '_', ',' ), '', strtoupper( trim( $vat_number ) ) );
634
635
        if ( empty( $country_code ) ) {
636
            $country_code = substr( $vat_number, 0, 2 );
637
        }
638
639
        if ( strpos( $vat_number , $country_code ) === 0 ) {
640
            $vat = str_replace( $country_code, '', $vat_number );
641
        } else {
642
            $vat = $country_code . $vat_number;
643
        }
644
645
        $return                 = array();
646
        $return['vat']          = $vat;
647
        $return['iso']          = $country_code;
648
        $return['vat_number']   = $country_code . $vat;
649
650
        return $return;
651
    }
652
653
    public static function offline_check( $vat_number, $country_code = '', $formatted = false ) {
654
        $vat            = self::sanitize_vat( $vat_number, $country_code );
655
        $vat_number     = $vat['vat_number'];
656
        $country_code   = $vat['iso'];
657
        $regex          = array();
658
659
        switch ( $country_code ) {
660
            case 'AT':
661
                $regex[] = '/^(AT)U(\d{8})$/';                           // Austria
662
                break;
663
            case 'BE':
664
                $regex[] = '/^(BE)(0?\d{9})$/';                          // Belgium
665
                break;
666
            case 'BG':
667
                $regex[] = '/^(BG)(\d{9,10})$/';                         // Bulgaria
668
                break;
669
            case 'CH':
670
            case 'CHE':
671
                $regex[] = '/^(CHE)(\d{9})MWST$/';                       // Switzerland (Not EU)
672
                break;
673
            case 'CY':
674
                $regex[] = '/^(CY)([0-5|9]\d{7}[A-Z])$/';                // Cyprus
675
                break;
676
            case 'CZ':
677
                $regex[] = '/^(CZ)(\d{8,13})$/';                         // Czech Republic
678
                break;
679
            case 'DE':
680
                $regex[] = '/^(DE)([1-9]\d{8})$/';                       // Germany
681
                break;
682
            case 'DK':
683
                $regex[] = '/^(DK)(\d{8})$/';                            // Denmark
684
                break;
685
            case 'EE':
686
                $regex[] = '/^(EE)(10\d{7})$/';                          // Estonia
687
                break;
688
            case 'EL':
689
                $regex[] = '/^(EL)(\d{9})$/';                            // Greece
690
                break;
691
            case 'ES':
692
                $regex[] = '/^(ES)([A-Z]\d{8})$/';                       // Spain (National juridical entities)
693
                $regex[] = '/^(ES)([A-H|N-S|W]\d{7}[A-J])$/';            // Spain (Other juridical entities)
694
                $regex[] = '/^(ES)([0-9|Y|Z]\d{7}[A-Z])$/';              // Spain (Personal entities type 1)
695
                $regex[] = '/^(ES)([K|L|M|X]\d{7}[A-Z])$/';              // Spain (Personal entities type 2)
696
                break;
697
            case 'EU':
698
                $regex[] = '/^(EU)(\d{9})$/';                            // EU-type
699
                break;
700
            case 'FI':
701
                $regex[] = '/^(FI)(\d{8})$/';                            // Finland
702
                break;
703
            case 'FR':
704
                $regex[] = '/^(FR)(\d{11})$/';                           // France (1)
705
                $regex[] = '/^(FR)[(A-H)|(J-N)|(P-Z)](\d{10})$/';        // France (2)
706
                $regex[] = '/^(FR)\d[(A-H)|(J-N)|(P-Z)](\d{9})$/';       // France (3)
707
                $regex[] = '/^(FR)[(A-H)|(J-N)|(P-Z)]{2}(\d{9})$/';      // France (4)
708
                break;
709
            case 'GB':
710
                $regex[] = '/^(GB)?(\d{9})$/';                           // UK (Standard)
711
                $regex[] = '/^(GB)?(\d{12})$/';                          // UK (Branches)
712
                $regex[] = '/^(GB)?(GD\d{3})$/';                         // UK (Government)
713
                $regex[] = '/^(GB)?(HA\d{3})$/';                         // UK (Health authority)
714
                break;
715
            case 'GR':
716
                $regex[] = '/^(GR)(\d{8,9})$/';                          // Greece
717
                break;
718
            case 'HR':
719
                $regex[] = '/^(HR)(\d{11})$/';                           // Croatia
720
                break;
721
            case 'HU':
722
                $regex[] = '/^(HU)(\d{8})$/';                            // Hungary
723
                break;
724
            case 'IE':
725
                $regex[] = '/^(IE)(\d{7}[A-W])$/';                       // Ireland (1)
726
                $regex[] = '/^(IE)([7-9][A-Z\*\+)]\d{5}[A-W])$/';        // Ireland (2)
727
                $regex[] = '/^(IE)(\d{7}[A-Z][AH])$/';                   // Ireland (3) (new format from 1 Jan 2013)
728
                break;
729
            case 'IT':
730
                $regex[] = '/^(IT)(\d{11})$/';                           // Italy
731
                break;
732
            case 'LV':
733
                $regex[] = '/^(LV)(\d{11})$/';                           // Latvia
734
                break;
735
            case 'LT':
736
                $regex[] = '/^(LT)(\d{9}|\d{12})$/';                     // Lithuania
737
                break;
738
            case 'LU':
739
                $regex[] = '/^(LU)(\d{8})$/';                            // Luxembourg
740
                break;
741
            case 'MT':
742
                $regex[] = '/^(MT)([1-9]\d{7})$/';                       // Malta
743
                break;
744
            case 'NL':
745
                $regex[] = '/^(NL)(\d{9})B\d{2}$/';                      // Netherlands
746
                break;
747
            case 'NO':
748
                $regex[] = '/^(NO)(\d{9})$/';                            // Norway (Not EU)
749
                break;
750
            case 'PL':
751
                $regex[] = '/^(PL)(\d{10})$/';                           // Poland
752
                break;
753
            case 'PT':
754
                $regex[] = '/^(PT)(\d{9})$/';                            // Portugal
755
                break;
756
            case 'RO':
757
                $regex[] = '/^(RO)([1-9]\d{1,9})$/';                     // Romania
758
                break;
759
            case 'RS':
760
                $regex[] = '/^(RS)(\d{9})$/';                            // Serbia (Not EU)
761
                break;
762
            case 'SI':
763
                $regex[] = '/^(SI)([1-9]\d{7})$/';                       // Slovenia
764
                break;
765
            case 'SK':
766
                $regex[] = '/^(SK)([1-9]\d[(2-4)|(6-9)]\d{7})$/';        // Slovakia Republic
767
                break;
768
            case 'SE':
769
                $regex[] = '/^(SE)(\d{10}01)$/';                         // Sweden
770
                break;
771
            default:
772
                $regex = array();
773
            break;
774
        }
775
776
        if ( empty( $regex ) ) {
777
            return false;
778
        }
779
780
        foreach ( $regex as $pattern ) {
781
            $matches = null;
782
            preg_match_all( $pattern, $vat_number, $matches );
783
784
            if ( !empty( $matches[1][0] ) && !empty( $matches[2][0] ) ) {
785
                if ( $formatted ) {
786
                    return array( 'code' => $matches[1][0], 'number' => $matches[2][0] );
787
                } else {
788
                    return true;
789
                }
790
            }
791
        }
792
793
        return false;
794
    }
795
796
    public static function vies_check( $vat_number, $country_code = '', $result = false ) {
797
        $vat            = self::sanitize_vat( $vat_number, $country_code );
798
        $vat_number     = $vat['vat'];
799
        $iso            = $vat['iso'];
800
801
        $url = 'http://ec.europa.eu/taxation_customs/vies/viesquer.do?ms=' . urlencode( $iso ) . '&iso=' . urlencode( $iso ) . '&vat=' . urlencode( $vat_number );
802
803
        if ( ini_get( 'allow_url_fopen' ) ) {
804
            $response = file_get_contents( $url );
805
        } else if ( function_exists( 'curl_init' ) ) {
806
            $ch = curl_init();
807
808
            curl_setopt( $ch, CURLOPT_URL, $url );
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() does only seem to accept resource, 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

808
            curl_setopt( /** @scrutinizer ignore-type */ $ch, CURLOPT_URL, $url );
Loading history...
809
            curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 30 );
810
            curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
811
            curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
812
            curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );
813
814
            $response = curl_exec( $ch );
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, 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

814
            $response = curl_exec( /** @scrutinizer ignore-type */ $ch );
Loading history...
815
816
            if ( curl_errno( $ch ) ) {
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_errno() does only seem to accept resource, 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

816
            if ( curl_errno( /** @scrutinizer ignore-type */ $ch ) ) {
Loading history...
817
                wpinv_error_log( curl_error( $ch ), 'VIES CHECK ERROR' );
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_error() does only seem to accept resource, 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

817
                wpinv_error_log( curl_error( /** @scrutinizer ignore-type */ $ch ), 'VIES CHECK ERROR' );
Loading history...
818
                $response = '';
819
            }
820
821
            curl_close( $ch );
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() does only seem to accept resource, 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

821
            curl_close( /** @scrutinizer ignore-type */ $ch );
Loading history...
822
        } else {
823
            wpinv_error_log( 'To use VIES CHECK you must have allow_url_fopen is ON or cURL installed & active on your server.', 'VIES CHECK ERROR' );
824
        }
825
826
        if ( empty( $response ) ) {
827
            return $result;
828
        }
829
830
        if ( preg_match( '/invalid VAT number/i', $response ) ) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $response does not seem to be defined for all execution paths leading up to this point.
Loading history...
831
            return false;
832
        } else if ( preg_match( '/valid VAT number/i', $response, $matches ) ) {
833
            $content = explode( "valid VAT number", htmlentities( $response ) );
834
835
            if ( !empty( $content[1] ) ) {
836
                preg_match_all( '/<tr>(.*?)<td.*?>(.*?)<\/td>(.*?)<\/tr>/si', html_entity_decode( $content[1] ), $matches );
837
838
                if ( !empty( $matches[2] ) && $matches[3] ) {
839
                    $return = array();
840
841
                    foreach ( $matches[2] as $key => $label ) {
842
                        $label = trim( $label );
843
844
                        switch ( strtolower( $label ) ) {
845
                            case 'member state':
846
                                $return['state'] = trim( strip_tags( $matches[3][$key] ) );
847
                            break;
848
                            case 'vat number':
849
                                $return['number'] = trim( strip_tags( $matches[3][$key] ) );
850
                            break;
851
                            case 'name':
852
                                $return['company'] = trim( strip_tags( $matches[3][$key] ) );
853
                            break;
854
                            case 'address':
855
                                $address           = str_replace( array( "<br><br>", "<br /><br />", "<br/><br/>" ), "<br>", html_entity_decode( trim( $matches[3][$key] ) ) );
856
                                $return['address'] = trim( strip_tags( $address, '<br>' ) );
857
                            break;
858
                            case 'consultation number':
859
                                $return['consultation'] = trim( strip_tags( $matches[3][$key] ) );
860
                            break;
861
                        }
862
                    }
863
864
                    if ( !empty( $return ) ) {
865
                        return $return;
866
                    }
867
                }
868
            }
869
870
            return true;
871
        } else {
872
            return $result;
873
        }
874
    }
875
876
    public static function check_vat( $vat_number, $country_code = '' ) {
877
        $vat_name           = getpaid_vat_name();
878
879
        $return             = array();
880
        $return['valid']    = false;
881
        $return['message']  = wp_sprintf( __( '%s number not validated', 'invoicing' ), $vat_name );
882
883
        if ( !wpinv_get_option( 'vat_offline_check' ) && !self::offline_check( $vat_number, $country_code ) ) {
884
            return $return;
885
        }
886
887
        $response = self::vies_check( $vat_number, $country_code );
888
889
        if ( $response ) {
890
            $return['valid']    = true;
891
892
            if ( is_array( $response ) ) {
893
                $return['company'] = isset( $response['company'] ) ? $response['company'] : '';
894
                $return['address'] = isset( $response['address'] ) ? $response['address'] : '';
895
                $return['message'] = $return['company'] . '<br/>' . $return['address'];
896
            }
897
        } else {
898
            $return['valid']    = false;
899
            $return['message']  = wp_sprintf( __( 'Fail to validate the %s number: EU Commission VAT server (VIES) check fails.', 'invoicing' ), $vat_name );
900
        }
901
902
        return $return;
903
    }
904
905
    public static function request_euvatrates( $group ) {
906
        $response               = array();
907
        $response['success']    = false;
908
        $response['error']      = null;
909
        $response['eurates']    = null;
910
911
        $euvatrates_url = 'https://euvatrates.com/rates.json';
912
        $euvatrates_url = apply_filters( 'wpinv_euvatrates_url', $euvatrates_url );
913
        $api_response   = wp_remote_get( $euvatrates_url );
914
915
        try {
916
            if ( is_wp_error( $api_response ) ) {
917
                $response['error']      = __( $api_response->get_error_message(), 'invoicing' );
918
            } else {
919
                $body = json_decode( $api_response['body'] );
920
                if ( isset( $body->rates ) ) {
921
                    $rates = array();
922
923
                    foreach ( $body->rates as $country_code => $rate ) {
924
                        $vat_rate = array();
925
                        $vat_rate['country']        = $rate->country;
926
                        $vat_rate['standard']       = (float)$rate->standard_rate;
927
                        $vat_rate['reduced']        = (float)$rate->reduced_rate;
928
                        $vat_rate['superreduced']   = (float)$rate->super_reduced_rate;
929
                        $vat_rate['parking']        = (float)$rate->parking_rate;
930
931
                        if ( $group !== '' && in_array( $group, array( 'standard', 'reduced', 'superreduced', 'parking' ) ) ) {
932
                            $vat_rate_group = array();
933
                            $vat_rate_group['country'] = $rate->country;
934
                            $vat_rate_group[$group]    = $vat_rate[$group];
935
936
                            $vat_rate = $vat_rate_group;
937
                        }
938
939
                        $rates[$country_code] = $vat_rate;
940
                    }
941
942
                    $response['success']    = true;
943
                    $response['rates']      = apply_filters( 'wpinv_process_euvatrates', $rates, $api_response, $group );
944
                } else {
945
                    $response['error']      = __( 'No EU rates found!', 'invoicing' );
946
                }
947
            }
948
        } catch ( Exception $e ) {
949
            $response['error'] = __( $e->getMessage(), 'invoicing' );
950
        }
951
952
        return apply_filters( 'wpinv_response_euvatrates', $response, $group );
953
    }
954
955
    public static function requires_vat( $requires_vat = false, $user_id = 0, $is_digital = null ) {
956
        global $wpi_item_id, $wpi_country;
957
958
        if ( !empty( $_POST['wpinv_country'] ) ) {
959
            $country_code = trim( $_POST['wpinv_country'] );
960
        } else if ( !empty( $_POST['country'] ) ) {
961
            $country_code = trim( $_POST['country'] );
962
        } else if ( !empty( $wpi_country ) ) {
963
            $country_code = $wpi_country;
964
        } else {
965
            $country_code = self::get_user_country( '', $user_id );
966
        }
967
968
        if ( $is_digital === null && $wpi_item_id ) {
969
            $is_digital = $wpi_item_id ? self::item_has_digital_rule( $wpi_item_id ) : self::allow_vat_rules();
970
        }
971
972
        if ( !empty( $country_code ) ) {
973
            $requires_vat = ( self::is_eu_state( $country_code ) && ( self::is_eu_state( wpinv_get_default_country() ) || $is_digital ) ) || ( self::is_gst_country( $country_code ) && self::is_gst_country( wpinv_get_default_country() ) );
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: $requires_vat = (self::i...get_default_country())), Probably Intended Meaning: $requires_vat = self::is...get_default_country()))
Loading history...
974
        }
975
976
        return apply_filters( 'wpinv_requires_vat', $requires_vat, $user_id );
977
    }
978
979
    public static function tax_label( $label = '' ) {
980
        global $wpi_requires_vat;
981
982
        if ( !( $wpi_requires_vat !== 0 && $wpi_requires_vat ) ) {
983
            $wpi_requires_vat = self::requires_vat( 0, false );
984
        }
985
986
        return $wpi_requires_vat ? __( self::get_vat_name(), 'invoicing' ) : ( $label ? $label : __( 'Tax', 'invoicing' ) );
0 ignored issues
show
Bug Best Practice introduced by
The method WPInv_EUVat::get_vat_name() is not static, but was called statically. ( Ignorable by Annotation )

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

986
        return $wpi_requires_vat ? __( self::/** @scrutinizer ignore-call */ get_vat_name(), 'invoicing' ) : ( $label ? $label : __( 'Tax', 'invoicing' ) );
Loading history...
987
    }
988
989
    public static function standard_rates_label() {
990
        return __( 'Standard Rates', 'invoicing' );
991
    }
992
993
    public static function get_rate_classes( $with_desc = false ) {
994
        $rate_classes_option = get_option( '_wpinv_vat_rate_classes', true );
995
        $classes = maybe_unserialize( $rate_classes_option );
996
997
        if ( empty( $classes ) || !is_array( $classes ) ) {
998
            $classes = array();
999
        }
1000
1001
        $rate_classes = array();
1002
        if ( !array_key_exists( '_standard', $classes ) ) {
1003
            if ( $with_desc ) {
1004
                $rate_classes['_standard'] = array( 'name' => self::standard_rates_label(), 'desc' => __( 'EU member states standard VAT rates', 'invoicing' ) );
1005
            } else {
1006
                $rate_classes['_standard'] = self::standard_rates_label();
1007
            }
1008
        }
1009
1010
        foreach ( $classes as $key => $class ) {
1011
            $name = !empty( $class['name'] ) ? __( $class['name'], 'invoicing' ) : $key;
1012
            $desc = !empty( $class['desc'] ) ? __( $class['desc'], 'invoicing' ) : '';
1013
1014
            if ( $with_desc ) {
1015
                $rate_classes[$key] = array( 'name' => $name, 'desc' => $desc );
1016
            } else {
1017
                $rate_classes[$key] = $name;
1018
            }
1019
        }
1020
1021
        return $rate_classes;
1022
    }
1023
1024
    public static function get_all_classes() {
1025
        $classes            = self::get_rate_classes();
1026
        $classes['_exempt'] = __( 'Exempt (0%)', 'invoicing' );
1027
1028
        return apply_filters( 'wpinv_vat_get_all_classes', $classes );
1029
    }
1030
1031
    public static function get_class_desc( $rate_class ) {
1032
        $rate_classes = self::get_rate_classes( true );
1033
1034
        if ( !empty( $rate_classes ) && isset( $rate_classes[$rate_class] ) && isset( $rate_classes[$rate_class]['desc'] ) ) {
1035
            return $rate_classes[$rate_class]['desc'];
1036
        }
1037
1038
        return '';
1039
    }
1040
1041
    public static function get_vat_groups() {
1042
        $vat_groups = array(
1043
            'standard'      => 'Standard',
1044
            'reduced'       => 'Reduced',
1045
            'superreduced'  => 'Super Reduced',
1046
            'parking'       => 'Parking',
1047
            'increased'     => 'Increased'
1048
        );
1049
1050
        return apply_filters( 'wpinv_get_vat_groups', $vat_groups );
1051
    }
1052
1053
    public static function get_rules() {
1054
        $vat_rules = array(
1055
            'digital' => __( 'Digital Product', 'invoicing' ),
1056
            'physical' => __( 'Physical Product', 'invoicing' ),
1057
            '_exempt' => __( 'Tax-Free Product', 'invoicing' ),
1058
        );
1059
        return apply_filters( 'wpinv_get_vat_rules', $vat_rules );
1060
    }
1061
1062
    public static function get_vat_rates( $class ) {
1063
        if ( $class === '_standard' ) {
1064
            return wpinv_get_tax_rates();
1065
        }
1066
1067
        $rates = self::get_non_standard_rates();
1068
1069
        return array_key_exists( $class, $rates ) ? $rates[$class] : array();
1070
    }
1071
1072
    public static function get_non_standard_rates() {
1073
        $option = get_option( 'wpinv_vat_rates', array());
1074
        return is_array( $option ) ? $option : array();
1075
    }
1076
1077
    public static function allow_vat_rules() {
1078
        return ( wpinv_use_taxes() && wpinv_get_option( 'apply_vat_rules' ) ? true : false );
1079
    }
1080
1081
    public static function allow_vat_classes() {
1082
        return false; // TODO
1083
        return ( wpinv_get_option( 'vat_allow_classes' ) ? true : false );
0 ignored issues
show
Unused Code introduced by
return wpinv_get_option(...lasses') ? true : false 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...
1084
    }
1085
1086
    public static function get_item_class( $postID ) {
1087
        $class = get_post_meta( $postID, '_wpinv_vat_class', true );
1088
1089
        if ( empty( $class ) ) {
1090
            $class = '_standard';
1091
        }
1092
1093
        return apply_filters( 'wpinv_get_item_vat_class', $class, $postID );
1094
    }
1095
1096
    public static function item_class_label( $postID ) {
1097
        $vat_classes = self::get_all_classes();
1098
1099
        $class = self::get_item_class( $postID );
1100
        $class = isset( $vat_classes[$class] ) ? $vat_classes[$class] : __( $class, 'invoicing' );
1101
1102
        return apply_filters( 'wpinv_item_class_label', $class, $postID );
1103
    }
1104
1105
    public static function get_item_rule( $postID ) {
1106
        $rule_type = get_post_meta( $postID, '_wpinv_vat_rule', true );
1107
1108
        if ( empty( $rule_type ) ) {
1109
            $rule_type = self::allow_vat_rules() ? 'digital' : 'physical';
1110
        }
1111
1112
        return apply_filters( 'wpinv_item_get_vat_rule', $rule_type, $postID );
1113
    }
1114
1115
    public static function item_rule_label( $postID ) {
1116
        $vat_rules  = self::get_rules();
1117
        $vat_rule   = self::get_item_rule( $postID );
1118
        $vat_rule   = isset( $vat_rules[$vat_rule] ) ? $vat_rules[$vat_rule] : $vat_rule;
1119
1120
        return apply_filters( 'wpinv_item_rule_label', $vat_rule, $postID );
1121
    }
1122
1123
    public static function item_has_digital_rule( $item_id = 0 ) {
1124
        return self::get_item_rule( $item_id ) == 'digital' ? true : false;
1125
    }
1126
1127
    public static function invoice_has_digital_rule( $invoice = 0 ) {
1128
        if ( !self::allow_vat_rules() ) {
1129
            return false;
1130
        }
1131
1132
        if ( empty( $invoice ) ) {
1133
            return true;
1134
        }
1135
1136
        if ( is_int( $invoice ) ) {
1137
            $invoice = new WPInv_Invoice( $invoice );
1138
        }
1139
1140
        if ( !( is_object( $invoice ) && is_a( $invoice, 'WPInv_Invoice' ) ) ) {
1141
            return true;
1142
        }
1143
1144
        $cart_items  = $invoice->get_cart_details();
1145
1146
        if ( !empty( $cart_items ) ) {
1147
            $has_digital_rule = false;
1148
1149
            foreach ( $cart_items as $key => $item ) {
1150
                if ( self::item_has_digital_rule( $item['id'] ) ) {
1151
                    $has_digital_rule = true;
1152
                    break;
1153
                }
1154
            }
1155
        } else {
1156
            $has_digital_rule = true;
1157
        }
1158
1159
        return $has_digital_rule;
1160
    }
1161
1162
    public static function item_is_taxable( $item_id = 0, $country = false, $state = false ) {
1163
        if ( !wpinv_use_taxes() ) {
1164
            return false;
1165
        }
1166
1167
        $is_taxable = true;
1168
1169
        if ( !empty( $item_id ) && self::get_item_class( $item_id ) == '_exempt' ) {
1170
            $is_taxable = false;
1171
        }
1172
1173
        if ( !empty( $item_id ) && self::get_item_rule( $item_id ) == '_exempt' ) {
1174
            $is_taxable = false;
1175
        }
1176
1177
        return apply_filters( 'wpinv_item_is_taxable', $is_taxable, $item_id, $country , $state );
1178
    }
1179
1180
    public static function find_rate( $country, $state, $rate, $class ) {
1181
        global $wpi_zero_tax;
1182
1183
        if ( $class === '_exempt' || $wpi_zero_tax ) {
1184
            return 0;
1185
        }
1186
1187
        $tax_rates   = wpinv_get_tax_rates();
1188
1189
        if ( $class !== '_standard' ) {
1190
            $class_rates = self::get_vat_rates( $class );
1191
1192
            if ( is_array( $class_rates ) ) {
1193
                $indexed_class_rates = array();
1194
1195
                foreach ( $class_rates as $key => $cr ) {
1196
                    $indexed_class_rates[$cr['country']] = $cr;
1197
                }
1198
1199
                $tax_rates = array_map( function( $tr ) use( $indexed_class_rates ) {
1200
                    $tr_country = $tr['country'];
1201
                    if ( !isset( $indexed_class_rates[$tr_country] ) ) {
1202
                        return $tr;
1203
                    }
1204
                    $icr = $indexed_class_rates[$tr_country];
1205
                    return ( empty( $icr['rate'] ) && $icr['rate'] !== '0' ) ? $tr : $icr;
1206
1207
                }, $tax_rates, $class_rates );
0 ignored issues
show
Bug introduced by
It seems like $tax_rates can also be of type false; 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

1207
                }, /** @scrutinizer ignore-type */ $tax_rates, $class_rates );
Loading history...
1208
            }
1209
        }
1210
1211
        if ( !empty( $tax_rates ) ) {
1212
            foreach ( $tax_rates as $key => $tax_rate ) {
1213
                if ( $country != $tax_rate['country'] )
1214
                    continue;
1215
1216
                if ( !empty( $tax_rate['global'] ) ) {
1217
                    if ( 0 !== $tax_rate['rate'] || !empty( $tax_rate['rate'] ) ) {
1218
                        $rate = number_format( $tax_rate['rate'], 4 );
1219
                    }
1220
                } else {
1221
                    if ( empty( $tax_rate['state'] ) || strtolower( $state ) != strtolower( $tax_rate['state'] ) )
1222
                        continue;
1223
1224
                    $state_rate = $tax_rate['rate'];
1225
                    if ( 0 !== $state_rate || !empty( $state_rate ) ) {
1226
                        $rate = number_format( $state_rate, 4 );
1227
                    }
1228
                }
1229
            }
1230
        }
1231
1232
        return $rate;
1233
    }
1234
1235
    public static function get_rate( $rate = 1, $country = '', $state = '', $item_id = 0 ) {
1236
        global $wpinv_options, $wpi_item_id, $wpi_zero_tax;
1237
1238
        $item_id = $item_id > 0 ? $item_id : $wpi_item_id;
1239
        $allow_vat_classes = self::allow_vat_classes();
1240
        $class = $item_id ? self::get_item_class( $item_id ) : '_standard';
1241
1242
        if ( $class === '_exempt' || $wpi_zero_tax ) {
1243
            return 0;
1244
        } else if ( !$allow_vat_classes ) {
0 ignored issues
show
introduced by
The condition $allow_vat_classes is always false.
Loading history...
1245
            $class = '_standard';
1246
        }
1247
1248
        if( !empty( $_POST['wpinv_country'] ) ) {
1249
            $post_country = $_POST['wpinv_country'];
1250
        } elseif( !empty( $_POST['wpinv_country'] ) ) {
1251
            $post_country = $_POST['wpinv_country'];
1252
        } elseif( !empty( $_POST['country'] ) ) {
1253
            $post_country = $_POST['country'];
1254
        } else {
1255
            $post_country = '';
1256
        }
1257
1258
        $country        = !empty( $post_country ) ? $post_country : wpinv_default_billing_country( $country );
1259
        $base_country   = wpinv_is_base_country( $country );
1260
1261
        $requires_vat   = self::requires_vat( 0, false );
1262
        $is_digital     = self::get_item_rule( $item_id ) == 'digital' ;
1263
        $rate           = $requires_vat && isset( $wpinv_options['eu_fallback_rate'] ) ? $wpinv_options['eu_fallback_rate'] : $rate;
1264
1265
        if ( self::same_country_rule() == 'no' && $base_country ) { // Disable VAT to same country
1266
            $rate = 0;
1267
        } else if ( $requires_vat ) {
1268
            $vat_number = self::get_user_vat_number( '', 0, true );
1269
            $vat_info   = self::current_vat_data();
1270
1271
            if ( is_array( $vat_info ) ) {
1272
                $vat_number = isset( $vat_info['number'] ) && !empty( $vat_info['valid'] ) ? $vat_info['number'] : "";
1273
            }
1274
1275
            if ( $country == 'UK' ) {
1276
                $country = 'GB';
1277
            }
1278
1279
            if ( !empty( $vat_number ) ) {
1280
                $rate = 0;
1281
            } else {
1282
                $rate = self::find_rate( $country, $state, $rate, $class ); // Fix if there are no tax rated and you try to pay an invoice it does not add the fallback tax rate
1283
            }
1284
1285
            if ( empty( $vat_number ) && !$is_digital ) {
1286
                if ( $base_country ) {
1287
                    $rate = self::find_rate( $country, null, $rate, $class );
1288
                } else {
1289
                    if ( empty( $country ) && isset( $wpinv_options['eu_fallback_rate'] ) ) {
1290
                        $rate = $wpinv_options['eu_fallback_rate'];
1291
                    } else if( !empty( $country ) ) {
1292
                        $rate = self::find_rate( $country, $state, $rate, $class );
1293
                    }
1294
                }
1295
            } else if ( empty( $vat_number ) || ( self::same_country_rule() == 'always' && $base_country ) ) {
1296
                if ( empty( $country ) && isset( $wpinv_options['eu_fallback_rate'] ) ) {
1297
                    $rate = $wpinv_options['eu_fallback_rate'];
1298
                } else if( !empty( $country ) ) {
1299
                    $rate = self::find_rate( $country, $state, $rate, $class );
1300
                }
1301
            }
1302
        } else {
1303
            if ( $is_digital ) {
1304
                $ip_country_code = getpaid_get_ip_country();
1305
1306
                if ( $ip_country_code && self::is_eu_state( $ip_country_code ) ) {
1307
                    $rate = self::find_rate( $ip_country_code, '', 0, $class );
1308
                } else {
1309
                    $rate = self::find_rate( $country, $state, $rate, $class );
1310
                }
1311
            } else {
1312
                $rate = self::find_rate( $country, $state, $rate, $class );
1313
            }
1314
        }
1315
1316
        return $rate;
1317
    }
1318
1319
    public static function current_vat_data() {
1320
        return getpaid_session()->get( 'user_vat_data' );
1321
    }
1322
1323
    public static function get_user_country( $country = '', $user_id = 0 ) {
1324
        $user_address = wpinv_get_user_address( $user_id, false );
1325
1326
        $country    = empty( $user_address ) || !isset( $user_address['country'] ) || empty( $user_address['country'] ) ? $country : $user_address['country'];
1327
        $result     = apply_filters( 'wpinv_get_user_country', $country, $user_id );
1328
1329
        if ( empty( $result ) ) {
1330
            $result = getpaid_get_ip_country();
1331
        }
1332
1333
        return $result;
1334
    }
1335
1336
    public static function set_user_country( $country = '', $user_id = 0 ) {
0 ignored issues
show
Unused Code introduced by
The parameter $user_id 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

1336
    public static function set_user_country( $country = '', /** @scrutinizer ignore-unused */ $user_id = 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...
1337
        global $wpi_userID;
1338
1339
        if ( empty($country) && !empty($wpi_userID) && get_current_user_id() != $wpi_userID ) {
1340
            $country = wpinv_get_default_country();
1341
        }
1342
1343
        return $country;
1344
    }
1345
1346
    public static function get_user_vat_number( $vat_number = '', $user_id = 0, $is_valid = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $vat_number 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

1346
    public static function get_user_vat_number( /** @scrutinizer ignore-unused */ $vat_number = '', $user_id = 0, $is_valid = 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...
1347
        global $wpi_current_id, $wpi_userID;
1348
1349
        if ( !empty( $_POST['new_user'] ) ) {
1350
            return '';
1351
        }
1352
1353
        if ( empty( $user_id ) ) {
1354
            $user_id = !empty( $wpi_userID ) ? $wpi_userID : ( $wpi_current_id ? wpinv_get_user_id( $wpi_current_id ) : get_current_user_id() );
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_get_user_id() 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

1354
            $user_id = !empty( $wpi_userID ) ? $wpi_userID : ( $wpi_current_id ? /** @scrutinizer ignore-deprecated */ wpinv_get_user_id( $wpi_current_id ) : get_current_user_id() );
Loading history...
1355
        }
1356
1357
        $vat_number = empty( $user_id ) ? '' : get_user_meta( $user_id, '_wpinv_vat_number', true );
1358
1359
        /* TODO
1360
        if ( $is_valid && $vat_number ) {
1361
            $adddress_confirmed = empty( $user_id ) ? false : get_user_meta( $user_id, '_wpinv_adddress_confirmed', true );
1362
            if ( !$adddress_confirmed ) {
1363
                $vat_number = '';
1364
            }
1365
        }
1366
        */
1367
1368
        return apply_filters('wpinv_get_user_vat_number', $vat_number, $user_id, $is_valid );
1369
    }
1370
1371
    public static function get_user_company( $company = '', $user_id = 0 ) {
0 ignored issues
show
Unused Code introduced by
The parameter $company 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

1371
    public static function get_user_company( /** @scrutinizer ignore-unused */ $company = '', $user_id = 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...
1372
        global $wpi_current_id, $wpi_userID;
1373
1374
        if ( empty( $user_id ) ) {
1375
            $user_id = !empty( $wpi_userID ) ? $wpi_userID : ( $wpi_current_id ? wpinv_get_user_id( $wpi_current_id ) : get_current_user_id() );
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_get_user_id() 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

1375
            $user_id = !empty( $wpi_userID ) ? $wpi_userID : ( $wpi_current_id ? /** @scrutinizer ignore-deprecated */ wpinv_get_user_id( $wpi_current_id ) : get_current_user_id() );
Loading history...
1376
        }
1377
1378
        $company = empty( $user_id ) ? "" : get_user_meta( $user_id, '_wpinv_company', true );
1379
1380
        return apply_filters( 'wpinv_user_company', $company, $user_id );
1381
    }
1382
1383
    public static function save_user_vat_details( $company = '', $vat_number = '' ) {
1384
        $save = apply_filters( 'wpinv_allow_save_user_vat_details', true );
1385
1386
        if ( is_user_logged_in() && $save ) {
1387
            $user_id = get_current_user_id();
1388
1389
            if ( !empty( $vat_number ) ) {
1390
                update_user_meta( $user_id, '_wpinv_vat_number', $vat_number );
1391
            } else {
1392
                delete_user_meta( $user_id, '_wpinv_vat_number');
1393
            }
1394
1395
            if ( !empty( $company ) ) {
1396
                update_user_meta( $user_id, '_wpinv_company', $company );
1397
            } else {
1398
                delete_user_meta( $user_id, '_wpinv_company');
1399
                delete_user_meta( $user_id, '_wpinv_vat_number');
1400
            }
1401
        }
1402
1403
        do_action('wpinv_save_user_vat_details', $company, $vat_number);
1404
    }
1405
1406
    public static function ajax_vat_validate() {
1407
        global $wpinv_options;
1408
1409
        $response               = array();
1410
        $response['success']    = false;
1411
1412
        if ( empty( $_REQUEST['_wpi_nonce'] ) || ( !empty( $_REQUEST['_wpi_nonce'] ) && !wp_verify_nonce( $_REQUEST['_wpi_nonce'], 'vat_validation' ) ) ) {
1413
            $response['error'] = __( 'Invalid security nonce', 'invoicing' );
1414
            wp_send_json( $response );
1415
        }
1416
1417
        $vat_name   = self::get_vat_name();
0 ignored issues
show
Bug Best Practice introduced by
The method WPInv_EUVat::get_vat_name() is not static, but was called statically. ( Ignorable by Annotation )

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

1417
        /** @scrutinizer ignore-call */ 
1418
        $vat_name   = self::get_vat_name();
Loading history...
1418
1419
        $company    = !empty( $_POST['company'] ) ? sanitize_text_field( $_POST['company'] ) : '';
1420
        $vat_number = !empty( $_POST['number'] ) ? sanitize_text_field( $_POST['number'] ) : '';
1421
1422
        $vat_info = getpaid_session()->get( 'user_vat_data' );
1423
        if ( !is_array( $vat_info ) || empty( $vat_info ) ) {
1424
            $vat_info = array( 'company'=> $company, 'number' => '', 'valid' => true );
1425
        }
1426
1427
        if ( empty( $vat_number ) ) {
1428
            $response['error'] = wp_sprintf( __( 'Please enter your %s number!', 'invoicing' ), $vat_name );
1429
            $vat_info['valid'] = false;
1430
            getpaid_session()->set( 'user_vat_data', $vat_info );
1431
            wp_send_json( $response );
1432
        }
1433
1434
        if ( empty( $company ) ) {
1435
            $vat_info['valid'] = false;
1436
            getpaid_session()->set( 'user_vat_data', $vat_info );
1437
1438
            $response['error'] = __( 'Please enter your registered company name!', 'invoicing' );
1439
            wp_send_json( $response );
1440
        }
1441
1442
        if ( !empty( $wpinv_options['vat_vies_check'] ) ) {
1443
            if ( empty( $wpinv_options['vat_offline_check'] ) && !self::offline_check( $vat_number ) ) {
1444
                $vat_info['valid'] = false;
1445
                getpaid_session()->set( 'user_vat_data', $vat_info );
1446
1447
                $response['error'] = wp_sprintf( __( '%s number not validated', 'invoicing' ), $vat_name );
1448
                wp_send_json( $response );
1449
            }
1450
1451
            $response['success'] = true;
1452
            $response['message'] = wp_sprintf( __( '%s number validated', 'invoicing' ), $vat_name );
1453
        } else {
1454
            $result = self::check_vat( $vat_number );
1455
1456
            if ( empty( $result['valid'] ) ) {
1457
                $response['error'] = $result['message'];
1458
                wp_send_json( $response );
1459
            }
1460
1461
            $vies_company = !empty( $result['company'] ) ? $result['company'] : '';
1462
            $vies_company = apply_filters( 'wpinv_vies_company_name', $vies_company );
1463
1464
            $valid_company = $vies_company && $company && ( $vies_company == '---' || strcasecmp( trim( $vies_company ), trim( $company ) ) == 0 ) ? true : false;
1465
1466
            if ( !empty( $wpinv_options['vat_disable_company_name_check'] ) || $valid_company ) {
1467
                $response['success'] = true;
1468
                $response['message'] = wp_sprintf( __( '%s number validated', 'invoicing' ), $vat_name );
1469
            } else {
1470
                $vat_info['valid'] = false;
1471
                getpaid_session()->set( 'user_vat_data', $vat_info );
1472
1473
                $response['success'] = false;
1474
                $response['message'] = wp_sprintf( __( 'The company name associated with the %s number provided is not the same as the company name provided.', 'invoicing' ), $vat_name );
1475
                wp_send_json( $response );
1476
            }
1477
        }
1478
1479
        wp_send_json( $response );
1480
    }
1481
1482
    /**
1483
     * Validates a vat number.
1484
     * 
1485
     * @return string
1486
     */
1487
    public static function validate_vat_number( $vat_number, $company, $country ) {
1488
        global $wpinv_options;
1489
1490
        // If we are not checking the vat number via view...
1491
        if ( ! empty( $wpinv_options['vat_vies_check'] ) ) {
1492
1493
            // Try validating via regex.
1494
            if ( empty( $wpinv_options['vat_offline_check'] ) && ! self::offline_check( $vat_number, $country ) ) {
1495
                return wp_sprintf(
1496
                    __( 'Your %s number is invalid', 'invoicing' ),
1497
                    getpaid_vat_name()
1498
                );
1499
            }
1500
1501
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
1502
        }
1503
1504
        // Validate the vat number.
1505
        $result = self::check_vat( $vat_number, $country );
1506
1507
        if ( empty( $result['valid'] ) ) {
1508
            return wp_sprintf(
1509
                __( 'Failed to validate the %s number via EU Commission VAT server (VIES).', 'invoicing' ),
1510
                getpaid_vat_name()
1511
            );
1512
        }
1513
1514
        // Validate the company.
1515
        $vies_company  = ! empty( $result['company'] ) ? $result['company'] : '';
1516
        $vies_company  = apply_filters( 'wpinv_vies_company_name', $vies_company );
1517
        $valid_company = $vies_company && $company && ( $vies_company == '---' || strcasecmp( trim( $vies_company ), trim( $company ) ) == 0 ) ? true : false;
1518
1519
        if ( ! $valid_company && ! empty( $wpinv_options['vat_disable_company_name_check'] ) ) {
1520
           return wp_sprintf(
1521
                __( 'The company name associated with the %s number provided is not the same as the company name provided.', 'invoicing' ),
1522
                getpaid_vat_name()
1523
            );
1524
        }
1525
1526
        return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type string.
Loading history...
1527
    }
1528
1529
}
1530
1531