PluginProbe ʕ •ᴥ•ʔ
WooCommerce Square / 2.2.2
WooCommerce Square v2.2.2
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 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 / Sync / Interval_Polling.php
woocommerce-square / includes / Sync Last commit date
Records 6 years ago Catalog_Item.php 6 years ago Interval_Polling.php 6 years ago Job.php 6 years ago Manual_Synchronization.php 6 years ago Product_Import.php 5 years ago Records.php 6 years ago Stepped_Job.php 6 years ago
Interval_Polling.php
283 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
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
22 */
23
24 namespace WooCommerce\Square\Sync;
25
26 use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27 use SquareConnect\Model\SearchCatalogObjectsResponse;
28 use SquareConnect\Model\BatchRetrieveInventoryCountsResponse;
29 use WooCommerce\Square\Handlers\Product;
30 use WooCommerce\Square\Handlers\Category;
31
32 defined( 'ABSPATH' ) || exit;
33
34 /**
35 * Class to represent a synchronization job to poll latest product updates at intervals.
36 *
37 * @since 2.0.0
38 */
39 class Interval_Polling extends Stepped_Job {
40
41
42 /**
43 * Assigns the next steps needed for this sync job.
44 *
45 * Adds the next steps to the 'next_steps' attribute.
46 *
47 * @since 2.0.0
48 */
49 protected function assign_next_steps() {
50
51 $next_steps = array();
52
53 if ( $this->is_system_of_record_square() ) {
54
55 $next_steps = array(
56 'update_category_data',
57 'update_product_data',
58 );
59 }
60
61 // only pull latest inventory if enabled
62 if ( wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
63 $next_steps[] = 'update_inventory_counts';
64 }
65
66 $this->set_attr( 'next_steps', $next_steps );
67 }
68
69 /**
70 * Updates categories from Square.
71 *
72 * @since 2.0.8
73 *
74 * @throws Framework\SV_WC_Plugin_Exception
75 */
76 protected function update_category_data() {
77 $date = new \DateTime();
78 $date->setTimestamp( $this->get_attr( 'catalog_last_synced_at', (int) wc_square()->get_sync_handler()->get_last_synced_at() ) );
79 $date->setTimezone( new \DateTimeZone( 'UTC' ) );
80
81 $response = wc_square()->get_api()->search_catalog_objects(
82 array(
83 'object_types' => array( 'CATEGORY' ),
84 'begin_time' => $date->format( DATE_ATOM ),
85 )
86 );
87
88 $categories = $response->get_data()->getObjects();
89
90 if ( $categories && is_array( $categories ) ) {
91 foreach ( $categories as $category ) {
92 Category::import_or_update( $category );
93 }
94
95 Records::set_record(
96 array(
97 'type' => 'info',
98 'message' => sprintf(
99 /* translator: Placeholder %d number of categories */
100 _n( 'Updated data for %d category.', 'Updated data for %d categories.', count( $categories ), 'woocommerce-square' ),
101 count( $categories )
102 ),
103 )
104 );
105 }
106
107 $this->complete_step( 'update_category_data' );
108 }
109
110 /**
111 * Updates products from Square.
112 *
113 * @since 2.0.0
114 *
115 * @throws Framework\SV_WC_Plugin_Exception
116 */
117 protected function update_product_data() {
118
119 $date = new \DateTime();
120 $date->setTimestamp( $this->get_attr( 'catalog_last_synced_at', (int) wc_square()->get_sync_handler()->get_last_synced_at() ) );
121 $date->setTimezone( new \DateTimeZone( 'UTC' ) );
122
123 $products_updated = $this->get_attr( 'processed_product_ids', array() );
124 $cursor = $this->get_attr( 'update_product_data_cursor' );
125
126 $response = wc_square()->get_api()->search_catalog_objects(
127 array(
128 'object_types' => array( 'ITEM' ),
129 'include_deleted_objects' => true,
130 'begin_time' => $date->format( DATE_ATOM ),
131 'cursor' => $cursor,
132 )
133 );
134
135 // store the timestamp after this API request was completed
136 // we don't want to set it at the end, as counts may have changed in the time it takes to process the data
137 if ( ! $cursor ) {
138 wc_square()->get_sync_handler()->set_last_synced_at();
139 }
140
141 if ( $response->get_data() instanceof SearchCatalogObjectsResponse && is_array( $response->get_data()->getObjects() ) ) {
142
143 foreach ( $response->get_data()->getObjects() as $object ) {
144
145 // filter out objects that aren't at our configured location
146 if ( ! $object->getPresentAtAllLocations() && ( ! is_array( $object->getPresentAtLocationIds() ) || ! in_array( wc_square()->get_settings_handler()->get_location_id(), $object->getPresentAtLocationIds(), true ) ) ) {
147 continue;
148 }
149
150 $product = Product::get_product_by_square_id( $object->getId() );
151
152 if ( $product instanceof \WC_Product ) {
153
154 // deleted items won't have any data to set, so don't try and update the product
155 if ( $object->getIsDeleted() ) {
156
157 $record = array(
158 'type' => 'alert',
159 'product_id' => $product->get_id(),
160 );
161
162 // if enabled, hide the product from the catalog
163 if ( wc_square()->get_settings_handler()->hide_missing_square_products() ) {
164
165 try {
166
167 $product->set_catalog_visibility( 'hidden' );
168 $product->save();
169
170 $record['product_hidden'] = true;
171
172 } catch ( \Exception $e ) {
173 }
174 }
175
176 Records::set_record( $record );
177
178 } else {
179
180 try {
181
182 Product::update_from_square( $product, $object->getItemData(), false );
183
184 if ( ! $product->get_image_id() && $object->getImageId() ) {
185 Product::update_image_from_square( $product, $object->getImageId() );
186 }
187
188 $products_updated[] = $product->get_id();
189
190 } catch ( \Exception $exception ) {
191
192 Records::set_record(
193 array(
194 'type' => 'alert',
195 'product_id' => $product->get_id(),
196 )
197 );
198 }
199 }
200 }
201 }
202 }
203
204 $cursor = $response->get_data() instanceof SearchCatalogObjectsResponse ? $response->get_data()->getCursor() : null;
205
206 $this->set_attr( 'update_product_data_cursor', $cursor );
207 $this->set_attr( 'processed_product_ids', array_unique( $products_updated ) );
208
209 if ( ! $cursor ) {
210 $this->complete_step( 'update_product_data' );
211 }
212 }
213
214
215 /**
216 * Updates the inventory counts from the latest in Square.
217 *
218 * Helper method, do not open to public.
219 *
220 * @since 2.0.0
221 *
222 * @throws Framework\SV_WC_API_Exception
223 */
224 protected function update_inventory_counts() {
225
226 $products_updated = $this->get_attr( 'processed_product_ids' );
227 $cursor = $this->get_attr( 'update_inventory_counts_cursor' );
228
229 $args = array(
230 'location_ids' => array( wc_square()->get_settings_handler()->get_location_id() ),
231 'cursor' => $cursor,
232 );
233
234 $last_synced_at = $this->get_attr( 'inventory_last_synced_at' );
235
236 if ( $last_synced_at ) {
237
238 $date = new \DateTime();
239 $date->setTimestamp( $last_synced_at );
240 $date->setTimezone( new \DateTimeZone( 'UTC' ) );
241
242 $args['updated_after'] = $date->format( DATE_ATOM );
243 }
244
245 $response = wc_square()->get_api()->batch_retrieve_inventory_counts( $args );
246
247 // store the timestamp after the first API request was completed
248 // we don't want to set it at the end, as counts may have changed in the time it takes to process the data
249 // we also check that this is the first or only request to be made (no cursor) so we don't set it again if there's more data to query
250 if ( ! $cursor ) {
251 wc_square()->get_sync_handler()->set_inventory_last_synced_at();
252 }
253
254 foreach ( $response->get_counts() as $count ) {
255
256 // Square can return multiple "types" of counts, WooCommerce only distinguishes whether a product is in stock or not
257 if ( 'IN_STOCK' === $count->getState() ) {
258
259 $product = Product::get_product_by_square_variation_id( $count->getCatalogObjectId() );
260
261 if ( $product instanceof \WC_Product ) {
262
263 $product->set_stock_quantity( $count->getQuantity() );
264 $product->save();
265
266 $products_updated[] = $product->get_id();
267 }
268 }
269 }
270
271 $cursor = $response->get_data() instanceof BatchRetrieveInventoryCountsResponse ? $response->get_data()->getCursor() : null;
272
273 $this->set_attr( 'update_inventory_counts_cursor', $cursor );
274 $this->set_attr( 'processed_product_ids', array_unique( $products_updated ) );
275
276 if ( ! $cursor ) {
277 $this->complete_step( 'update_inventory_counts' );
278 }
279 }
280
281
282 }
283