PluginProbe ʕ •ᴥ•ʔ
TaxCloud for WooCommerce / 8.4.11
TaxCloud for WooCommerce v8.4.11
8.4.11 8.4.10 8.4.9 trunk 6.0.11 6.0.12 6.0.13 6.0.14 6.1.0 6.1.1 6.1.2 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.3.0 6.3.1 6.3.10 6.3.11 6.3.12 6.3.13 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.3.8 6.3.9 7.0.0 7.0.1 7.0.10 7.0.11 7.0.12 7.0.13 7.0.2 7.0.3 7.0.4 7.0.5 7.0.6 7.0.7 7.0.8 7.0.9 8.0.0 8.0.1 8.0.10 8.0.11 8.0.12 8.0.13 8.0.14 8.0.15 8.0.16 8.0.17 8.0.2 8.0.3 8.0.4 8.0.5 8.0.6 8.0.7 8.0.8 8.0.9 8.1.0 8.1.1 8.2.0 8.2.1 8.2.2 8.2.3 8.2.4 8.3.0 8.3.1 8.3.2 8.3.3 8.3.4 8.3.5 8.3.6 8.3.7 8.3.8 8.4.0 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.4.6 8.4.7 8.4.8
simple-sales-tax / includes / class-sst-ajax.php
simple-sales-tax / includes Last commit date
abstracts 3 months ago admin 3 months ago frontend 1 month ago integrations 1 month ago v3 3 months ago vendor 6 days ago views 8 months ago class-simplesalestax.php 6 days ago class-sst-addresses.php 1 month ago class-sst-ajax.php 3 months ago class-sst-assets.php 6 months ago class-sst-blocks-integration.php 1 month ago class-sst-blocks.php 1 year ago class-sst-certificates.php 6 days ago class-sst-install.php 6 months ago class-sst-logger.php 5 months ago class-sst-marketplaces.php 6 months ago class-sst-order-controller.php 3 months ago class-sst-order.php 1 month ago class-sst-origin-address.php 8 months ago class-sst-product.php 3 months ago class-sst-rate-limit.php 5 months ago class-sst-settings.php 3 months ago class-sst-shipping.php 3 years ago class-sst-taxcloud-v3-api.php 3 months ago class-sst-taxcloud-v3.php 3 months ago class-sst-tic.php 2 years ago class-sst-updater.php 3 years ago sst-compatibility-functions.php 4 months ago sst-functions.php 6 days ago sst-message-functions.php 3 years ago sst-update-functions.php 11 months ago
class-sst-ajax.php
389 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit; // Exit if accessed directly.
5 }
6
7 /**
8 * SST Ajax.
9 *
10 * Ajax functions.
11 *
12 * @author Simple Sales Tax
13 * @package SST
14 * @since 5.0
15 */
16 class SST_Ajax {
17
18 /**
19 * AJAX Hooks.
20 *
21 * @var array
22 * @since 5.0
23 */
24 private static $hooks = array(
25 'sst_verify_taxcloud' => false,
26 'sst_delete_certificate' => false,
27 'sst_add_certificate' => false,
28 'woocommerce_calc_line_taxes' => false,
29 'sst_get_certificates' => false,
30 'sst_dismiss_taxcloud_notice' => false,
31 'sst_get_order_log' => false,
32 'sst_update_data_mover' => false,
33 );
34
35 /**
36 * Initialize hooks.
37 *
38 * @since 5.0
39 */
40 public static function init() {
41 foreach ( self::$hooks as $hook => $nopriv ) {
42 $function = str_replace( array( 'woocommerce_', 'sst_' ), '', $hook );
43
44 /* If we are overriding a woo hook, give ours higher priority */
45 if ( 0 === strpos( $hook, 'woocommerce_' ) ) {
46 $priority = 1;
47 } else {
48 $priority = 10;
49 }
50
51 add_action( "wp_ajax_$hook", array( __CLASS__, $function ), $priority );
52
53 if ( $nopriv ) {
54 add_action( "wp_ajax_nopriv_$hook", array( __CLASS__, $function ), $priority );
55 }
56 }
57 }
58
59 /**
60 * Verify the user's TaxCloud API Login ID and API Key.
61 *
62 * @since 5.0
63 */
64 public static function verify_taxcloud() {
65 $taxcloud_id = '';
66 $taxcloud_key = '';
67
68 // Verify nonce.
69 check_ajax_referer( 'sst_verify_taxcloud_nonce' );
70
71 if ( isset( $_POST['wootax_tc_id'] ) ) {
72 $taxcloud_id = sanitize_text_field( wp_unslash( $_POST['wootax_tc_id'] ) ); // phpcs:ignore WordPress.CSRF.NonceVerification
73 }
74 if ( isset( $_POST['wootax_tc_key'] ) ) {
75 $taxcloud_key = sanitize_text_field( wp_unslash( $_POST['wootax_tc_key'] ) ); // phpcs:ignore WordPress.CSRF.NonceVerification
76 }
77
78 if ( empty( $taxcloud_id ) || empty( $taxcloud_key ) ) {
79 wp_send_json_error();
80 } else {
81 try {
82 TaxCloud()->Ping( new TaxCloud\Request\Ping( $taxcloud_id, $taxcloud_key ) );
83
84 // Ping successful, update data mover settings
85 SST_TaxCloud_V3_API::update_data_mover_settings( $taxcloud_id, $taxcloud_key );
86
87 wp_send_json_success( array(
88 'connection_id' => SST_Settings::get( 'tc_connection_id' ),
89 ) );
90 } catch ( Exception $ex ) {
91 wp_send_json_error( $ex->getMessage() );
92 }
93 }
94 }
95
96 /**
97 * Respond when user requests to delete a certificate.
98 *
99 * @since 5.0
100 */
101 public static function delete_certificate() {
102 $nonce = sanitize_text_field(
103 wp_unslash( $_POST['nonce'] ?? '' )
104 );
105
106 if ( ! wp_verify_nonce( $nonce, 'sst_delete_certificate' ) ) {
107 return;
108 }
109
110 $certificate_id = sanitize_text_field(
111 wp_unslash( $_POST['certificate_id'] ?? '' )
112 );
113 $user_id = absint(
114 wp_unslash( $_POST['user_id'] ?? 0 )
115 );
116
117 try {
118 SST_Certificates::delete_certificate( $certificate_id, $user_id );
119
120 wp_send_json_success(
121 array( 'certificates' => SST_Certificates::get_certificates_formatted( $user_id ) )
122 );
123 } catch ( Exception $ex ) { /* Failed to delete */
124 wp_send_json_error( $ex->getMessage() );
125 }
126 }
127
128 /**
129 * Add an exemption certificate for the customer.
130 *
131 * NOTE: Single purchase exemption certificates not supported at this
132 * time.
133 *
134 * @since 5.0
135 */
136 public static function add_certificate() {
137 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
138
139 // Handle invalid requests.
140 if ( ! wp_verify_nonce( $nonce, 'sst_add_certificate' ) ) {
141 return;
142 }
143
144 if ( ! isset( $_POST['address'], $_POST['certificate'] ) ) {
145 wp_send_json_error( __( 'Invalid request.', 'simple-sales-tax' ) );
146 }
147
148 // Get data.
149 $certificate = array_map(
150 'sanitize_text_field',
151 wp_unslash( $_POST['certificate'] )
152 ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
153 $address = array_map(
154 'sanitize_text_field',
155 wp_unslash( $_POST['address'] )
156 ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
157 $user_id = absint( $_POST['user_id'] ?? 0 );
158
159 // Add certificate.
160 try {
161 $certificate_id = SST_Certificates::add_certificate(
162 $certificate,
163 $address,
164 $user_id
165 );
166
167 wp_send_json_success(
168 array(
169 'certificate_id' => $certificate_id,
170 'certificates' => SST_Certificates::get_certificates_formatted( $user_id ),
171 )
172 );
173 } catch ( Throwable $ex ) {
174 wp_send_json_error( $ex->getMessage() );
175 }
176 }
177
178 /**
179 * Lists all exemption certificates available for a customer.
180 * Used to populate the Exemption Certificate dropdown on the
181 * Edit Order screen.
182 *
183 * @since 7.0.0
184 */
185 public static function get_certificates() {
186 check_ajax_referer( 'sst_get_certificates', 'nonce' );
187
188 $user_id = intval( wp_unslash( $_REQUEST['customerId'] ) );
189 $certificates = array();
190
191 if ( current_user_can( 'edit_user', $user_id ) ) {
192 // Get certificates in select2 data format.
193 $certificates = SST_Certificates::get_certificates_formatted(
194 $user_id
195 );
196 }
197
198 wp_send_json_success( $certificates );
199 }
200
201 /**
202 * Gets a string describing an exemption certificate.
203 *
204 * @param array $certificate Certificate data.
205 *
206 * @return string
207 */
208 protected static function get_certificate_text( $certificate ) {
209 return $certificate['CertificateID'];
210 }
211
212 /**
213 * Recalculate sales tax via AJAX.
214 *
215 * @since 4.2
216 */
217 public static function calc_line_taxes() {
218 check_ajax_referer( 'calc-totals', 'security' );
219
220 if ( ! current_user_can( 'edit_shop_orders' ) ) {
221 wp_die( -1 );
222 }
223
224 if ( ! isset( $_POST['order_id'], $_POST['country'], $_POST['state'], $_POST['postcode'], $_POST['city'], $_POST['items'] ) ) {
225 wp_die( -1 );
226 }
227
228 $items = array();
229 $order_id = absint( $_POST['order_id'] );
230 $country = strtoupper( sanitize_text_field( wp_unslash( $_POST['country'] ) ) );
231 $state = strtoupper( sanitize_text_field( wp_unslash( $_POST['state'] ) ) );
232 $postcode = strtoupper( sanitize_text_field( wp_unslash( $_POST['postcode'] ) ) );
233 $city = sanitize_text_field( wp_unslash( $_POST['city'] ) );
234 $certificate_id = sanitize_text_field(
235 wp_unslash( $_POST['exemption_certificate'] ?? '' )
236 );
237
238 // Let Woo take the reins if the customer is international.
239 if ( 'US' !== $country ) {
240 return;
241 }
242
243 // Parse jQuery serialized items.
244 $raw_items = sanitize_text_field( wp_unslash( $_POST['items'] ) );
245 parse_str( $raw_items, $items );
246
247 $items = wc_clean( $items );
248
249 // Save items and recalc taxes.
250 wc_save_order_items( $order_id, $items );
251
252 $order = wc_get_order( $order_id );
253 $posted_address = compact(
254 'country',
255 'state',
256 'city',
257 'postcode'
258 );
259
260 self::ensure_order_address( $order, 'billing', $posted_address );
261 self::ensure_order_address( $order, 'shipping', $posted_address );
262
263 $order->update_meta_data( '_wootax_exempt_cert', $certificate_id );
264
265 $result = sst_order_calculate_taxes( $order );
266
267 if ( is_wp_error( $result ) ) {
268 wp_die( $result->get_error_message() ); // phpcs:ignore WordPress.Security.EscapeOutput
269 }
270
271 include WC()->plugin_path() . '/includes/admin/meta-boxes/views/html-order-items.php';
272
273 wp_die();
274 }
275
276 /**
277 * Ensures that an order has an address set before taxes are calculated.
278 *
279 * @param WC_Order $order Order object.
280 * @param string $type Address type. Can be 'billing' or 'shipping'.
281 * @param array $address POSTed address data.
282 */
283 protected static function ensure_order_address( $order, $type, $address ) {
284 try {
285 foreach ( $address as $field => $value ) {
286 if ( empty( $order->{"get_{$type}_{$field}"}() ) ) {
287 $order->{"set_{$type}_{$field}"}( $value );
288 }
289 }
290 } catch ( WC_Data_Exception $ex ) {
291 wc_get_logger()->error(
292 sprintf( 'Failed to set %s address for order #%d: %s', $type, $order->get_id(), $ex->getMessage() )
293 );
294 }
295 }
296
297 /**
298 * Dismiss a TaxCloud admin notice.
299 *
300 * @since 8.3.6
301 */
302 public static function dismiss_taxcloud_notice() {
303 check_ajax_referer( 'dismiss_taxcloud_notice', 'nonce' );
304 $id = sanitize_text_field( wp_unslash( $_POST['notice_id'] ) );
305 $dismissed_notices = SST_Settings::get( 'dismissed_notices', [] );
306 if ( ! in_array( $id, $dismissed_notices, true ) ) {
307 $dismissed_notices[] = $id;
308 SST_Settings::set( 'dismissed_notices', $dismissed_notices );
309 }
310 wp_send_json_success( SST_Settings::get( 'dismissed_notices', [] ) );
311 }
312
313 /**
314 * Get the order log.
315 *
316 * @since 8.3.5
317 */
318 public static function get_order_log() {
319 // Verify nonce.
320 check_ajax_referer( 'sst-debug-order-nonce' );
321
322 // Get the order ID.
323 $order_id = (int) sanitize_text_field( wp_unslash( $_POST['order_id'] ) );
324
325 // Order object.
326 $order = wc_get_order( $order_id );
327 if ( ! $order ) {
328 wp_send_json_error( __( 'Invalid order ID.', 'simple-sales-tax' ) );
329 }
330
331 // Meta keys
332 $meta_keys = [
333 '_wootax_status',
334 '_wootax_db_version',
335 '_wootax_exempt_cert',
336 '_shipping_address_index',
337 '_wootax_packages',
338 ];
339
340 // Get Woo Order status
341 $order_meta['order_status'] = $order->get_status();
342
343 // Get customer ID
344 $order_meta['customer_id'] = $order->get_customer_id();
345
346 // Totals
347 $order_meta['total'] = $order->get_total();
348 $order_meta['shipping'] = $order->get_shipping_total();
349 $order_meta['tax'] = $order->get_total_tax();
350
351 // Get order meta.
352 foreach ( $meta_keys as $key ) {
353 $order_meta[ $key ] = maybe_unserialize( $order->get_meta( $key, true ) );
354 }
355
356 // Logging
357 SST_Logger::order_log( __( 'View Order Debug Log triggered.', 'simple-sales-tax' ), $order_id, $order_meta );
358
359 wp_send_json_success();
360 }
361
362 /**
363 * Update Data Mover settings.
364 *
365 * @since 8.3.5
366 */
367 public static function update_data_mover() {
368 // Verify nonce.
369 check_ajax_referer( 'sst-update-data-mover-nonce' );
370
371 // Update data mover settings
372 SST_TaxCloud_V3_API::update_data_mover_settings();
373
374 // Get data mover settings
375 $data_mover = SST_Settings::get( 'data_mover', false );
376 $integration_mode = $data_mover == false ? __( 'Real Time', 'simple-sales-tax' ) : __( 'Data Import', 'simple-sales-tax' );
377
378 // Response
379 wp_send_json_success( [
380 'integration_mode' => $integration_mode,
381 'data_mover' => $data_mover,
382 'connection_id' => SST_Settings::get( 'tc_connection_id' ),
383 ] );
384 }
385
386 }
387
388 SST_Ajax::init();
389