PluginProbe
WooCommerce Square / 1.0.27
WooCommerce Square v1.0.27
5.5.0 5.4.3 5.4.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 All 132 releases
woocommerce-square / includes / class-wc-square-utils.php
class-wc-square-utils.php
934 lines 27.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 exit; // Exit if accessed directly
4 }
5
6 /**
7 * Class WC_Square_Utils
8 *
9 * Static helper methods for the WC <-> Square integration, used in multiple
10 * places throughout the extension, with no dependencies of their own.
11 *
12 * Mostly data formatting and entity retrieval methods.
13 */
14 class WC_Square_Utils {
15
16 const WC_TERM_SQUARE_ID = 'square_cat_id';
17 const WC_PRODUCT_SQUARE_ID = '_square_item_id';
18 const WC_VARIATION_SQUARE_ID = '_square_item_variation_id';
19 const WC_PRODUCT_IMAGE_SQUARE_ID = '_square_item_image_id';
20
21 /**
22 * Convert a WC Product or Variation into a Square ItemVariation
23 * See: https://docs.connect.squareup.com/api/connect/v1/#datatype-itemvariation
24 *
25 * @param WC_Product|WC_Product_Variation $variation
26 * @param bool $include_inventory
27 * @return array Formatted as a Square ItemVariation
28 */
29 public static function format_wc_variation_for_square_api( $variation, $include_inventory = false ) {
30
31 $formatted = array(
32 'name' => null,
33 'pricing_type' => null,
34 'price_money' => null,
35 'sku' => null,
36 'track_inventory' => null,
37 'inventory_alert_type' => null,
38 'inventory_alert_threshold' => null,
39 'user_data' => null,
40 );
41
42 if ( $variation instanceof WC_Product ) {
43
44 $formatted['name'] = __( 'Regular', 'woocommerce-square' );
45 $formatted['price_money'] = array(
46 'currency_code' => apply_filters( 'woocommerce_square_currency', get_woocommerce_currency() ),
47 'amount' => (int) WC_Square_Utils::format_amount_to_square( version_compare( WC_VERSION, '3.0.0', '<' ) ? $variation->get_display_price() : wc_get_price_excluding_tax( $variation ) ),
48 );
49 $formatted['sku'] = $variation->get_sku();
50
51 if ( $include_inventory && $variation->managing_stock() ) {
52 $formatted['track_inventory'] = true;
53 }
54 }
55
56 if ( $variation instanceof WC_Product_Variation ) {
57
58 $formatted['name'] = implode( ', ', $variation->get_variation_attributes() );
59
60 }
61
62 return array_filter( $formatted );
63
64 }
65
66 /**
67 * Normalize description text to Square
68 * Square expects no HTML to be in the description and
69 * the limit of characters is 4095.
70 *
71 * @since 1.0.27
72 * @param mixed $description
73 * @return string
74 */
75 public static function normalize_description( $description = '' ) {
76 return substr( wp_strip_all_tags( $description ), 0, 4095 );
77 }
78
79 /**
80 * Convert a WC Product into a Square Item for Update
81 *
82 * Updates (PUT) don't accept the same parameters (namely variations) as Creation
83 * See: https://docs.connect.squareup.com/api/connect/v1/index.html#put-itemid
84 *
85 * @param WC_Product $wc_product
86 * @param bool $include_category
87 * @return array
88 */
89 public static function format_wc_product_update_for_square_api( WC_Product $wc_product, $include_category = false ) {
90
91 $formatted = array(
92 'name' => $wc_product->get_title(),
93 'description' => self::normalize_description( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->post->post_content : $wc_product->get_description() ),
94 'visibility' => 'PUBLIC',
95 );
96
97 if ( $include_category ) {
98 $square_cat_id = self::get_square_category_id_for_wc_product( $wc_product );
99
100 if ( $square_cat_id ) {
101 $formatted['category_id'] = $square_cat_id;
102 }
103 }
104
105 return array_filter( $formatted );
106 }
107
108 /**
109 * Convert a WC Product into a Square Item for Create
110 *
111 * Creation (POST) allows more parameters than Updating, namely variations
112 * See: https://docs.connect.squareup.com/api/connect/v1/index.html#post-items
113 *
114 * @param WC_Product $wc_product
115 * @param bool $include_category
116 * @param bool $include_inventory
117 * @return array
118 */
119 public static function format_wc_product_create_for_square_api( WC_Product $wc_product, $include_category = false, $include_inventory = false ) {
120
121 $formatted = self::format_wc_product_update_for_square_api( $wc_product, $include_category );
122
123 // check product type
124 if ( 'simple' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->product_type : $wc_product->get_type() ) ) {
125
126 $formatted['variations'] = array(
127 WC_Square_Utils::format_wc_variation_for_square_api( $wc_product, $include_inventory ),
128 );
129
130 } elseif ( 'variable' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->product_type : $wc_product->get_type() ) ) {
131
132 $wc_variations = self::get_wc_product_variations( $wc_product );
133
134 foreach ( (array) $wc_variations as $wc_variation ) {
135
136 $formatted['variations'][] = WC_Square_Utils::format_wc_variation_for_square_api( $wc_variation, $include_inventory );
137 }
138 }
139
140 return array_filter( $formatted );
141 }
142
143 /**
144 * Map existing WC Variation IDs to a formatted product update array.
145 *
146 * Square ItemVariations are matched to their WC Variation equivalents via SKU.
147 *
148 * @param WC_Product $wc_product
149 * @param array $product_update Formatted product update. @see WC_Square_Utils::format_square_item_for_wc_api
150 *
151 * @return array WC Product formatted for update, with Variation IDs mapped.
152 */
153 public static function set_wc_variation_ids_for_update( WC_Product $wc_product, $product_update ) {
154
155 if ( ( 'variable' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->product_type : $wc_product->get_type() ) ) && isset( $product_update['variations'] ) ) {
156
157 $wc_variations = self::get_wc_product_variations( $wc_product );
158
159 $wc_variation_sku_id_map = array();
160
161 foreach ( $wc_variations as $wc_variation ) {
162 $wc_variation_sku = $wc_variation->get_sku();
163
164 $wc_variation_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_variation->variation_id : $wc_variation->get_id();
165
166 if ( ! empty( $wc_variation_sku ) && ! empty( $wc_variation_id ) ) {
167
168 $wc_variation_sku_id_map[ $wc_variation_sku ] = $wc_variation_id;
169 }
170 }
171
172 foreach ( (array) $product_update['variations'] as $idx => $variation ) {
173 if ( ! empty( $variation['sku'] ) && isset( $wc_variation_sku_id_map[ $variation['sku'] ] ) ) {
174 $product_update['variations'][ $idx ]['id'] = $wc_variation_sku_id_map[ $variation['sku'] ];
175 }
176 }
177 }
178
179 return $product_update;
180 }
181
182 /**
183 * Format a Square Item for an UPDATE through the WC Product API
184 *
185 * See: https://docs.connect.squareup.com/api/connect/v1/#datatype-item
186 * See: https://woothemes.github.io/woocommerce-rest-api-docs/#products-properties
187 *
188 * @param object $square_item
189 * @param WC_Product $wc_product
190 * @param bool $include_category
191 * @param bool $include_inventory
192 * @param bool $include_image
193 *
194 * @return array
195 */
196 public static function format_square_item_for_wc_api_update( $square_item, WC_Product $wc_product, $include_category = false, $include_inventory = false, $include_image = false ) {
197
198 $formatted = self::format_square_item_for_wc_api_create( $square_item, $include_category, $include_inventory, $include_image );
199
200 return self::set_wc_variation_ids_for_update( $wc_product, $formatted );
201 }
202
203 /**
204 * Format a Square Item for a CREATE through the WC Product API
205 *
206 * See: https://docs.connect.squareup.com/api/connect/v1/#datatype-item
207 * See: https://woothemes.github.io/woocommerce-rest-api-docs/#products-properties
208 *
209 * @param object $square_item
210 * @param bool $include_inventory
211 * @param bool $include_image
212 *
213 * @return array
214 */
215 public static function format_square_item_for_wc_api_create( $square_item, $include_category = false, $include_inventory = false, $include_image = false ) {
216
217 $formatted = array(
218 'title' => $square_item->name,
219 );
220
221 if ( apply_filters( 'woocommerce_square_sync_from_square_description', false ) ) {
222 $description = ! empty( $square_item->description ) ? $square_item->description : '';
223 $formatted['description'] = $description;
224 }
225
226 if ( $include_image && isset( $square_item->master_image->url ) ) {
227
228 $formatted['images'] = array(
229 array(
230 'position' => 0,
231 'src' => $square_item->master_image->url,
232 ),
233 );
234 }
235
236 if ( $include_category && isset( $square_item->category->id ) ) {
237 $wc_cat_id = self::get_wc_category_id_for_square_category_id( $square_item->category->id );
238
239 if ( $wc_cat_id ) {
240 $formatted['categories'] = array( $wc_cat_id );
241 }
242 }
243
244 if ( count( $square_item->variations ) > 1 ) {
245
246 $formatted['type'] = 'variable';
247 $formatted['variations'] = array();
248
249 foreach ( $square_item->variations as $square_item_variation ) {
250
251 $formatted['variations'][] = self::format_square_item_variation_for_wc_api( $square_item_variation, $include_inventory );
252
253 }
254
255 $formatted['attributes'] = array(
256 array(
257 'name' => 'Attribute',
258 'slug' => 'attribute',
259 'position' => 0,
260 'visible' => true,
261 'variation' => true,
262 'options' => wp_list_pluck( $square_item->variations, 'name' ),
263 ),
264 );
265
266 } else {
267
268 $variation = self::format_square_item_variation_for_wc_api( $square_item->variations[0], $include_inventory );
269
270 $formatted['type'] = 'simple';
271 $formatted['sku'] = isset( $variation['sku'] ) ? $variation['sku'] : null;
272 $formatted['regular_price'] = isset( $variation['regular_price'] ) ? $variation['regular_price'] : null;
273 $formatted['stock_quantity'] = isset( $variation['stock_quantity'] ) ? $variation['stock_quantity'] : null;
274 $formatted['managing_stock'] = isset( $variation['managing_stock'] ) ? $variation['managing_stock'] : null;
275
276 }
277
278 return array_filter( $formatted );
279 }
280
281 /**
282 * Convert a Square ItemVariation for the WC Product API
283 *
284 * See: https://docs.connect.squareup.com/api/connect/v1/#datatype-itemvariation
285 * See: https://woothemes.github.io/woocommerce-rest-api-docs/#products-properties
286 *
287 * @param object $square_item_variation
288 * @return array
289 */
290 public static function format_square_item_variation_for_wc_api( $square_item_variation, $include_inventory = false ) {
291
292 $formatted = array(
293 'sku' => ! empty( $square_item_variation->sku ) ? $square_item_variation->sku : '',
294 'regular_price' => self::format_square_price_for_wc( $square_item_variation->price_money->amount ),
295 'stock_quantity' => null,
296 'attributes' => array(
297 array(
298 'name' => 'Attribute',
299 'option' => ! empty( $square_item_variation->name ) ? $square_item_variation->name : '',
300 ),
301 ),
302 );
303
304 if ( $include_inventory ) {
305 $formatted['managing_stock'] = $square_item_variation->track_inventory ? true : null;
306 }
307
308 return array_filter( $formatted );
309 }
310
311 /**
312 * Formats the price coming from Square as they use the lowest denominator ex. cents
313 *
314 * See: https://docs.connect.squareup.com/api/connect/v1/#workingwithmonetaryamounts
315 *
316 * @param int $price
317 * @return int
318 */
319 public static function format_square_price_for_wc( $price = 0 ) {
320 return apply_filters( 'woocommerce_square_format_price', self::format_amount_from_square( $price ) );
321 }
322
323 /**
324 * Retrieve the Square ID for a WC Term
325 *
326 * @param int $wc_term_id
327 * @return mixed See get_woocommerce_term_meta()
328 */
329 public static function get_wc_term_square_id( $wc_term_id ) {
330 return get_woocommerce_term_meta( $wc_term_id, self::WC_TERM_SQUARE_ID );
331 }
332
333 /**
334 * Update the Square ID for a WC Term
335 *
336 * @param int $wc_term_id
337 * @param string $square_id
338 * @return bool See update_woocommerce_term_meta()
339 */
340 public static function update_wc_term_square_id( $wc_term_id, $square_id ) {
341 return update_woocommerce_term_meta( $wc_term_id, self::WC_TERM_SQUARE_ID, $square_id );
342 }
343
344 /**
345 * Retrieve the Square ID for a WC Product
346 *
347 * @param int $wc_product_id
348 * @return array|mixed See get_post_meta()
349 */
350 public static function get_wc_product_square_id( $wc_product_id ) {
351 return get_post_meta( $wc_product_id, self::WC_PRODUCT_SQUARE_ID, true );
352 }
353
354 /**
355 * Update the Square ID for a WC Product
356 *
357 * @param int $wc_product_id
358 * @param string $square_id
359 * @return bool|int See update_post_meta()
360 */
361 public static function update_wc_product_square_id( $wc_product_id, $square_id ) {
362 return update_post_meta( $wc_product_id, self::WC_PRODUCT_SQUARE_ID, $square_id );
363 }
364
365 /**
366 * Retrieve the Square ID for a WC Product Variation
367 *
368 * @param int $wc_variation_id
369 * @return array|mixed See get_post_meta()
370 */
371 public static function get_wc_variation_square_id( $wc_variation_id ) {
372 return get_post_meta( $wc_variation_id, self::WC_VARIATION_SQUARE_ID, true );
373 }
374
375 /**
376 * Update the Square ID for a WC Product Variation
377 *
378 * @param int $wc_variation_id
379 * @param string $square_id
380 * @return bool|int See update_post_meta()
381 */
382 public static function update_wc_variation_square_id( $wc_variation_id, $square_id ) {
383 return update_post_meta( $wc_variation_id, self::WC_VARIATION_SQUARE_ID, $square_id );
384 }
385
386 /**
387 * Get all SKUs associated with a WC Product (could be many, if variable).
388 *
389 * @param WC_Product $wc_product
390 * @return array
391 */
392 public static function get_wc_product_skus( WC_Product $wc_product ) {
393 $wc_product_skus = array();
394
395 if ( 'simple' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->product_type : $wc_product->get_type() ) ) {
396
397 $wc_product_skus[] = $wc_product->get_sku();
398
399 } elseif ( 'variable' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->product_type : $wc_product->get_type() ) ) {
400 $wc_variations = self::get_wc_product_variations( $wc_product );
401
402 if ( version_compare( WC_VERSION, '3.0.0', '<' ) ) {
403 $wc_product_skus = wp_list_pluck( $wc_variations, 'sku' );
404 } else {
405 foreach ( $wc_variations as $wc_variation ) {
406 $wc_product_skus[] = $wc_variation->get_sku();
407 }
408 }
409 }
410
411 // SKUs are optional, so let's only return ones that have values
412 return array_filter( $wc_product_skus );
413 }
414
415 /**
416 * Determine which WC Product Category to send to Square.
417 *
418 * Returns the first top-level Category that has an associated Square ID.
419 *
420 * @param WC_Product $wc_product
421 * @return bool|mixed
422 */
423 public static function get_square_category_id_for_wc_product( WC_Product $wc_product ) {
424 $wc_categories = wp_get_post_terms( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->id : $wc_product->get_id(), 'product_cat' );
425
426 if ( is_wp_error( $wc_categories ) && empty( $wc_categories ) ) {
427
428 return false;
429
430 }
431
432 foreach ( $wc_categories as $category ) {
433
434 if ( $category->parent ) {
435
436 $ancestors = get_ancestors( $category->term_id, 'product_cat', 'taxonomy' );
437 $top_level_id = end( $ancestors );
438
439 } else {
440
441 $top_level_id = $category->term_id;
442
443 }
444
445 $square_cat_id = self::get_wc_term_square_id( $top_level_id );
446
447 if ( $square_cat_id ) {
448 return $square_cat_id;
449 }
450 }
451
452 return false;
453 }
454
455 /**
456 * Retrieve the Square Item Image ID for a WC Product
457 *
458 * @param int $wc_product_id
459 * @return array|mixed See get_post_meta()
460 */
461 public static function get_wc_product_image_square_id( $wc_product_id ) {
462 return get_post_meta( $wc_product_id, self::WC_PRODUCT_IMAGE_SQUARE_ID, true );
463 }
464
465 /**
466 * Update the Square Item Image ID for a WC Product
467 *
468 * @param int $wc_product_id
469 * @param string $square_id
470 * @return bool|int See update_post_meta()
471 */
472 public static function update_wc_product_image_square_id( $wc_product_id, $square_image_id ) {
473 return update_post_meta( $wc_product_id, self::WC_PRODUCT_IMAGE_SQUARE_ID, $square_image_id );
474 }
475
476 /**
477 * Retrieve the WC Category ID that corresponds to a given Square Category ID.
478 *
479 * @param string $square_cat_id
480 * @return bool|int WC Category ID on successful match, boolean false otherwise.
481 */
482 public static function get_wc_category_id_for_square_category_id( $square_cat_id ) {
483 $categories = get_terms( 'product_cat', array(
484 'parent' => 0,
485 'hide_empty' => false,
486 'fields' => 'ids',
487 ) );
488
489 if ( is_wp_error( $categories ) ) {
490 WC_Square_Sync_Logger::log( sprintf( '%s::%s - Taxonomy "product_cat" not found. Make sure WooCommerce is enabled.', __CLASS__, __FUNCTION__ ) );
491 return false;
492 }
493
494 foreach ( $categories as $wc_category ) {
495 $wc_square_cat_id = self::get_wc_term_square_id( $wc_category );
496
497 if ( $wc_square_cat_id && ( $square_cat_id === $wc_square_cat_id ) ) {
498 return $wc_category;
499 }
500 }
501
502 return false;
503 }
504
505 /**
506 * Attempt to find a WC Product that corresponds to a given Square Item.
507 *
508 * This function first queries for a WC Product already associated to the
509 * Square Item's ID. If none found, all WC Products (and variations) are
510 * queried using the SKUs present in the Square Item's Variations. If a
511 * match is found, the parent (non-variant) WC Product is returned.
512 *
513 * @param object $square_item
514 * @return bool|WC_Product Corresponding WC_Product on successful match, boolean false otherwise.
515 */
516 public static function get_wc_product_for_square_item( $square_item ) {
517 if ( ! is_object( $square_item ) || ! property_exists( $square_item, 'id' ) ) {
518 return false;
519 }
520
521 $wc_product_ids = get_posts( array(
522 'post_type' => 'product',
523 'post_status' => 'publish', // this is ignored
524 'meta_query' => array(
525 array(
526 'key' => self::WC_PRODUCT_SQUARE_ID,
527 'compare' => '=',
528 'value' => $square_item->id,
529 ),
530 ),
531 'posts_per_page' => 1,
532 'fields' => 'ids',
533 ) );
534
535 if ( ! empty( $wc_product_ids ) ) {
536 $wc_product = wc_get_product( $wc_product_ids[0] );
537
538 // only return publish products
539 if ( 'publish' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->post->post_status : $wc_product->get_status() ) ) {
540 return $wc_product;
541 }
542 }
543
544 $square_item_skus = self::get_square_item_skus( $square_item );
545
546 if ( empty( $square_item_skus ) ) {
547 return false;
548 }
549
550 $wc_product_ids = get_posts( array(
551 'post_type' => array( 'product', 'product_variation' ),
552 'post_status' => 'publish', // this is ignored
553 'meta_query' => array(
554 array(
555 'key' => '_sku',
556 'compare' => 'IN',
557 'value' => $square_item_skus,
558 ),
559 ),
560 'posts_per_page' => 1,
561 'fields' => 'ids',
562 ) );
563
564 if ( ! empty( $wc_product_ids ) ) {
565 $wc_product = wc_get_product( $wc_product_ids[0] );
566
567 if ( ! is_object( $wc_product ) ) {
568 return false;
569 }
570
571 if ( 'publish' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->post->post_status : $wc_product->get_status() ) ) {
572 if ( 'simple' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->product_type : $wc_product->get_type() ) ) {
573
574 return $wc_product;
575
576 }
577
578 return wc_get_product( ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->parent : $wc_product->get_parent_id() ) );
579 }
580 }
581
582 return false;
583 }
584
585 /**
586 * Attempt to find a WC Product that corresponds to a given Square Item.
587 *
588 * @param string $square_variation_id
589 * @return bool|WC_Product Corresponding WC_Product on successful match, boolean false otherwise.
590 */
591 public static function get_wc_product_for_square_item_variation_id( $square_variation_id ) {
592 $wc_product_ids = get_posts( array(
593 'post_type' => array( 'product', 'product_variation' ),
594 'post_status' => 'publish', // this is ignored
595 'meta_query' => array(
596 array(
597 'key' => self::WC_VARIATION_SQUARE_ID,
598 'compare' => '=',
599 'value' => $square_variation_id,
600 ),
601 ),
602 'posts_per_page' => 1,
603 'fields' => 'ids',
604 ) );
605
606 if ( ! empty( $wc_product_ids ) ) {
607 $product = wc_get_product( $wc_product_ids[0] );
608
609 // only return publish products
610 if ( 'publish' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $product->post->post_status : $product->get_status() ) ) {
611 return $product;
612 }
613 }
614
615 return false;
616 }
617
618 /**
619 * Checks if all SKUs have been set for the Square Item.
620 * We do not want to sync the item if not all SKU is set.
621 *
622 * @since 1.0.14
623 * @version 1.0.14
624 * @param object $square_item
625 * @return bool
626 */
627 public static function is_square_item_skus_set( $square_item ) {
628 if ( empty( $square_item ) || empty( $square_item->variations ) ) {
629
630 return false;
631 }
632
633 foreach ( $square_item->variations as $item_variation ) {
634 // If even one sku is missing we don't want to sync.
635 if ( empty( $item_variation->sku ) ) {
636
637 return false;
638 }
639 }
640
641 return true;
642 }
643
644 /**
645 * Return array of SKUs from all variations of a Square Item
646 *
647 * @param object $square_item
648 * @return array
649 */
650 public static function get_square_item_skus( $square_item ) {
651
652 $item_skus = array();
653
654 if ( empty( $square_item->variations ) ) {
655
656 return $item_skus;
657 }
658
659 foreach ( $square_item->variations as $item_variation ) {
660 if ( ! empty( $item_variation->sku ) ) {
661
662 $item_skus[] = $item_variation->sku;
663 }
664 }
665
666 return $item_skus;
667 }
668
669 /**
670 * Store Square Item ID and ItemVariation IDs on a WC Product and it's variations,
671 * matching using the SKU value.
672 *
673 * This is most useful in WC->Square creation, and Square->WC operations.
674 *
675 * @param WC_Product $wc_product
676 * @param object $square_item
677 */
678 public static function set_square_ids_on_wc_product_by_sku( WC_Product $wc_product, $square_item ) {
679 if ( ! is_object( $square_item ) || ! property_exists( $square_item, 'id' ) ) {
680 return false;
681 }
682
683 self::update_wc_product_square_id( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->id : $wc_product->get_id(), $square_item->id );
684
685 if ( 'simple' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->product_type : $wc_product->get_type() ) ) {
686
687 self::update_wc_variation_square_id( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->id : $wc_product->get_id(), $square_item->variations[0]->id );
688
689 } elseif ( 'variable' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->product_type : $wc_product->get_type() ) ) {
690
691 // Create mapping of Square ItemVariation SKU => ID
692 $square_variations = array();
693
694 foreach ( $square_item->variations as $square_variation ) {
695
696 if ( ! empty( $square_variation->sku ) ) {
697
698 $square_variations[ $square_variation->sku ] = $square_variation->id;
699
700 }
701 }
702
703 // Create mapping of WC Variation SKU => ID
704 $wc_item_variations = self::get_wc_product_variations( $wc_product );
705 $wc_variations = array();
706
707 foreach ( $wc_item_variations as $wc_item_variation ) {
708 $wc_variation_sku = $wc_item_variation->get_sku();
709
710 if ( ! empty( $wc_variation_sku ) ) {
711 $wc_variations[ $wc_variation_sku ] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_item_variation->variation_id : $wc_item_variation->get_id();
712 }
713 }
714
715 // Map the WC Variations to their Square ItemVariation counterparts
716 foreach ( $wc_variations as $sku => $wc_variation_id ) {
717 if ( array_key_exists( $sku, $square_variations ) ) {
718
719 self::update_wc_variation_square_id( $wc_variation_id, $square_variations[ $sku ] );
720 }
721 }
722 }
723 }
724
725 /**
726 * Retrieve WC Variation IDs for a given WC Product, that we're managing stock for.
727 *
728 * @param WC_Product $wc_product
729 * @return array
730 */
731 public static function get_stock_managed_wc_variation_ids( WC_Product $wc_product ) {
732 $wc_product = wc_get_product( $wc_product->get_id() );
733
734 $wc_variation_ids = array();
735
736 if ( ! is_object( $wc_product ) ) {
737 return $wc_variation_ids;
738 }
739
740 if ( 'simple' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->product_type : $wc_product->get_type() ) ) {
741
742 if ( $wc_product->managing_stock() ) {
743
744 $wc_variation_ids = array( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->id : $wc_product->get_id() );
745
746 }
747 } elseif ( 'variable' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_product->product_type : $wc_product->get_type() ) ) {
748
749 $variations = self::get_wc_product_variations( $wc_product );
750
751 foreach ( (array) $variations as $variation ) {
752
753 if ( $variation->managing_stock() ) {
754
755 $wc_variation_ids[] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $variation->variation_id : $variation->get_id();
756
757 }
758 }
759 }
760
761 return $wc_variation_ids;
762 }
763
764 /**
765 * Get all variations of a given WC_Product_Variable.
766 *
767 * @param WC_Product_Variable $wc_variable_product
768 * @return array Array of WC_Product_Variation objects.
769 */
770 public static function get_wc_product_variations( WC_Product_Variable $wc_variable_product ) {
771 $variations = array();
772
773 foreach ( $wc_variable_product->get_children() as $child_id ) {
774
775 $variation = version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_variable_product->get_child( $child_id ) : wc_get_product( $child_id );
776
777 $variation_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $variation->variation_id : $variation->get_id();
778
779 if ( empty( $variation_id ) ) {
780 continue;
781 }
782
783 $variations[] = $variation;
784 }
785
786 return $variations;
787 }
788
789 /**
790 * Check if the square item is found
791 *
792 * @param object $square_item
793 * @return bool
794 */
795 public static function is_square_item_found( $square_item ) {
796 if ( is_object( $square_item ) && 'not_found' !== $square_item->type ) {
797 return true;
798 }
799
800 return false;
801 }
802
803 /**
804 * Checks to see if product disable sync is enabled
805 *
806 * @param int $product_id parent product id
807 * @return bool
808 */
809 public static function skip_product_sync( $product_id = null ) {
810 if ( null === $product_id ) {
811 return false;
812 }
813
814 $skip_sync = get_post_meta( $product_id, '_wcsquare_disable_sync', true );
815
816 if ( 'yes' === $skip_sync ) {
817 return true;
818 }
819
820 return false;
821 }
822
823 /**
824 * Process amount to be passed to Square.
825 * @return float
826 */
827 public static function format_amount_to_square( $total, $currency = '' ) {
828 if ( ! $currency ) {
829 $currency = get_woocommerce_currency();
830 }
831
832 switch ( strtoupper( $currency ) ) {
833 // Zero decimal currencies
834 case 'BIF':
835 case 'CLP':
836 case 'DJF':
837 case 'GNF':
838 case 'JPY':
839 case 'KMF':
840 case 'KRW':
841 case 'MGA':
842 case 'PYG':
843 case 'RWF':
844 case 'VND':
845 case 'VUV':
846 case 'XAF':
847 case 'XOF':
848 case 'XPF':
849 $total = absint( $total );
850 break;
851 default:
852 $total = absint( wc_format_decimal( ( (float) $total * 100 ), wc_get_price_decimals() ) ); // In cents.
853 break;
854 }
855
856 return $total;
857 }
858
859 /**
860 * Process amount to be passed from Square.
861 * @return float
862 */
863 public static function format_amount_from_square( $total, $currency = '' ) {
864 if ( ! $currency ) {
865 $currency = get_woocommerce_currency();
866 }
867
868 switch ( strtoupper( $currency ) ) {
869 // Zero decimal currencies
870 case 'BIF':
871 case 'CLP':
872 case 'DJF':
873 case 'GNF':
874 case 'JPY':
875 case 'KMF':
876 case 'KRW':
877 case 'MGA':
878 case 'PYG':
879 case 'RWF':
880 case 'VND':
881 case 'VUV':
882 case 'XAF':
883 case 'XOF':
884 case 'XPF':
885 $total = absint( $total );
886 break;
887 default:
888 $total = wc_format_decimal( absint( $total ) / 100 );
889 break;
890 }
891
892 return $total;
893 }
894
895 /**
896 * This is for developers to test with their own staging access with Square.
897 * This is usually not accessible by regular merchants.
898 *
899 * @param string $environment
900 * @return string
901 */
902 public static function is_staging( $environment = null ) {
903 if ( ! empty( $environment ) && 'staging' === $environment && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
904 return true;
905 }
906
907 return false;
908 }
909
910 /**
911 * Deletes all transients.
912 *
913 * @since 1.0.17
914 * @version 1.0.17
915 */
916 public static function delete_transients() {
917 delete_transient( 'wc_square_processing_total_count' );
918
919 delete_transient( 'wc_square_processing_ids' );
920
921 delete_transient( 'wc_square_syncing_square_inventory' );
922
923 delete_transient( 'sq_wc_sync_current_process' );
924
925 delete_transient( 'wc_square_inventory' );
926
927 delete_transient( 'wc_square_polling' );
928
929 delete_transient( 'wc_square_manual_sync_processing' );
930
931 return true;
932 }
933 }
934