PluginProbe ʕ •ᴥ•ʔ
WooCommerce Square / 2.2.5
WooCommerce Square v2.2.5
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 / Handlers / Order.php
woocommerce-square / includes / Handlers Last commit date
Product 6 years ago Background_Job.php 6 years ago Category.php 6 years ago Connection.php 6 years ago Email.php 6 years ago Order.php 6 years ago Product.php 5 years ago Products.php 5 years ago Sync.php 5 years ago
Order.php
307 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\Handlers;
25
26 use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27 use WooCommerce\Square\Plugin;
28 use WooCommerce\Square\Handlers\Product;
29
30 defined( 'ABSPATH' ) || exit;
31
32 /**
33 * Order handler class.
34 *
35 * @since 2.0.0
36 */
37 class Order {
38
39 /**
40 * Array of previous stock values.
41 *
42 * @var array
43 */
44 private $previous_stock = array();
45
46 /**
47 * Array of product IDs that have been scheduled for sync in this request.
48 *
49 * @var array
50 */
51 private $products_to_sync = array();
52
53
54 /**
55 * Sets up Square order handler.
56 *
57 * @since 2.0.0
58 */
59 public function __construct() {
60
61 // remove Square variation IDs from order item meta
62 add_action( 'woocommerce_hidden_order_itemmeta', array( $this, 'hide_square_order_item_meta' ) );
63
64 // ADD hooks for stock syncs based on changes from orders not from this gateway
65 add_action( 'woocommerce_checkout_order_processed', array( $this, 'maybe_sync_stock_for_order_via_other_gateway' ), 10, 3 );
66
67 // Add specific hook for paypal IPN callback
68 add_action( 'valid-paypal-standard-ipn-request', array( $this, 'maybe_sync_stock_for_order_via_paypal' ), 10, 1 );
69
70 // ADD hooks to listen to refunds on orders from other gateways.
71 add_action( 'woocommerce_order_refunded', array( $this, 'maybe_sync_stock_for_refund_from_other_gateway' ), 10, 2 );
72 }
73
74
75 /**
76 * Ensures the Square order item meta is hidden.
77 *
78 * @since 2.0.0
79 *
80 * @param string[] $hidden the hidden order item meta
81 * @return string[] updated meta
82 */
83 public function hide_square_order_item_meta( $hidden ) {
84
85 $hidden[] = '_square_item_variation_id';
86
87 return $hidden;
88 }
89
90 /**
91 * Add hooks to ensure PayPal IPN callbacks are added caches and considered for inventory changes
92 * when the sync happens. This also adds the shutdown hook to ensure sync happens if needed at
93 * a later stage.
94 *
95 * @since 2.1.1
96 *
97 * @param array $posted values returned from PayPal Standard IPN callback.
98 */
99 public function maybe_sync_stock_for_order_via_paypal( $posted ) {
100 if ( empty( $posted['custom'] ) ) {
101 return;
102 }
103
104 $raw_order = json_decode( $posted['custom'] );
105 if ( empty( $raw_order->order_id ) ) {
106 return;
107 }
108
109 $order = wc_get_order( $raw_order->order_id );
110
111 if ( ! $order || ! $order instanceof \WC_Order ) {
112 return;
113 }
114
115 $this->sync_stock_for_order( $order );
116 }
117
118 /**
119 * Checks if we should sync stock for this order.
120 * We only sync for other gateways that Square will not be aware of.
121 *
122 * This functions sets a process in motion that gathers products that will be processed on shutdown.
123 *
124 * @since 2.0.8
125 *
126 * @param int $order_id Order ID number.
127 * @param array $posted_data Submitted order data.
128 * @param WC_Order $order Order object.
129 */
130 public function maybe_sync_stock_for_order_via_other_gateway( $order_id, $posted_data, $order ) {
131
132 // Confirm we are not processing the order through the Square gateway.
133 if ( ! $order instanceof \WC_Order || Plugin::GATEWAY_ID === $order->get_payment_method() ) {
134 return;
135 }
136
137 $this->sync_stock_for_order( $order );
138 }
139
140 /**
141 * For a given order sync stock if inventory sync is enabled.
142 *
143 * @since 2.1.1
144 *
145 * @param \WC_Order $order the order for which the stock must be synced.
146 */
147 protected function sync_stock_for_order( $order ) {
148
149 if ( ! wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
150 return;
151 }
152
153 $this->cache_previous_stock( $order );
154
155 add_action( 'woocommerce_product_set_stock', array( $this, 'maybe_stage_inventory_updates_for_product' ) );
156 add_action( 'woocommerce_variation_set_stock', array( $this, 'maybe_stage_inventory_updates_for_product' ) );
157
158 add_action( 'shutdown', array( $this, 'maybe_sync_staged_inventory_updates' ) );
159 }
160
161 /**
162 * Loop through order and cached previous stock values before they are reduced.
163 *
164 * @since 2.0.8
165 *
166 * @param WC_Order $order Order object.
167 */
168 private function cache_previous_stock( $order ) {
169
170 // Loop over all items.
171 foreach ( $order->get_items() as $item ) {
172 if ( ! $item->is_type( 'line_item' ) ) {
173 continue;
174 }
175
176 // Check to make sure it hasn't already been reduced.
177 $product = $item->get_product();
178 $item_stock_reduced = $item->get_meta( '_reduced_stock', true );
179
180 if ( $item_stock_reduced || ! $product || ! $product->managing_stock() ) {
181 continue;
182 }
183
184 $this->previous_stock[ $product->get_id() ] = $product->get_stock_quantity();
185 }
186 }
187
188 /**
189 * Stages a product inventory update for sync with Square when a product stock is updated.
190 *
191 * @internal The staged values will be stored in product_to_sync
192 *
193 * @since 2.0.8
194 *
195 * @param WC_Product $product the updated product with inventory updates.
196 */
197 public function maybe_stage_inventory_updates_for_product( $product ) {
198
199 // Do not add inventory changes if we are already doing a sync, or we are not syncing this product.
200 if ( defined( 'DOING_SQUARE_SYNC' ) || ! $product || ! Product::is_synced_with_square( $product ) ) {
201 return;
202 }
203
204 // Compare stock to get difference.
205 $product_id = $product->get_id();
206 $previous = isset( $this->previous_stock[ $product_id ] ) ? $this->previous_stock[ $product_id ] : false;
207 $current = $product->get_stock_quantity();
208 $adjustment = (int) $current - $previous;
209
210 if ( false === $previous || 0 === $adjustment ) {
211 return;
212 }
213
214 // Record what type of inventory action occurred.
215 $this->products_to_sync[ $product_id ] = $adjustment;
216 }
217
218
219 /**
220 * Initializes a synchronization event for any staged inventory updates in this request.
221 *
222 * @internal
223 *
224 * @since 2.0.8
225 */
226 public function maybe_sync_staged_inventory_updates() {
227
228 $inventory_adjustments = array();
229
230 foreach ( $this->products_to_sync as $product_id => $adjustment ) {
231
232 $product = wc_get_product( $product_id );
233 if ( ! $product instanceof \WC_Product ) {
234 continue;
235 }
236
237 $inventory_adjustment = Product::get_inventory_change_adjustment_type( $product, $adjustment );
238
239 if ( empty( $inventory_adjustment ) ) {
240 continue;
241 }
242
243 $inventory_adjustments[] = $inventory_adjustment;
244 }
245
246 if ( empty( $inventory_adjustments ) ) {
247 return;
248 }
249
250 wc_square()->log( 'New order from other gateway inventory syncing..' );
251 $idempotency_key = wc_square()->get_idempotency_key( md5( serialize( $inventory_adjustments ) ) . '_change_inventory' );
252 wc_square()->get_api()->batch_change_inventory( $idempotency_key, $inventory_adjustments );
253 }
254
255 /**
256 * Handle order refunds inventory/stock changes sync.
257 *
258 * @since 2.0.8
259 *
260 * @param in $order_id
261 * @param int $refund_id
262 */
263 public function maybe_sync_stock_for_refund_from_other_gateway( $order_id, $refund_id ) {
264
265 if ( ! wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
266 return;
267 }
268
269 // Confirm we are not processing the order through the Square gateway.
270 $order = wc_get_order( $order_id );
271 if ( ! $order instanceof \WC_Order || Plugin::GATEWAY_ID === $order->get_payment_method() ) {
272 return;
273 }
274
275 $refund = new \WC_Order_Refund( $refund_id );
276 $inventory_adjustments = array();
277 foreach ( $refund->get_items() as $item ) {
278
279 if ( 'line_item' !== $item->get_type() ) {
280 continue;
281 }
282
283 $product = $item->get_product();
284 if ( ! $product instanceof \WC_Product ) {
285 continue;
286 }
287
288 $adjustment = -1 * ( $item->get_quantity() ); // we want a positive value to increase the stock and a negative number to decrease it.
289 $inventory_adjustment = Product::get_inventory_change_adjustment_type( $product, $adjustment );
290
291 if ( empty( $inventory_adjustment ) ) {
292 continue;
293 }
294
295 $inventory_adjustments[] = $inventory_adjustment;
296 }
297
298 if ( empty( $inventory_adjustments ) ) {
299 return;
300 }
301
302 wc_square()->log( 'Order from other gateway Refund inventory updates syncing..' );
303 $idempotency_key = wc_square()->get_idempotency_key( md5( serialize( $inventory_adjustments ) ) . '_change_inventory' );
304 wc_square()->get_api()->batch_change_inventory( $idempotency_key, $inventory_adjustments );
305 }
306 }
307