PluginProbe ʕ •ᴥ•ʔ
WooCommerce Square / 5.3.2
WooCommerce Square v5.3.2
5.4.1 5.4.0 trunk 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.7.0 2.8.0 2.9.0 2.9.1 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.2.0 3.3.0 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.7.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 4.0.0 4.1.0 4.2.0 4.2.1 4.2.2 4.2.3 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.4.2 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.6.2 4.6.3 4.6.4 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.8.4 4.8.5 4.8.6 4.8.7 4.8.8 4.9.0 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.6 4.9.7 4.9.8 4.9.9 5.0.0 5.0.1 5.1.0 5.1.1 5.1.2 5.2.0 5.3.0 5.3.1 5.3.2 5.3.3
woocommerce-square / includes / AJAX.php
woocommerce-square / includes Last commit date
API 4 months ago Admin 4 months ago Emails 1 year ago Framework 3 months ago Gateway 3 months ago Handlers 3 months ago Sync 6 months ago Utilities 3 months ago AJAX.php 2 years ago API.php 4 months ago Admin.php 10 months ago Coupons.php 4 months ago Functions.php 3 years ago Gateway.php 3 months ago Lifecycle.php 2 years ago Plugin.php 4 months ago Settings.php 4 months ago WC_Order_Square.php 2 years ago WC_Payments_Compatibility.php 1 year ago
AJAX.php
379 lines
1 <?php
2 /**
3 * WooCommerce Square
4 *
5 * This source file is subject to the GNU General Public License v3.0
6 * that is bundled with this package in the file license.txt.
7 * It is also available through the world-wide-web at this URL:
8 * http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0 or later
9 * If you did not receive a copy of the license and are unable to
10 * obtain it through the world-wide-web, please send an email
11 * to license@woocommerce.com so we can send you a copy immediately.
12 *
13 * DISCLAIMER
14 *
15 * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16 * versions in the future. If you wish to customize WooCommerce Square for your
17 * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18 *
19 * @author WooCommerce
20 * @copyright Copyright: (c) 2019, Automattic, Inc.
21 * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0 or later
22 */
23
24 namespace WooCommerce\Square;
25
26 defined( 'ABSPATH' ) || exit;
27
28 use WooCommerce\Square\Handlers\Product;
29 use WooCommerce\Square\Sync\Records;
30
31 /**
32 * AJAX handler.
33 *
34 * @since 2.0.0
35 */
36 class AJAX {
37
38
39 /**
40 * Adds AJAX action callbacks.
41 *
42 * @since 2.0.0
43 */
44 public function __construct() {
45
46 // check an individual product sync status
47 add_action( 'wp_ajax_wc_square_get_quick_edit_product_details', array( $this, 'get_quick_edit_product_details' ) );
48
49 // fetch product stock from Square
50 add_action( 'wp_ajax_wc_square_fetch_product_stock_with_square', array( $this, 'fetch_product_stock_with_square' ) );
51
52 add_action( 'wp_ajax_wc_square_import_products_from_square', array( $this, 'import_products_from_square' ) );
53
54 // sync all products with Square
55 add_action( 'wp_ajax_wc_square_sync_products_with_square', array( $this, 'sync_products_with_square' ) );
56
57 // handle sync records
58 add_action( 'wp_ajax_wc_square_handle_sync_records', array( $this, 'handle_sync_records' ) );
59
60 // get the status of a sync job
61 add_action( 'wp_ajax_wc_square_get_sync_with_square_status', array( $this, 'get_sync_with_square_job_status' ) );
62
63 // rest end point to import products
64 add_action( 'rest_api_init', array( $this, 'register_rest_endpoints' ) );
65 }
66
67 /**
68 * Register REST API endpoints.
69 *
70 * @since 2.1.6
71 */
72 public function register_rest_endpoints() {
73 register_rest_route(
74 'wc/v3',
75 'wc_square/import-products',
76 array(
77 'methods' => 'POST',
78 'callback' => array( $this, 'import_products_from_square' ),
79 'permission_callback' => array( $this, 'check_permission' ),
80 )
81 );
82
83 register_rest_route(
84 'wc/v3',
85 'wc_square/connected_page_visited',
86 array(
87 'methods' => 'POST',
88 'callback' => array( $this, 'update_connected_page_visited' ),
89 'permission_callback' => array( $this, 'check_permission' ),
90 )
91 );
92 }
93
94 /**
95 * Verify access.
96 *
97 * Override this method if custom permissions required.
98 */
99 public function check_permission() {
100 return current_user_can( 'manage_woocommerce' ); // phpcs:ignore WordPress.WP.Capabilities.Unknown
101 }
102
103 /**
104 * Fetches product stock data from Square.
105 *
106 * @internal
107 *
108 * @since 2.0.0
109 */
110 public function fetch_product_stock_with_square() {
111 check_ajax_referer( 'fetch-product-stock-with-square', 'security' );
112
113 if ( ! current_user_can( 'edit_products' ) ) {
114 wp_send_json_error( __( 'Invalid permissions.', 'woocommerce-square' ) );
115 }
116
117 $fix_error = __( 'Please mark product as un-synced and save, then synced again.', 'woocommerce-square' );
118 $product = isset( $_REQUEST['product_id'] ) ? wc_get_product( (int) $_REQUEST['product_id'] ) : false;
119
120 if ( $product ) {
121
122 try {
123 $product = Product::update_stock_from_square( $product );
124 $response = array(
125 'quantity' => $product->get_stock_quantity(),
126 'manage_stock' => $product->get_manage_stock(),
127 );
128
129 wp_send_json_success( $response );
130
131 } catch ( \Exception $exception ) {
132
133 /* translators: Placeholders: %1$s = error message, %2$s = help text */
134 wp_send_json_error( sprintf( __( 'Unable to fetch inventory: %1$s. %2$s', 'woocommerce-square' ), $exception->getMessage(), $fix_error ) );
135 }
136 }
137
138 /* translators: Placeholders: %s = help text */
139 wp_send_json_error( sprintf( __( 'Error finding item in Square. %s', 'woocommerce-square' ), $fix_error ) );
140 }
141
142
143 /**
144 * Starts importing products from Square.
145 *
146 * @param \WP_REST_Request $request The REST request object.
147 *
148 * @internal
149 *
150 * @since 2.0.0
151 */
152 public function import_products_from_square( $request = null ) {
153
154 $api_callback = $request ? $request->get_param( 'api_callback' ) : false;
155
156 $update_during_import = $request
157 ? $request->get_param( 'update_during_import' )
158 : ( ! empty( $_POST['update_during_import'] ) && 'true' === $_POST['update_during_import'] );
159
160 if ( ! $api_callback ) {
161 check_ajax_referer( 'import-products-from-square', 'security' );
162 }
163
164 // The edit_others_shop_orders capability is used to determine if the user can access these settings.
165 if ( ! current_user_can( 'edit_others_shop_orders' ) ) {
166 wp_send_json_error( __( 'Could not start import. Invalid permissions.', 'woocommerce-square' ) );
167 }
168
169 $started = wc_square()->get_sync_handler()->start_product_import( $update_during_import );
170
171 if ( ! $started ) {
172 wp_send_json_error( __( 'Could not start import. Please try again.', 'woocommerce-square' ) );
173 }
174
175 wp_send_json_success( __( 'Your products are being imported in the background! This may take some time to complete.', 'woocommerce-square' ) );
176 }
177
178 /**
179 * Update the connected_page_visited option.
180 * This will be used to show a message to visit the onboarding
181 * wizard and the onboarding wizard submenu until found `true`.
182 *
183 * @since 4.7.0
184 */
185 public function update_connected_page_visited() {
186 update_option( 'wc_square_connected_page_visited', true, false );
187 wp_send_json_success();
188 }
189
190 /**
191 * Starts syncing products with Square.
192 *
193 * @internal
194 *
195 * @since 2.0.0
196 */
197 public function sync_products_with_square() {
198
199 check_ajax_referer( 'sync-products-with-square', 'security' );
200
201 // The edit_others_shop_orders capability is used to determine if the user can access these settings.
202 if ( ! current_user_can( 'edit_others_shop_orders' ) ) {
203 wp_send_json_error();
204 }
205
206 $started = wc_square()->get_sync_handler()->start_manual_sync();
207
208 if ( ! $started ) {
209 wp_send_json_error();
210 }
211
212 wp_send_json_success();
213 }
214
215
216 /**
217 * Handles sync records actions.
218 *
219 * @internal
220 *
221 * @since 2.0.0
222 */
223 public function handle_sync_records() {
224
225 check_ajax_referer( 'handle-sync-with-square-records', 'security' );
226
227 if ( ! current_user_can( 'edit_others_shop_orders' ) ) {
228 wp_send_json_error( __( 'An error occurred. Invalid permissions.', 'woocommerce-square' ) );
229 }
230
231 $error = '';
232
233 if ( isset( $_POST['id'], $_POST['handle'] ) ) {
234
235 $id = sanitize_key( $_POST['id'] );
236 $action = sanitize_key( $_POST['handle'] );
237
238 if ( 'all' === $id && 'delete' === $action ) {
239
240 $outcome = Records::clean_records();
241 $error = esc_html__( 'Could not delete records.', 'woocommerce-square' );
242
243 } elseif ( is_string( $id ) && '' !== $id ) {
244
245 switch ( $action ) {
246
247 case 'delete':
248 $outcome = Records::delete_record( $id );
249 $error = esc_html__( 'Could not delete record.', 'woocommerce-square' );
250
251 break;
252
253 case 'resolve':
254 $record = Records::get_record( $id );
255 if ( $record ) {
256 $record->resolve();
257 $outcome = $record->save();
258 }
259
260 $error = esc_html__( 'Could not resolve record.', 'woocommerce-square' );
261
262 break;
263
264 case 'unsync':
265 $record = Records::get_record( $id );
266 $product = $record ? $record->get_product() : null;
267 if ( $product ) {
268 $record->resolve();
269 $outcome = Product::unset_synced_with_square( $product ) && $record->save();
270 }
271
272 $error = esc_html__( 'Could not unsync product.', 'woocommerce-square' );
273
274 break;
275 }
276 }
277
278 if ( ! empty( $outcome ) ) {
279 wp_send_json_success( $outcome );
280 }
281 }
282
283 /* translators: Placeholder: %s - error message */
284 wp_send_json_error( sprintf( __( 'An error occurred. %s', 'woocommerce-square' ), $error ) );
285 }
286
287
288 /**
289 * Gets a sync job status.
290 *
291 * Also bumps the job progression (useful for when background processing isn't available).
292 *
293 * @internal
294 *
295 * @since 2.0.0
296 */
297 public function get_sync_with_square_job_status() {
298 check_ajax_referer( 'get-sync-with-square-status', 'security' );
299
300 if ( ! current_user_can( 'edit_others_shop_orders' ) ) {
301 wp_send_json_error( __( 'An error occurred. Invalid permissions.', 'woocommerce-square' ) );
302 }
303
304 $job_id = isset( $_POST['job_id'] ) ? sanitize_key( $_POST['job_id'] ) : null;
305
306 if ( $job_id ) {
307 try {
308 $handler = wc_square()->get_background_job_handler();
309 $job_in_progress = $handler ? $handler->get_job( $job_id ) : false;
310 if ( $job_in_progress ) {
311
312 $result = array(
313 'action' => $job_in_progress->action,
314 'id' => $job_in_progress->id,
315 'job_products_count' => count( $job_in_progress->product_ids ),
316 'percentage' => ( (float) count( $job_in_progress->processed_product_ids ) / max( 1, count( $job_in_progress->product_ids ) ) ) * 100,
317 'imported_products_count' => count( $job_in_progress->processed_product_ids ),
318 'updated_products_count' => count( $job_in_progress->updated_product_ids ),
319 'skipped_products_count' => count( $job_in_progress->skipped_products ),
320 'status' => $job_in_progress->status,
321 );
322
323 wp_send_json_success( $result );
324 }
325 } catch ( \Exception $e ) {
326
327 wp_send_json_error( $e->getMessage() );
328 }
329 }
330
331 /* translators: Placeholder: %s - sync job ID */
332 wp_send_json_error( sprintf( esc_html__( 'No sync job in progress found %s', 'woocommerce-square' ), is_string( $job_id ) ? $job_id : null ) );
333 }
334
335 /**
336 * Get sync status, variable status, and edit url for product
337 *
338 * Used to manipulate quick edit menu for product
339 *
340 * @since 2.1.6
341 */
342 public function get_quick_edit_product_details() {
343
344 check_ajax_referer( 'get-quick-edit-product-details', 'security' );
345
346 if ( ! current_user_can( 'edit_products' ) ) {
347 wp_send_json_error( 'invalid_permission' );
348 }
349
350 $product = isset( $_POST['product_id'] ) ? wc_get_product( (int) $_POST['product_id'] ) : false;
351
352 if ( $product ) {
353 $is_variable = $product->is_type( 'variable' );
354
355 if ( ! Product::has_sku( $product ) ) {
356 if ( $is_variable ) {
357 wp_send_json_error( 'missing_variation_sku' );
358 } else {
359 wp_send_json_error( 'missing_sku' );
360 }
361 }
362
363 $is_synced_with_square = Product::is_synced_with_square( $product ) ? 'yes' : 'no';
364 $is_woocommerce_sor = wc_square()->get_settings_handler()->is_system_of_record_woocommerce();
365
366 wp_send_json_success(
367 array(
368 'edit_url' => $is_woocommerce_sor ? get_edit_post_link( (int) $_POST['product_id'] ) : null,
369 'i18n' => $is_woocommerce_sor ? __( 'Stock must be fetched from Square before editing stock quantity', 'woocommerce-square' ) : null,
370 'is_synced_with_square' => $is_synced_with_square,
371 'is_variable' => $is_variable,
372 )
373 );
374 }
375 wp_send_json_error( 'invalid_product' );
376 }
377
378 }
379