Passed
Push — master ( b3b246...bcec86 )
by Brian
05:30
created

GetPaid_Payment_Form_Submission_Taxes   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 246
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 37
eloc 69
c 1
b 0
f 0
dl 0
loc 246
rs 9.44

9 Methods

Rating   Name   Duplication   Size   Complexity  
A has_digital_item() 0 12 3
A requires_vat() 0 7 3
B validate_vat() 0 39 9
A set_error() 0 3 2
A is_eu_transaction() 0 13 6
A get_company() 0 11 3
A __construct() 0 24 4
A process_item_tax() 0 19 4
A get_vat_number() 0 11 3
1
<?php
2
/**
3
 * Processes taxes for a payment form submission.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * Payment form submission taxes class
11
 *
12
 */
13
class GetPaid_Payment_Form_Submission_Taxes {
14
15
	/**
16
	 * The tax validation error.
17
	 * @var string
18
	 */
19
	public $tax_error;
20
21
	/**
22
	 * Submission taxes.
23
	 * @var array
24
	 */
25
	public $taxes = array();
26
27
	/**
28
	 * Initial tax.
29
	 * @var float
30
	 */
31
	protected $initial_tax = 0;
32
33
	/**
34
	 * Recurring tax.
35
	 * @var float
36
	 */
37
	protected $recurring_tax = 0;
38
39
    /**
40
	 * Class constructor
41
	 *
42
	 * @param GetPaid_Payment_Form_Submission $submission
43
	 */
44
	public function __construct( $submission ) {
45
46
		// Make sure that taxes are enabled.
47
		if ( ! $submission->use_taxes() ) {
48
			return;
49
		}
50
51
		// Validate VAT number.
52
		$this->validate_vat( $submission );
53
54
		foreach ( $submission->get_items() as $item ) {
55
			$this->process_item_tax( $item, $submission );
56
		}
57
58
		// Process any existing invoice taxes.
59
		if ( $submission->has_invoice() ) {
60
			$this->taxes = $submission->get_invoice()->get_taxes();
61
		}
62
63
		// Add VAT.
64
		$this->taxes['vat'] = array(
65
			'name'          => 'vat',
66
			'initial_tax'   => $this->initial_tax,
67
			'recurring_tax' => $this->recurring_tax,
68
		);
69
70
	}
71
72
	/**
73
	 * Maybe process tax.
74
	 *
75
	 * @since 1.0.19
76
	 * @param GetPaid_Form_Item $item
77
	 * @param GetPaid_Payment_Form_Submission $submission
78
	 */
79
	public function process_item_tax( $item, $submission ) {
80
81
		// Abort early if an error occurred.
82
		if ( ! empty( $this->tax_error ) ) {
83
			return;
84
		}
85
86
		$rate     = wpinv_get_tax_rate( $submission->country, $submission->state, $item->get_id() );
87
		$price    = $item->get_sub_total();
88
		$item_tax = $price * $rate * 0.01;
89
90
		if ( wpinv_prices_include_tax() ) {
91
			$item_tax = $price - ( $price - $price * $rate * 0.01 );
92
		}
93
94
		$this->initial_tax += $item_tax;
95
96
		if ( $item->is_recurring() ) {
97
			$this->recurring_tax += $item_tax;
98
		}
99
100
	}
101
102
	/**
103
	 * Sets an error without overwriting the previous error.
104
	 *
105
	 * @param string $error
106
	 */
107
	public function set_error( $error ) {
108
		if ( empty( $this->tax_error ) ) {
109
			$this->tax_error = $error;
110
		}
111
	}
112
113
	/**
114
	 * Checks if the submission has a digital item.
115
	 *
116
	 * @param GetPaid_Payment_Form_Submission $submission
117
	 * @since 1.0.19
118
	 * @return bool
119
	 */
120
	public function has_digital_item( $submission ) {
121
122
		foreach ( $submission->get_items() as $item ) {
123
124
			if ( 'digital' == $item->get_vat_rule() ) {
125
				return true;
126
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
127
			}
128
129
		}
130
131
		return false;
132
	}
133
134
	/**
135
	 * Checks if this is an eu purchase.
136
	 *
137
	 * @param GetPaid_Payment_Form_Submission $submission
138
	 * @param bool                            $has_digital
139
	 * @since 1.0.19
140
	 * @return bool
141
	 */
142
	public function is_eu_transaction( $submission, $has_digital ) {
143
144
		// Both from EU.
145
		if ( getpaid_is_eu_state( $submission->country ) && ( getpaid_is_eu_state( wpinv_get_default_country() ) || $has_digital ) ) {
146
			return true;
147
		}
148
149
		// Both from GST.
150
		if ( getpaid_is_gst_country( $submission->country ) && getpaid_is_gst_country( wpinv_get_default_country() ) ) {
151
			return true;
152
		}
153
154
		return false;
155
	}
156
157
	/**
158
	 * Retrieves the vat number.
159
	 *
160
	 * @param GetPaid_Payment_Form_Submission $submission
161
	 * @since 1.0.19
162
	 * @return string
163
	 */
164
	public function get_vat_number( $submission ) {
165
166
		$data = $submission->get_data();
167
168
		// Retrieve from the posted number.
169
		if ( ! empty( $data['wpinv_vat_number'] ) ) {
170
			return wpinv_clean( $data['wpinv_vat_number'] );
0 ignored issues
show
Bug Best Practice introduced by
The expression return wpinv_clean($data['wpinv_vat_number']) also could return the type array which is incompatible with the documented return type string.
Loading history...
171
		}
172
173
		// Retrieve from the invoice.
174
		return $submission->has_invoice() ? $submission->get_invoice()->get_vat_number() : '';
175
	}
176
177
	/**
178
	 * Retrieves the company.
179
	 *
180
	 * @param GetPaid_Payment_Form_Submission $submission
181
	 * @since 1.0.19
182
	 * @return string
183
	 */
184
	public function get_company( $submission ) {
185
186
		$data = $submission->get_data();
187
188
		// Retrieve from the posted data.
189
		if ( ! empty( $data['wpinv_company'] ) ) {
190
			return wpinv_clean( $data['wpinv_company'] );
0 ignored issues
show
Bug Best Practice introduced by
The expression return wpinv_clean($data['wpinv_company']) also could return the type array which is incompatible with the documented return type string.
Loading history...
191
		}
192
193
		// Retrieve from the invoice.
194
		return $submission->has_invoice() ? $submission->get_invoice()->get_company() : '';
195
	}
196
197
	/**
198
	 * Retrieves the company.
199
	 *
200
	 * @param bool $ip_in_eu Whether the selected IP is from the EU
201
	 * @param bool $country_in_eu Whether the selected country is from the EU
202
	 * @since 1.0.19
203
	 * @return string
204
	 */
205
	public function requires_vat( $ip_in_eu, $country_in_eu ) {
206
207
		$prevent_b2c = wpinv_get_option( 'vat_prevent_b2c_purchase' );
208
		$prevent_b2c = ! empty( $prevent_b2c );
209
		$is_eu       = $ip_in_eu || $country_in_eu;
210
211
		return $prevent_b2c && $is_eu;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $prevent_b2c && $is_eu returns the type boolean which is incompatible with the documented return type string.
Loading history...
212
	}
213
214
	/**
215
	 * Validate VAT data.
216
	 *
217
	 * @param GetPaid_Payment_Form_Submission $submission
218
	 * @since 1.0.19
219
	 */
220
	public function validate_vat( $submission ) {
221
222
		$has_digital = $this->has_digital_item( $submission );
223
		$in_eu       = $this->is_eu_transaction( $submission, $has_digital );
224
225
		// Abort if we are not validating vat numbers.
226
		if ( ! $has_digital && ! $in_eu ) {
227
            return;
228
		}
229
230
		// Prepare variables.
231
		$vat_number  = $this->get_vat_number( $submission );
232
		$company     = $this->get_company( $submission );
233
		$ip_country  = WPInv_EUVat::get_country_by_ip();
234
        $is_eu       = getpaid_is_eu_state( $submission->country );
235
        $is_ip_eu    = getpaid_is_eu_state( $ip_country );
236
237
		// If we're preventing business to consumer purchases, ensure
238
		if ( $this->requires_vat( $is_ip_eu, $is_eu ) && empty( $vat_number ) ) {
239
240
			// Ensure that a vat number has been specified.
241
			return $this->set_error(
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->set_error(wp_spri...), getpaid_vat_name())) targeting GetPaid_Payment_Form_Submission_Taxes::set_error() seems to always return null.

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

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

}

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

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

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

Loading history...
242
				wp_sprintf(
243
					__( 'Please enter your %s number to verify your purchase is by an EU business.', 'invoicing' ),
244
					getpaid_vat_name()
245
				)
246
			);
247
248
		}
249
250
		// Abort if we are not validating vat (vat number should exist, user should be in eu and business too).
251
		if ( ! $is_eu || ! $in_eu || empty( $vat_number ) ) {
252
            return;
253
		}
254
255
		$is_valid = WPInv_EUVat::validate_vat_number( $vat_number, $company, $submission->country );
256
257
		if ( is_string( $is_valid ) ) {
0 ignored issues
show
introduced by
The condition is_string($is_valid) is always true.
Loading history...
258
			$this->set_error( $is_valid );
259
		}
260
261
	}
262
263
}
264