PluginProbe
Gift Up Gift Cards for WordPress and WooCommerce / trunk
Gift Up Gift Cards for WordPress and WooCommerce vtrunk
3.2.2 3.1.7 3.1.8 3.2 3.2.1 wp5.2 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.2 1.2.1 1.2.2 1.2.3 1.2.4 All 131 releases
gift-up / includes / class-giftup-woocommerce.php

class-giftup-woocommerce.php in Gift Up Gift Cards for WordPress and WooCommerce trunk, at includes/class-giftup-woocommerce.php

402 lines 19.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class GiftUp_WooCommerce {
4
5 public function __construct()
6 {
7 if ( GiftUp()->options->get_woocommerce_enabled()
8 && GiftUp()->diagnostics->is_woocommerce_activated() ) {
9 require_once GIFTUP_ABSPATH . 'view/giftup-cart.php';
10
11 $cart_adjustment_priority = 100;
12
13 // Compatability with WooCommerce Extended Coupon Features PRO
14 if ( class_exists( 'WJECF_AutoCoupon' ) ) {
15 $cart_adjustment_priority = 20;
16 }
17
18 // Compatability with WooCommerce AvaTax
19 if ( class_exists( 'WC_AvaTax_Checkout_Handler' ) ) {
20 $cart_adjustment_priority = 1000;
21 }
22
23 // Compatability with Advanced Dynamic Pricing (AlgolPlus)
24 add_filter( 'wdp_calculate_totals_hook_priority', function( $priority ) use ( $cart_adjustment_priority ) { return $cart_adjustment_priority - 1; });
25
26 // Adjust the cart total to take into consideration the gift card balance
27 add_action( 'woocommerce_after_calculate_totals', array( __CLASS__, 'woocommerce_after_calculate_totals' ), $cart_adjustment_priority, 1 );
28 add_action( 'woocommerce_order_after_calculate_totals', array( __CLASS__, 'woocommerce_order_after_calculate_totals' ), 10, 2 );
29
30 // Entering the gift card code on the cart
31 add_action( 'woocommerce_cart_totals_before_order_total', 'giftup_woocommerce_cart_coupon' );
32
33 // Displaying the gift card code on the checkout/payment page
34 add_action( 'woocommerce_review_order_before_order_total', 'giftup_woocommerce_cart_coupon' );
35
36 // Adding the gift card code to the order metadata (legacy)
37 add_action( 'woocommerce_checkout_create_order', array( __CLASS__, 'woocommerce_checkout_create_order' ) );
38
39 // Adding the gift card code to the order metadata (blocks)
40 add_action( 'woocommerce_store_api_checkout_order_processed', array( __CLASS__, 'woocommerce_checkout_create_order' ) );
41
42 // Remove the gift card
43 add_action( 'woocommerce_cart_emptied', array( __CLASS__, 'woocommerce_cart_emptied' ) );
44 add_action( 'woocommerce_cart_item_removed', array( __CLASS__, 'woocommerce_cart_emptied' ) );
45
46 // Deduct the balance from the gift card
47 add_action( 'woocommerce_pre_payment_complete', array( __CLASS__, 'woocommerce_redeem_gift_card' ) );
48 add_action( 'woocommerce_order_status_processing', array( __CLASS__, 'woocommerce_redeem_gift_card' ) );
49 add_action( 'woocommerce_order_status_pre-ordered', array( __CLASS__, 'woocommerce_redeem_gift_card' ) );
50 add_action( 'woocommerce_order_status_completed', array( __CLASS__, 'woocommerce_redeem_gift_card' ) );
51 add_action( 'woocommerce_payment_complete', array( __CLASS__, 'woocommerce_redeem_gift_card' ) );
52
53 // Diagnostics output
54 add_action( 'wp_footer', array( 'giftup_diagnostics', 'render') );
55
56 add_action( 'wp_enqueue_scripts', array( __CLASS__, 'cart_scripts' ) );
57
58 if ( class_exists( 'Automattic\WooCommerce\Blocks\Package' ) && version_compare( \Automattic\WooCommerce\Blocks\Package::get_version(), '7.0.0' ) > 0 ) {
59 require_once GIFTUP_ABSPATH . 'includes/class-giftup-woocommerce-block.php';
60 }
61 }
62
63 // Rendering the gift card that has been used in an order in the admin order details page
64 add_action( 'woocommerce_admin_order_totals_after_tax', array( __CLASS__, 'woocommerce_admin_order_totals_after_tax' ) );
65
66 // Rendering the gift card that has been used in an order in the customers view post payment & emails
67 add_filter( 'woocommerce_get_order_item_totals', array( __CLASS__, 'woocommerce_get_order_item_totals' ), 30, 3 );
68 }
69
70 private static function apply_gift_card_to_cart_impl( $cart, $code ) {
71 $debug = GiftUp()->options->get_woocommerce_diagnostics_mode();
72
73 GiftUp()->diagnostics->append( "├ Entering apply_gift_card_to_cart…" );
74
75 if ( property_exists( $cart, 'recurring_cart_key' ) ) {
76 GiftUp()->diagnostics->append( "├ recurring_cart_key property exists, exiting." );
77 return;
78 }
79
80 if ( $debug ) {
81 GiftUp()->diagnostics->append( "├ Incoming cart sub-total: " . strval($cart->get_subtotal()) );
82 GiftUp()->diagnostics->append( "├ Incoming cart shipping: " . strval($cart->get_shipping_total()) );
83 GiftUp()->diagnostics->append( "├ Incoming cart taxes: " . strval($cart->get_total_tax()) );
84 GiftUp()->diagnostics->append( "├ Incoming cart total: " . strval($cart->total) );
85 }
86
87 GiftUp()->cache->set_gift_card_code( $code );
88
89 if ( !$code ) {
90 GiftUp()->diagnostics->append( "â”” No gift card code entered, exiting." );
91 return;
92 }
93
94 GiftUp()->diagnostics->append( "├ Gift card code: " . GiftUp()->cache->get_accepted_gift_card_code() );
95
96 if ( GiftUp()->api->get_is_currency_backed() == false ) {
97 GiftUp()->diagnostics->append( "â”” Cannot accept non-currency-backed gift cards in WooCommerce, exiting." );
98 return;
99 }
100
101 $gift_card_balance = GiftUp()->api->get_gift_card_balance();
102
103 if ( $gift_card_balance <= 0 ) {
104 GiftUp()->diagnostics->append( "â”” Gift card has no balance, exiting." );
105 return;
106 }
107
108 // Deal with this hook being replayed in the same request
109 if ( property_exists( $cart, 'giftup_new_calculated_total' ) ) {
110 if ( $debug ) {
111 GiftUp()->diagnostics->append( "├ Replaying compute request…" );
112 GiftUp()->diagnostics->append( "├ Previous incoming cart total: " . strval($cart->giftup_previous_incoming_cart_total) );
113 GiftUp()->diagnostics->append( "├ Previous applied balance: " . strval($cart->giftup_applied_gift_card_balance) );
114 GiftUp()->diagnostics->append( "├ Previous adjusted cart total: " . strval($cart->giftup_new_calculated_total) );
115 }
116
117 if ( abs($cart->giftup_new_calculated_total - $cart->total) < 0.00001 ) {
118 GiftUp()->diagnostics->append( "â”” Cart totals are the same: " . strval($cart->total) . ", exiting." );
119 return;
120 }
121
122 GiftUp()->diagnostics->append( "â”” Cart totals differ by: " . strval($cart->giftup_new_calculated_total - $cart->total) );
123 }
124
125 $eligible_cart_total = $cart->total;
126
127 if ( GiftUp()->options->get_woocommerce_apply_to_shipping() == false ) {
128 $eligible_cart_total = $eligible_cart_total - $cart->get_shipping_total();
129 GiftUp()->diagnostics->append( "├ Applying gift card to shipping" );
130 }
131
132 if ( GiftUp()->options->get_woocommerce_apply_to_taxes() == false ) {
133 $eligible_cart_total = $eligible_cart_total - $cart->get_total_tax();
134 GiftUp()->diagnostics->append( "├ Applying gift card to taxes" );
135 }
136
137 // Allow devs to mutate the cart total to filter items our etc...
138 $eligible_cart_total = apply_filters( 'giftup_eligible_cart_total', $eligible_cart_total, $cart );
139
140 // Make sure we don't set the cart total negative
141 $applied_gift_card_balance = min($eligible_cart_total , $gift_card_balance);
142
143 GiftUp()->diagnostics->append( "├ Eligible cart total: " . strval($eligible_cart_total) );
144 GiftUp()->diagnostics->append( "├ Gift card balance: " . strval($gift_card_balance) );
145
146 if ( $cart->total < $applied_gift_card_balance ) {
147 $applied_gift_card_balance = $cart->total;
148 }
149
150 $new_cart_total = $cart->total - $applied_gift_card_balance;
151
152 GiftUp()->diagnostics->append( "├ Applied balance: " . strval($applied_gift_card_balance) );
153 GiftUp()->diagnostics->append( "â”” New cart total: " . strval($new_cart_total) );
154
155 // Store some data about totals for replayability guard check
156 $cart->giftup_previous_incoming_cart_total = $cart->total;
157 $cart->giftup_new_calculated_total = $new_cart_total;
158 $cart->giftup_applied_gift_card_balance = $applied_gift_card_balance;
159
160 $cart->set_total(max(0, $new_cart_total));
161
162 try {
163 $cart->set_session();
164 } catch (exception $e) {
165 if ( $debug ) {
166 GiftUp()->diagnostics->append( "├ Exception calling cart->set_session()" );
167 GiftUp()->diagnostics->append( "├ " . $e->getMessage() );
168 }
169 }
170
171 // Store the gift card applied balance
172 GiftUp()->cache->applied_gift_card_balance = $applied_gift_card_balance;
173 }
174
175 /*
176 Invoked by new cart/checkout block code
177 */
178 public function apply_gift_card_to_cart( $cart, $code ) {
179 GiftUp()->diagnostics->new_group();
180 GiftUp()->diagnostics->append( "Entering apply_gift_card_to_cart" );
181
182 self::apply_gift_card_to_cart_impl( $cart, $code );
183
184 GiftUp()->diagnostics->append( "Exiting apply_gift_card_to_cart" );
185 }
186
187 /*
188 LEGACY
189 Adjust the cart total to take into consideration the gift card balance
190 This gets called on the basket page, on the checkoput page and before the order is created
191 */
192 public static function woocommerce_after_calculate_totals( $cart ) {
193 GiftUp()->diagnostics->new_group();
194 GiftUp()->diagnostics->append( "Entering woocommerce_after_calculate_totals…" );
195
196 $code = GiftUp()->cache->get_accepted_gift_card_code();
197
198 if ( is_cart() || is_checkout() ) {
199 if ( 'POST' == $_SERVER['REQUEST_METHOD'] && isset($_POST['giftup_gift_card_code']) ) {
200 if (strlen( $_POST['giftup_gift_card_code'] ) > 0) {
201 GiftUp()->diagnostics->append( "â”” Setting gift card code to: " . $_POST['giftup_gift_card_code'] );
202 } else {
203 GiftUp()->diagnostics->append( "â”” Clearing gift card code" );
204 }
205
206 $code = $_POST['giftup_gift_card_code'];
207 }
208 }
209
210 if ( isset($code) ) {
211 self::apply_gift_card_to_cart_impl( $cart, $code );
212 }
213
214 GiftUp()->diagnostics->append( "Exiting woocommerce_after_calculate_totals…" );
215 }
216
217 /**
218 * Get Gift Cards total amount from a given order.
219 *
220 * @param bool $and_taxes
221 * @param WC_Order $order
222 * @return void
223 */
224 public static function woocommerce_order_after_calculate_totals( $and_taxes, $order ) {
225 $applied_balance = GiftUp()->cache->applied_gift_card_balance;;
226 if ( $applied_balance > 0 ) {
227 $order->set_total( max( 0, $order->get_total() - $applied_balance ) );
228 }
229 }
230
231 public static function cart_scripts() {
232 wp_enqueue_script( 'giftup-cart-script', plugins_url( 'gift-up' ) . '/view/giftup-cart.js', array(), GIFTUP_VERSION );
233 }
234
235 /*
236 Rendering the gift card that has been used in an order in the admin order details page
237 This is the admin view when viewing an order. It is not translated.
238 */
239 public static function woocommerce_admin_order_totals_after_tax ( $order_id ) {
240 $order = wc_get_order( $order_id );
241
242 if ( $order -> meta_exists(GIFTUP_ORDER_META_CODE_KEY) ) {
243 $code = trim( $order -> get_meta(GIFTUP_ORDER_META_CODE_KEY) );
244 $requested_balance = $order -> get_meta(GIFTUP_ORDER_META_REQUESTED_BALANCE_KEY);
245 $outstanding = $requested_balance;
246
247 if ( $order -> meta_exists(GIFTUP_ORDER_META_REDEEMED_BALANCE_KEY) ) {
248 $redeemed_balance = $order -> get_meta(GIFTUP_ORDER_META_REDEEMED_BALANCE_KEY);
249 $outstanding = $requested_balance - $redeemed_balance;
250 }
251
252 if ( $requested_balance > 0 ) {
253 ?>
254 <tr>
255 <td class="label">Gift card (<a href="https://giftup.app/orders?search=<?php echo $code; // WPCS: XSS ok. ?>" target="_blank" style="text-transform: uppercase"><?php echo $code; // WPCS: XSS ok. ?></a>):</td>
256 <td width="1%"></td>
257 <td class="total">
258 <?php echo wc_price( -1 * $requested_balance, array( 'currency' => $order->get_currency() ) ); // WPCS: XSS ok. ?>
259 </td>
260 </tr>
261 <?php
262 if ( $outstanding > 0 && $order -> get_status() == "on-hold" ) {
263 ?>
264 <tr>
265 <td colspan="3" style="color: red">
266 Please ensure
267 <?php echo wc_price( $outstanding, array( 'currency' => $order->get_currency() ) ); // WPCS: XSS ok. ?>
268 has been redeemed from the gift card in Gift Up!
269 </td>
270 </tr>
271 <?php
272 }
273 }
274 }
275 }
276
277 /*
278 Rendering the gift card that has been used in an order in the customers view post payment & emails
279 This is the customers view when viewing an order in My Account and in the emails & receipt
280 */
281 public static function woocommerce_get_order_item_totals( $total_rows, $order, $tax_display ) {
282 if ( $order -> meta_exists(GIFTUP_ORDER_META_CODE_KEY) ) {
283 $code = $order -> get_meta(GIFTUP_ORDER_META_CODE_KEY);
284 $applied_balance = $order -> get_meta(GIFTUP_ORDER_META_REQUESTED_BALANCE_KEY);
285
286 if ( $applied_balance > 0 ) {
287 // Set last total row in a variable and remove it.
288 $grand_total = $total_rows['order_total'];
289 unset( $total_rows['order_total'] );
290
291 // Insert a new row
292 $total_rows['giftup'] = array(
293 'label' => __( 'Gift card', 'gift-up' ) . ' (' . strtoupper( $code ) . '):',
294 'value' => wc_price( -1 * $applied_balance, array( 'currency' => $order->get_currency() ) ),
295 );
296
297 // Set back last total row
298 $total_rows['order_total'] = $grand_total;
299 }
300 }
301
302 return $total_rows;
303 }
304
305 /*
306 Store the code & requested balance as soon as we have a new order created
307 */
308 public static function woocommerce_checkout_create_order( $order ) {
309 $code = GiftUp()->cache->get_accepted_gift_card_code();
310
311 if ( isset($code) ) {
312 $applied_balance = GiftUp()->cache->applied_gift_card_balance;
313
314 if ( $applied_balance > 0 ) {
315 $order -> add_meta_data( GIFTUP_ORDER_META_CODE_KEY, $code );
316 $order -> add_meta_data( GIFTUP_ORDER_META_REQUESTED_BALANCE_KEY, $applied_balance );
317 $order -> add_meta_data( GIFTUP_ORDER_META_REDEEMED_BALANCE_KEY, 0 );
318 }
319 }
320 }
321
322 /*
323 Remove the gift card code from the checkout as soon as the order is placed
324 */
325 public static function woocommerce_cart_emptied() {
326 if (WC()->cart->get_cart_contents_count() == 0) {
327 GiftUp()->cache->set_gift_card_code( null );
328 }
329 }
330
331 /*
332 Deduct the balance from the gift card once 'payment has been made' (or for Cash On Delivery type payments, when it's set to 'processing')
333 This method is safe to repeatedly call
334 */
335 public static function woocommerce_redeem_gift_card( $order_id ) {
336 $order = wc_get_order( $order_id );
337
338 if ( $order -> meta_exists(GIFTUP_ORDER_META_CODE_KEY) ) {
339 $code = $order -> get_meta(GIFTUP_ORDER_META_CODE_KEY);
340 $requested_balance = $order -> get_meta(GIFTUP_ORDER_META_REQUESTED_BALANCE_KEY);
341 $redeemed_balance = $order -> get_meta(GIFTUP_ORDER_META_REDEEMED_BALANCE_KEY);
342 $outstanding = $requested_balance - $redeemed_balance;
343
344 if ( $outstanding > 0 ) {
345 $just_redeemed_value = GiftUp()->api->redeem_gift_card( $code, $outstanding, $order_id );
346
347 if ( $just_redeemed_value > 0 ) {
348 $order -> update_meta_data( GIFTUP_ORDER_META_REDEEMED_BALANCE_KEY, $just_redeemed_value + $redeemed_balance );
349 $order -> add_order_note( wc_price( $just_redeemed_value, array( 'currency' => $order->get_currency() ) ) . " redeemed from gift card " . strtoupper( $code ) . "." );
350 $order -> save();
351 }
352
353 self::woocommerce_possibly_hold_order( $order, $just_redeemed_value );
354 }
355 }
356 }
357
358 /*
359 If we've had an exceptional reason to put the order on hold
360 This only really occurs when there either:
361 1) Not enough balance on the gift card after all (i.e. bad actor)
362 2) There was a transient API call failure
363 */
364 private static function woocommerce_possibly_hold_order( $order, $just_redeemed_value ) {
365 if ( $order -> meta_exists(GIFTUP_ORDER_META_CODE_KEY) ) {
366 $code = $order -> get_meta(GIFTUP_ORDER_META_CODE_KEY);
367 $requested_balance = $order -> get_meta(GIFTUP_ORDER_META_REQUESTED_BALANCE_KEY);
368 $redeemed_balance = $order -> get_meta(GIFTUP_ORDER_META_REDEEMED_BALANCE_KEY);
369 $outstanding = $requested_balance - $redeemed_balance;
370
371 if ( $outstanding > 0 ) {
372 if ( $redeemed_balance > 0 ) {
373 $order -> add_order_note( "Gift card \"" . strtoupper( $code ) . "\" was not redeemed correctly. Only " . wc_price( $redeemed_balance, array( 'currency' => $order->get_currency() ) ) . " was redeemed off the gift card. Please redeem a further " . wc_price( $outstanding, array( 'currency' => $order->get_currency() ) ) . " from the gift card in Gift Up!" );
374 $order -> save();
375 }
376 else {
377 if ( $just_redeemed_value == -1001 ) {
378 $order -> add_order_note( "Gift card \"" . strtoupper( $code ) . "\" was not redeemed as the gift card could not be found in Gift Up." );
379 } else if ( $just_redeemed_value == -1002 ) {
380 $current_balance = GiftUp()->api->get_gift_card_balance( $code );
381 $order -> add_order_note( "Gift card \"" . strtoupper( $code ) . "\" was not redeemed as the gift card does not have enough remaining balance (" . wc_price( $current_balance, array( 'currency' => $order->get_currency() ) ) . ")." );
382 } else if ( $just_redeemed_value <= -2000 ) {
383 $response_code = abs($just_redeemed_value + 2000);
384 $order -> add_order_note( "Gift card \"" . strtoupper( $code ) . "\" was not redeemed as the Gift Up plugin -> Gift Up API call failed (code: " . $response_code . "). This is either due to a temporary issue with Gift Up's API, or possibly due to a security plugin/system installed in your WordPress environment. Please review your Gift Up's API logs here: https://giftup.app/integrations/api-logs" );
385 } else {
386 $order -> add_order_note( "Gift card \"" . strtoupper( $code ) . "\" was not redeemed (unknown reason: " . $just_redeemed_value . ")." );
387 }
388
389 $order -> save();
390 }
391
392 $status = $order -> get_status();
393
394 if ( $status != 'on-hold' && $status != 'completed' ) {
395 $order -> set_status('on-hold');
396 $order -> save();
397 }
398 }
399 }
400 }
401 }
402