PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 3.7.1
Tutor LMS – eLearning and online course solution v3.7.1
3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / ecommerce / Tax.php
tutor / ecommerce Last commit date
Cart 1 year ago PaymentGateways 11 months ago AdminMenu.php 1 year ago BillingController.php 1 year ago CartController.php 1 year ago CheckoutController.php 11 months ago CouponController.php 11 months ago Ecommerce.php 1 year ago EmailController.php 11 months ago HooksHandler.php 11 months ago OptionKeys.php 1 year ago OrderActivitiesController.php 1 year ago OrderController.php 11 months ago PaymentHandler.php 11 months ago Settings.php 1 year ago Tax.php 11 months ago currency.php 1 year ago
Tax.php
337 lines
1 <?php
2 /**
3 * Tax calculation class for tutor monetization.
4 *
5 * @package Tutor\Ecommerce
6 * @author Themeum
7 * @link https://themeum.com
8 * @since 3.0.0
9 */
10
11 namespace Tutor\Ecommerce;
12
13 use Tutor\Traits\JsonResponse;
14
15 /**
16 * Class Tax
17 *
18 * @since 3.0.0
19 */
20 class Tax {
21 use JsonResponse;
22
23 /**
24 * Tax type const.
25 */
26 const TYPE_INCLUSIVE = 'inclusive';
27 const TYPE_EXCLUSIVE = 'exclusive';
28
29 /**
30 * Register hooks and dependencies.
31 *
32 * @since 3.0.0
33 *
34 * @param boolean $register_hooks hook register or not.
35 */
36 public function __construct( $register_hooks = true ) {
37 if ( ! $register_hooks ) {
38 return;
39 }
40
41 add_filter( 'tutor_option_input', array( $this, 'format_tax_data_before_save' ) );
42 add_action( 'wp_ajax_tutor_get_tax_settings', array( $this, 'ajax_get_tax_settings' ) );
43 }
44
45 /**
46 * Format ecommerce tax setting data before save it to tutor settings.
47 *
48 * @param array $option option.
49 *
50 * @return array
51 */
52 public function format_tax_data_before_save( $option ) {
53 if ( ! empty( $option['ecommerce_tax'] ) ) {
54 $option['ecommerce_tax'] = wp_unslash( $option['ecommerce_tax'] );
55 }
56
57 return $option;
58 }
59
60 /**
61 * Get the tax settings from the tutor options.
62 *
63 * @since 3.0.0
64 *
65 * @return void
66 */
67 public function ajax_get_tax_settings() {
68 tutor_utils()->checking_nonce();
69 tutor_utils()->check_current_user_capability();
70
71 $tax_settings = self::get_settings();
72
73 if ( ! empty( $tax_settings->active_country ) ) {
74 $tax_settings->active_country = null;
75 }
76
77 $this->json_response( __( 'Success', 'tutor' ), $tax_settings );
78 }
79
80 /**
81 * Get tax settings.
82 *
83 * @since 3.0.0
84 *
85 * @return object
86 */
87 public static function get_settings() {
88 $tax_settings = tutor_utils()->get_option( 'ecommerce_tax' );
89
90 if ( ! empty( $tax_settings ) && is_string( $tax_settings ) ) {
91 $tax_settings = json_decode( $tax_settings );
92 }
93
94 return $tax_settings;
95 }
96
97 /**
98 * Get tax settings key data.
99 *
100 * @since 3.0.0
101 *
102 * @param string $key key.
103 * @param mixed $default default value.
104 *
105 * @return mixed
106 */
107 public static function get_setting( $key, $default = false ) {
108 $tax_settings = self::get_settings();
109
110 if ( isset( $tax_settings->$key ) ) {
111 return $tax_settings->$key;
112 }
113
114 return $default;
115 }
116
117 /**
118 * Check individual tax control is enabled or not.
119 *
120 * @since 3.7.0
121 *
122 * @return boolean
123 */
124 public static function is_individual_control_enabled() {
125 return self::get_setting( 'enable_individual_tax_control', false );
126 }
127
128 /**
129 * Should calculate tax or not.
130 *
131 * @since 3.7.0
132 *
133 * @return boolean
134 */
135 public static function should_calculate_tax() {
136 return self::get_setting( 'enable_tax', true ) && self::is_tax_configured();
137 }
138
139 /**
140 * Calculate tax.
141 *
142 * @since 3.0.0
143 *
144 * @param float $amount amount.
145 * @param float $rate tax rate.
146 *
147 * @return float
148 */
149 public static function calculate_tax( $amount, $rate ) {
150 if ( 0 === $rate ) {
151 return $rate;
152 }
153
154 if ( self::is_tax_included_in_price() ) {
155 // Tax = (Tax Rate X Price) / (1 + Tax Rate).
156 // Amount Without Tax = Amount With Tax / (1 + Tax Rate).
157 $tax_rate = $rate / 100;
158 $tax = ( $tax_rate * $amount ) / ( 1 + $tax_rate );
159 } else {
160 try {
161 $tax = $amount * ( $rate / 100 );
162 } catch ( \Throwable $th ) {
163 $tax = 0.0;
164 }
165 }
166
167 // Tax amount should not negative value.
168 return max( 0, round( $tax, 2 ) );
169 }
170
171 /**
172 * Get text rate for a user according to billing country and state.
173 *
174 * @param integer $user_id user id.
175 *
176 * @return float tax rate.
177 */
178 public static function get_user_tax_rate( $user_id = 0 ) {
179 $billing_info = ( new BillingController( false ) )->get_billing_info( $user_id );
180 $billing_country = $billing_info->billing_country ?? '';
181 $billing_state = $billing_info->billing_state ?? '';
182
183 return self::get_country_state_tax_rate( $billing_country, $billing_state );
184 }
185
186 /**
187 * Check site admin configured tax or not.
188 *
189 * @since 3.0.0
190 *
191 * @return boolean
192 */
193 public static function is_tax_configured() {
194 $tax_settings = self::get_settings();
195
196 return ( is_object( $tax_settings )
197 && isset( $tax_settings->rates )
198 && count( $tax_settings->rates ) );
199 }
200
201 /**
202 * Check tax is included in price or not.
203 *
204 * @since 3.0.0
205 *
206 * @return boolean
207 */
208 public static function is_tax_included_in_price() {
209 return (bool) self::get_setting( 'is_tax_included_in_price' );
210 }
211
212 /**
213 * Show price with tax in course list and details.
214 *
215 * @since 3.0.0
216 *
217 * @return bool
218 */
219 public static function show_price_with_tax() {
220 return (bool) self::get_setting( 'show_price_with_tax' );
221 }
222
223 /**
224 * Get tax type.
225 *
226 * @since 3.0.0
227 *
228 * @return string
229 */
230 public static function get_tax_type() {
231 return self::is_tax_included_in_price() ? self::TYPE_INCLUSIVE : self::TYPE_EXCLUSIVE;
232 }
233
234 /**
235 * Get country rate.
236 *
237 * @since 3.0.0
238 *
239 * @since 3.3.0 Country param is optional
240 *
241 * @param string $country the country code for which the tax rate needs to be found.
242 * @param string $state state name.
243 *
244 * @return float tax rate value.
245 */
246 public static function get_country_state_tax_rate( $country = null, $state = null ) {
247 $zero_tax = 0.0;
248
249 $country = apply_filters( 'tutor_ecommerce_tax_country', $country );
250 $state = apply_filters( 'tutor_ecommerce_tax_state', $state );
251
252 if ( empty( $country ) ) {
253 return $zero_tax;
254 }
255
256 $country_info = self::get_country_info( $country );
257 if ( ! $country_info ) {
258 return $zero_tax;
259 }
260
261 $country_code = $country_info['numeric_code'] ?? '';
262 $country_rate_data = null;
263
264 $tax_settings = self::get_settings();
265 if ( empty( $tax_settings->rates ) ) {
266 return $zero_tax;
267 }
268
269 foreach ( $tax_settings->rates as $rate ) {
270 if ( $rate->country === $country_code ) {
271 $country_rate_data = $rate;
272 break;
273 }
274 }
275
276 if ( empty( $country_rate_data ) ) {
277 return $zero_tax;
278 }
279
280 if ( $country_rate_data->is_same_rate || 0 === count( $country_rate_data->states ) ) {
281 return floatval( $country_rate_data->rate );
282 } else {
283 // Get state rate.
284 $state_info = self::get_state_info( $country_info['states'], $state );
285 if ( empty( $state_info ) ) {
286 return $zero_tax;
287 }
288
289 $state_rate = null;
290 foreach ( $country_rate_data->states as $item ) {
291 if ( $item->id === $state_info['id'] ) {
292 $state_rate = floatval( $item->rate );
293 break;
294 }
295 }
296
297 return $state_rate;
298 }
299 }
300
301 /**
302 * Get country info by name.
303 *
304 * @since 3.0.0
305 *
306 * @param string $name name of country.
307 *
308 * @return array|null
309 */
310 public static function get_country_info( $name ) {
311 $countries = tutor_get_country_list();
312 foreach ( $countries as $country ) {
313 if ( strtolower( $country['name'] ) === strtolower( $name ) ) {
314 return $country;
315 }
316 }
317 }
318
319 /**
320 * Get state info of a country.
321 *
322 * @since 3.0.0
323 *
324 * @param array $states list of states of a country.
325 * @param string $state_name name of state.
326 *
327 * @return array|null
328 */
329 public static function get_state_info( $states, $state_name ) {
330 foreach ( $states as $state ) {
331 if ( strtolower( $state['name'] ) === strtolower( $state_name ) ) {
332 return $state;
333 }
334 }
335 }
336 }
337