Changeset 3169593
- Timestamp:
- 10/15/2024 08:57:35 PM (18 months ago)
- Location:
- activecampaign-for-woocommerce/trunk
- Files:
-
- 16 edited
-
README.txt (modified) (3 diffs)
-
ac_vendor/autoload.php (modified) (1 diff)
-
ac_vendor/composer/autoload_real.php (modified) (5 diffs)
-
ac_vendor/composer/autoload_static.php (modified) (2 diffs)
-
activecampaign-for-woocommerce.php (modified) (1 diff)
-
admin/class-activecampaign-for-woocommerce-admin-product-sync.php (modified) (2 diffs)
-
admin/views/activecampaign-for-woocommerce-product-sync.php (modified) (5 diffs)
-
includes/class-activecampaign-for-woocommerce.php (modified) (4 diffs)
-
includes/config/activecampaign-for-woocommerce-global-constants.php (modified) (1 diff)
-
includes/orders/class-activecampaign-for-woocommerce-new-order-created-event.php (modified) (1 diff)
-
includes/orders/class-activecampaign-for-woocommerce-new-order-sync-job.php (modified) (9 diffs)
-
includes/orders/class-activecampaign-for-woocommerce-order-action-events.php (modified) (6 diffs)
-
includes/products/class-activecampaign-for-woocommerce-product-sync-job.php (modified) (5 diffs)
-
includes/products/class-activecampaign-for-woocommerce-sync-status.php (modified) (1 diff)
-
includes/subscriptions/class-activecampaign-for-woocommerce-new-subscription-sync-job.php (modified) (2 diffs)
-
includes/traits/trait-activecampaign-for-woocommerce-arg-data-gathering.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
activecampaign-for-woocommerce/trunk/README.txt
r3151035 r3169593 4 4 Requires at least: 6.0 5 5 Tested up to: 6.6.2 6 Stable tag: 2.7. 76 Stable tag: 2.7.8 7 7 Requires PHP: 7.4 8 8 License: GPLv2 or later … … 68 68 69 69 = WooCommerce Compatibility = 70 * Tested up to version: 9. 2.370 * Tested up to version: 9.3.3 71 71 * Minimal version requirement: 7.4.0 72 72 * HPOS Compatible … … 94 94 95 95 == Changelog == 96 97 = 2.7.8 2024-10-15 = 98 * Bugfix - WooCommerce hook for stripe added to the order sync 99 * Bugfix - Order status changes should not get lost if done quickly 100 * Bugfix - Added debug display items for product sync 101 * Bugfix - Fixed product sync issue related to gathering records due to WC updates 96 102 97 103 = 2.7.7 2024-09-11 = -
activecampaign-for-woocommerce/trunk/ac_vendor/autoload.php
r3151035 r3169593 5 5 require_once __DIR__ . '/composer/autoload_real.php'; 6 6 7 return ComposerAutoloaderInit d890cba30b9ecdc77ec51b42cb0a1937::getLoader();7 return ComposerAutoloaderInit5559985682c8e8debf7e2ee247bd1345::getLoader(); -
activecampaign-for-woocommerce/trunk/ac_vendor/composer/autoload_real.php
r3151035 r3169593 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit d890cba30b9ecdc77ec51b42cb0a19375 class ComposerAutoloaderInit5559985682c8e8debf7e2ee247bd1345 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit d890cba30b9ecdc77ec51b42cb0a1937', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInit5559985682c8e8debf7e2ee247bd1345', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); 29 spl_autoload_unregister(array('ComposerAutoloaderInit d890cba30b9ecdc77ec51b42cb0a1937', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInit5559985682c8e8debf7e2ee247bd1345', 'loadClassLoader')); 30 30 31 31 $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); … … 33 33 require __DIR__ . '/autoload_static.php'; 34 34 35 call_user_func(\Composer\Autoload\ComposerStaticInit d890cba30b9ecdc77ec51b42cb0a1937::getInitializer($loader));35 call_user_func(\Composer\Autoload\ComposerStaticInit5559985682c8e8debf7e2ee247bd1345::getInitializer($loader)); 36 36 } else { 37 37 $map = require __DIR__ . '/autoload_namespaces.php'; … … 54 54 55 55 if ($useStaticLoader) { 56 $includeFiles = Composer\Autoload\ComposerStaticInit d890cba30b9ecdc77ec51b42cb0a1937::$files;56 $includeFiles = Composer\Autoload\ComposerStaticInit5559985682c8e8debf7e2ee247bd1345::$files; 57 57 } else { 58 58 $includeFiles = require __DIR__ . '/autoload_files.php'; 59 59 } 60 60 foreach ($includeFiles as $fileIdentifier => $file) { 61 composerRequire d890cba30b9ecdc77ec51b42cb0a1937($fileIdentifier, $file);61 composerRequire5559985682c8e8debf7e2ee247bd1345($fileIdentifier, $file); 62 62 } 63 63 … … 66 66 } 67 67 68 function composerRequire d890cba30b9ecdc77ec51b42cb0a1937($fileIdentifier, $file)68 function composerRequire5559985682c8e8debf7e2ee247bd1345($fileIdentifier, $file) 69 69 { 70 70 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { -
activecampaign-for-woocommerce/trunk/ac_vendor/composer/autoload_static.php
r3151035 r3169593 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit d890cba30b9ecdc77ec51b42cb0a19377 class ComposerStaticInit5559985682c8e8debf7e2ee247bd1345 8 8 { 9 9 public static $files = array ( … … 487 487 { 488 488 return \Closure::bind(function () use ($loader) { 489 $loader->prefixLengthsPsr4 = ComposerStaticInit d890cba30b9ecdc77ec51b42cb0a1937::$prefixLengthsPsr4;490 $loader->prefixDirsPsr4 = ComposerStaticInit d890cba30b9ecdc77ec51b42cb0a1937::$prefixDirsPsr4;491 $loader->classMap = ComposerStaticInit d890cba30b9ecdc77ec51b42cb0a1937::$classMap;489 $loader->prefixLengthsPsr4 = ComposerStaticInit5559985682c8e8debf7e2ee247bd1345::$prefixLengthsPsr4; 490 $loader->prefixDirsPsr4 = ComposerStaticInit5559985682c8e8debf7e2ee247bd1345::$prefixDirsPsr4; 491 $loader->classMap = ComposerStaticInit5559985682c8e8debf7e2ee247bd1345::$classMap; 492 492 493 493 }, null, ClassLoader::class); -
activecampaign-for-woocommerce/trunk/activecampaign-for-woocommerce.php
r3151035 r3169593 17 17 * Plugin URI: https://www.activecampaign.com/ 18 18 * Description: Add Abandoned Cart functionality to your WooCommerce store, synchronize order & customer information using ActiveCampaign. 19 * Version: 2.7. 719 * Version: 2.7.8 20 20 * WC requires at least: 7.4.0 21 * WC tested up to: 9. 2.321 * WC tested up to: 9.3.3 22 22 * Requires at least: 6.0 23 23 * Requires PHP: 7.4 -
activecampaign-for-woocommerce/trunk/admin/class-activecampaign-for-woocommerce-admin-product-sync.php
r2966088 r3169593 24 24 */ 25 25 trait Activecampaign_For_Woocommerce_Admin_Product_Sync { 26 use Activecampaign_For_Woocommerce_Admin_Utilities; 26 27 27 28 /** … … 65 66 ); 66 67 68 $data['products'] = $this->get_products_by_offset( -1, 15, true ); 67 69 $data['event_status'] = wp_get_scheduled_event( ACTIVECAMPAIGN_FOR_WOOCOMMERCE_RUN_PRODUCT_SYNC_NAME ); 68 70 $data['page_url'] = esc_url( admin_url( 'admin.php?page=' . ACTIVECAMPAIGN_FOR_WOOCOMMERCE_PLUGIN_NAME_SNAKE . '_product_sync&activesync=1' ) ); -
activecampaign-for-woocommerce/trunk/admin/views/activecampaign-for-woocommerce-product-sync.php
r3002947 r3169593 1 1 <?php 2 2 if ( ! isset( $activecampaign_for_woocommerce_product_sync_data['products'] ) || empty( $activecampaign_for_woocommerce_product_sync_data['products'] ) ) { 3 $activecampaign_for_woocommerce_product_sync_data['products'] = 0; 4 } 3 5 /** 4 6 * Provide an admin product sync view for the plugin … … 40 42 41 43 <div class="mb-500"> 42 Product data sync times vary based on the amount of product you're syncing in. you could check back later when sync is completed 44 Product data sync times vary based on the amount of product you're syncing in. you could check back later when sync is completed.<br/> 45 Product types that will not sync: Grouped, unpublished, private, pending, password protected 46 </div> 47 <div class="mb-500"> 48 There are <?php echo esc_html( count( $activecampaign_for_woocommerce_product_sync_data['products'] ) ); ?> products available to sync. 43 49 </div> 44 50 … … 84 90 <div id="sync-run-section"> 85 91 <div id="activecampaign-product-sync-run-shortly" class="sync-run-status" style="border:1px dashed #2271b1; padding:5px 10px; display:none;"> 86 <span> </span>92 <span>-</span> 87 93 <?php 88 94 esc_html_e( … … 132 138 <?php if ( $activecampaign_for_woocommerce_product_sync_data['options']['ac_debug'] ) : ?> 133 139 <div> 134 <p>Debug info: <span id="activecampaign-run-product-sync-debug">placeholder</span> 135 </p> 140 <p>Debug info: <span id="activecampaign-run-product-sync-debug">placeholder</span></p> 136 141 </div> 137 142 <?php endif; ?> … … 148 153 </div> 149 154 </div> 150 151 155 </div> 152 156 </div> 157 <?php 158 if ( $activecampaign_for_woocommerce_product_sync_data['options']['ac_debug'] && isset( $activecampaign_for_woocommerce_product_sync_data['products'] ) && ! empty( $activecampaign_for_woocommerce_product_sync_data['products'] ) ) : 159 ; 160 ?> 161 <div class="card max-w-none"> 162 <p>(Debug) Product IDs visible by the plugin to sync</p> 163 <p style=""><?php echo esc_html( implode( ', ', $activecampaign_for_woocommerce_product_sync_data['products'] ) ); ?></p> 164 </div> 165 <?php endif; ?> 153 166 </section> 154 167 </div> -
activecampaign-for-woocommerce/trunk/includes/class-activecampaign-for-woocommerce.php
r3128320 r3169593 594 594 $this->order_events, 595 595 'execute_order_updated', 596 20,596 90, 597 597 1 598 598 ); … … 601 601 'woocommerce_order_status_changed', 602 602 $this->order_events, 603 'execute_order_updated', 604 20 603 'execute_order_status_changed', 604 10, 605 3 606 ); 607 608 // needed for stripe 609 $this->loader->add_action( 610 'woocommerce_order_edit_status', 611 $this->order_events, 612 'execute_order_edit_status', 613 20, 614 2 605 615 ); 606 616 … … 612 622 2 613 623 ); 624 614 625 // On order refund 615 626 $this->loader->add_action( 616 627 'woocommerce_order_refunded', 617 628 $this->order_events, 618 'execute_order_updated ',629 'execute_order_updated_refund', 619 630 20, 620 1631 2 621 632 ); 622 633 … … 637 648 $this->new_order_sync, 638 649 'execute', 650 1, 651 2 652 ); 653 654 $this->loader->add_action( 655 'activecampaign_for_woocommerce_admin_sync_single_order_status', 656 $this->new_order_sync, 657 'execute_from_status', 639 658 1, 640 659 2 -
activecampaign-for-woocommerce/trunk/includes/config/activecampaign-for-woocommerce-global-constants.php
r3151035 r3169593 26 26 */ 27 27 if ( ! defined( 'ACTIVECAMPAIGN_FOR_WOOCOMMERCE_VERSION' ) ) { 28 define( 'ACTIVECAMPAIGN_FOR_WOOCOMMERCE_VERSION', '2.7. 7' );28 define( 'ACTIVECAMPAIGN_FOR_WOOCOMMERCE_VERSION', '2.7.8' ); 29 29 } 30 30 -
activecampaign-for-woocommerce/trunk/includes/orders/class-activecampaign-for-woocommerce-new-order-created-event.php
r3089566 r3169593 545 545 $this->schedule_recurring_order_sync_task(); 546 546 } 547 547 548 } -
activecampaign-for-woocommerce/trunk/includes/orders/class-activecampaign-for-woocommerce-new-order-sync-job.php
r2968938 r3169593 112 112 113 113 /** 114 * Sync any new/live orders.114 * Sync any orders triggered from a status update. 115 115 * Triggered from a hook call. 116 116 * 117 117 * @param mixed ...$args The passed args. 118 118 */ 119 public function execute( ...$args ) { 120 if ( ! $this->logger ) { 121 $this->logger = new Logger(); 122 } 123 124 $unsynced_order_data = null; 125 $recovered_orders = null; 119 public function execute_from_status( ...$args ) { 120 $wc_order_status = null; 126 121 127 122 try { … … 138 133 } 139 134 140 if ( isset( $wc_order_id ) ) { 141 // We're just syncing one row by order id 142 $wc_order = $this->get_wc_order( $wc_order_id ); 143 144 if ( false === $wc_order || ! $this->order_has_required_data( $wc_order ) ) { 145 $this->mark_order_as_incompatible( $wc_order_id ); 146 return false; 147 } 148 149 $ac_customer_id = $this->get_ac_customer_id( $wc_order->get_billing_email() ); 150 $ac_order = $this->single_sync_cofe_data( $wc_order, false, $ac_customer_id ); 151 152 if ( ! isset( $ac_order ) || ! $ac_order ) { 153 $this->logger->warning( 154 'The order may have failed to sync to cofe', 155 [ 156 $ac_order, 157 ] 158 ); 159 160 $this->mark_order_as_failed( $wc_order_id ); 161 } else { 162 $ac_id = null; 163 164 if ( self::validate_object( $ac_order, 'get_id' ) ) { 165 $ac_id = $ac_order->get_id(); 166 } 167 168 $this->add_update_notes( $wc_order_id, $ac_id, $wc_order->get_status() ); 169 $this->mark_single_order_synced( $wc_order_id ); 170 $this->update_last_order_sync(); 171 } 135 // get status 136 if ( isset( $args[1] ) && is_string( $args[1] ) ) { 137 $wc_order_status = $args[1]; 138 } 139 140 if ( isset( $args[0]['status'] ) ) { 141 $wc_order_status = $args[0]['status']; 142 } 143 144 if ( isset( $args['status'] ) ) { 145 $wc_order_status = $args['status']; 172 146 } 173 147 } catch ( Throwable $t ) { … … 184 158 } 185 159 } 160 try { 161 if ( isset( $wc_order_id ) ) { 162 // We're just syncing one row by order id 163 $wc_order = $this->get_wc_order( $wc_order_id ); 164 165 if ( false === $wc_order || ! $this->order_has_required_data( $wc_order ) ) { 166 $this->mark_order_as_incompatible( $wc_order_id ); 167 168 return false; 169 } 170 171 $this->add_meta_to_order( $wc_order ); 172 173 $ac_customer_id = $this->get_ac_customer_id( $wc_order->get_billing_email() ); 174 $ac_order = $this->single_sync_cofe_data( $wc_order, false, $ac_customer_id, $wc_order_status ); 175 176 if ( ! isset( $ac_order ) || ! $ac_order ) { 177 $this->logger->warning( 178 'The order may have failed to sync to cofe', 179 [ 180 $ac_order, 181 ] 182 ); 183 184 $this->mark_order_as_failed( $wc_order_id ); 185 } else { 186 $ac_id = null; 187 188 if ( self::validate_object( $ac_order, 'get_id' ) ) { 189 $ac_id = $ac_order->get_id(); 190 } 191 192 $this->add_update_notes( $wc_order_id, $ac_id, $wc_order_status ); 193 $this->mark_single_order_synced( $wc_order_id ); 194 $this->update_last_order_sync(); 195 } 196 } 197 } catch ( Throwable $t ) { 198 $this->logger->warning( 199 'Activecampaign_For_Woocommerce_New_Order_Sync: There was an error processing the order data.', 200 [ 201 'message' => $t->getMessage(), 202 'stack_trace' => $t->getTrace(), 203 ] 204 ); 205 } 206 } 207 208 /** 209 * Sync any new/live orders. 210 * Triggered from a hook call. 211 * 212 * @param mixed ...$args The passed args. 213 */ 214 public function execute( ...$args ) { 215 if ( ! $this->logger ) { 216 $this->logger = new Logger(); 217 } 218 219 $unsynced_order_data = null; 220 $recovered_orders = null; 221 222 try { 223 if ( isset( $args[0] ) && is_int( $args[0] ) ) { 224 $wc_order_id = $args[0]; 225 } 226 227 if ( isset( $args[0]['wc_order_id'] ) ) { 228 $wc_order_id = $args[0]['wc_order_id']; 229 } 230 231 if ( isset( $args['wc_order_id'] ) ) { 232 $wc_order_id = $args['wc_order_id']; 233 } 234 235 if ( isset( $wc_order_id ) ) { 236 // We're just syncing one row by order id 237 $wc_order = $this->get_wc_order( $wc_order_id ); 238 239 if ( false === $wc_order || ! $this->order_has_required_data( $wc_order ) ) { 240 $this->mark_order_as_incompatible( $wc_order_id ); 241 return false; 242 } 243 244 $ac_customer_id = $this->get_ac_customer_id( $wc_order->get_billing_email() ); 245 $ac_order = $this->single_sync_cofe_data( $wc_order, false, $ac_customer_id ); 246 247 if ( ! isset( $ac_order ) || ! $ac_order ) { 248 $this->logger->warning( 249 'The order may have failed to sync to cofe', 250 [ 251 $ac_order, 252 ] 253 ); 254 255 $this->mark_order_as_failed( $wc_order_id ); 256 } else { 257 $ac_id = null; 258 259 if ( self::validate_object( $ac_order, 'get_id' ) ) { 260 $ac_id = $ac_order->get_id(); 261 } 262 263 $this->add_update_notes( $wc_order_id, $ac_id, $wc_order->get_status() ); 264 $this->mark_single_order_synced( $wc_order_id ); 265 $this->update_last_order_sync(); 266 } 267 } 268 } catch ( Throwable $t ) { 269 $this->logger->error( 270 'Activecampaign_For_Woocommerce_New_Order_Sync: There was an error processing the order data by wc_order_id.', 271 [ 272 'args' => $args, 273 'message' => $t->getMessage(), 274 'stack_trace' => $t->getTrace(), 275 ] 276 ); 277 if ( isset( $wc_order_id ) && ! empty( $wc_order_id ) ) { 278 $this->mark_order_as_incompatible( $wc_order_id ); 279 } 280 } 186 281 187 282 try { … … 320 415 } 321 416 417 $this->add_meta_to_order( $wc_order ); 418 322 419 $this->add_update_notes( $prep_order->wc_order_id, $ac_id, $wc_order->get_status() ); 323 420 … … 380 477 } 381 478 479 $this->add_meta_to_order( $wc_order ); 382 480 $this->add_update_notes( $unsynced_recovered_order->wc_order_id, $ac_id, $wc_order->get_status() ); 383 481 … … 398 496 * @return false|void 399 497 */ 400 public function single_sync_cofe_data( $wc_order, $externalcheckoutid = false, $ac_customer_id = null ) {498 public function single_sync_cofe_data( $wc_order, $externalcheckoutid = false, $ac_customer_id = null, $status = null ) { 401 499 if ( ! isset( $wc_order ) ) { 402 500 return false; … … 416 514 // Data for cofe order sync 417 515 $ecom_order = $cofe_order_builder->setup_cofe_order_from_table( $wc_order, 1 ); 418 516 if ( ! is_null( $status ) ) { 517 $ecom_order->set_wc_status( $status ); 518 } 419 519 if ( is_null( $ecom_order ) ) { 420 520 $this->logger->warning( 'Setup COFE order returned null. Something may have gone wrong or the data may not be missing/incompatible with AC.' ); … … 548 648 $data['ac_order_id'] = $ac_order_id; 549 649 $data['synced_to_ac'] = self::STATUS_SYNCED; 650 550 651 $this->add_update_notes( $unsynced_order->wc_order_id, $ac_order_id ); 551 652 $this->update_last_order_sync(); … … 718 819 return $ac_customer_id; 719 820 } 821 822 /** 823 * @param WC_Order $wc_order The WooCommerce order object. 824 */ 825 private function add_meta_to_order( $wc_order ) { 826 // save the status so update checks do not sync the same data 827 $wc_order->add_meta_data( 'ac_last_synced_status', $wc_order->get_status(), true ); 828 829 $last_sync_time = $wc_order->get_meta( 'ac_order_last_synced_time' ); 830 $ac_datahash = $wc_order->get_meta( 'ac_datahash' ); 831 832 if ( ! empty( $last_sync_time ) ) { 833 $wc_order->update_meta_data( 'ac_order_last_synced_time', time() ); 834 } else { 835 $wc_order->add_meta_data( 'ac_order_last_synced_time', time(), true ); 836 } 837 838 if ( ! empty( $ac_datahash ) ) { 839 $wc_order->update_meta_data( 'ac_datahash', md5( json_encode( $wc_order->get_data() ) ) ); 840 } else { 841 $wc_order->add_meta_data( 'ac_datahash', md5( json_encode( $wc_order->get_data() ) ), true ); 842 } 843 844 $wc_order->save_meta_data(); 845 } 720 846 } -
activecampaign-for-woocommerce/trunk/includes/orders/class-activecampaign-for-woocommerce-order-action-events.php
r3128320 r3169593 74 74 } 75 75 76 /** 77 * An order update is always processed backend so it will not interrupt customer process. 78 * Due to that, we should always process immediately and not on a cron to keep data from going stale 79 * or from losing the data due to quick status changes. 80 * FYI New orders do not go through this process. 81 * 82 * @param string|int $order_id The order id as passed from the hook. 83 */ 76 84 public function execute_order_updated( $order_id ) { 77 85 $logger = new Logger(); 78 86 79 87 if ( isset( $order_id ) && ! empty( $order_id ) ) { 80 $logger->debug (88 $logger->debug_excess( 81 89 'Order update triggered', 82 90 [ … … 90 98 if ( 'shop_subscription' === $post_type ) { 91 99 $wc_subscription = $this->get_wc_subscription( $order_id ); 92 do_action( 'activecampaign_for_woocommerce_route_order_update_to_subscription', [ $wc_subscription ] ); 100 101 if ( $this->check_update_validity( $wc_subscription ) ) { 102 do_action( 'activecampaign_for_woocommerce_route_order_update_to_subscription', [ $wc_subscription ] ); 103 } 104 93 105 return; 94 106 } … … 99 111 } 100 112 101 set_transient( 'acforwc_order_updated_hook', wp_date( DATE_ATOM ), 604800 );102 103 113 $wc_order = $this->get_wc_order( $order_id ); 104 114 105 115 // Check if order is valid 106 if ( self::validate_object( $wc_order, 'get_data' ) ) { 107 // This will sync it immediately but also blindly 108 if ( ! wp_get_scheduled_event( 'activecampaign_for_woocommerce_admin_sync_single_order_active', [ 'wc_order_id' => $order_id ] ) ) { 116 if ( self::validate_object( $wc_order, 'get_data' ) && $this->check_update_validity( $wc_order ) ) { 117 set_transient( 'acforwc_order_updated_hook', wp_date( DATE_ATOM ), 604800 ); 118 119 if ( ! wp_get_scheduled_event( 120 'activecampaign_for_woocommerce_admin_sync_single_order_active', 121 [ 122 'wc_order_id' => $order_id, 123 'status' => $wc_order->get_status(), 124 ] 125 ) && 126 ! wp_get_scheduled_event( 127 'activecampaign_for_woocommerce_admin_sync_single_order_status', 128 [ 129 'wc_order_id' => $order_id, 130 'status' => $wc_order->get_status(), 131 ] 132 ) ) { 109 133 wp_schedule_single_event( 110 time() + 30,134 time() + 10, 111 135 'activecampaign_for_woocommerce_admin_sync_single_order_active', 112 136 [ 113 137 'wc_order_id' => $order_id, 138 'status' => $wc_order->get_status(), 114 139 ] 115 140 ); … … 127 152 128 153 /** 129 * @param object $stripe_response The stripe response. 130 * @param WC_Order $order The order. 131 */ 132 public function execute_order_updated_stripe( $stripe_response, $order ) { 133 $logger = new Logger(); 134 135 $order_id = null; 154 * Order status updates are processed through this function. 155 * 156 * @param int|string $order_id The order id. 157 * @param string $from_status The status the order changed from. 158 * @param string $to_status The status the order is changing to. 159 */ 160 public function execute_order_status_changed( $order_id, $from_status, $to_status ) { 161 $logger = new Logger(); 162 163 if ( isset( $order_id ) && ! empty( $order_id ) ) { 164 $logger->debug_excess( 165 'Order status update triggered', 166 [ 167 'order' => $order_id, 168 'order_status' => $from_status, 169 'new_status' => $to_status, 170 ] 171 ); 172 173 $post_type = get_post_type( $order_id ); 174 175 // If it's a subscription, route through subscription update. 176 if ( 'shop_subscription' === $post_type ) { 177 $wc_subscription = $this->get_wc_subscription( $order_id ); 178 179 do_action( 'activecampaign_for_woocommerce_route_order_update_to_subscription', [ $wc_subscription ] ); 180 return; 181 } 182 183 // If it's not an order do nothing, this could be anything 184 if ( 'shop_order' !== $post_type ) { 185 $logger->debug_excess( 186 'Order status update was triggered but the post is not a shop order type.', 187 [ 188 'order_id' => $order_id, 189 'post_type' => $post_type, 190 'new_status' => $to_status, 191 ] 192 ); 193 194 return; 195 } 196 197 $wc_order = $this->get_wc_order( $order_id ); 198 199 // Check if order is valid 200 if ( self::validate_object( $wc_order, 'get_data' ) ) { 201 set_transient( 'acforwc_order_updated_hook', wp_date( DATE_ATOM ), 604800 ); 202 203 if ( ! wp_get_scheduled_event( 204 'activecampaign_for_woocommerce_admin_sync_single_order_status', 205 [ 206 'wc_order_id' => $order_id, 207 'status' => $to_status, 208 ] 209 ) ) { 210 wp_schedule_single_event( 211 time() + 10, 212 'activecampaign_for_woocommerce_admin_sync_single_order_status', 213 [ 214 'wc_order_id' => $order_id, 215 'status' => $to_status, 216 ] 217 ); 218 } 219 } 220 } else { 221 $logger->warning( 222 'The updated order does not appear to be valid for sync to AC.', 223 [ 224 'order_id' => $order_id, 225 ] 226 ); 227 } 228 } 229 230 public function woocommerce_order_edit_status( $order_id, $new_status ) { 231 $wc_order = $this->get_wc_order( $order_id ); 232 233 if ( self::validate_object( $wc_order, 'get_data' ) ) { 234 set_transient( 'acforwc_order_updated_hook', wp_date( DATE_ATOM ), 604800 ); 235 236 if ( ! wp_get_scheduled_event( 237 'activecampaign_for_woocommerce_admin_sync_single_order_status', 238 [ 239 'wc_order_id' => $order_id, 240 'event_type' => 'status_' . $new_status, 241 ] 242 ) ) { 243 wp_schedule_single_event( 244 time() + 10, 245 'activecampaign_for_woocommerce_admin_sync_single_order_status', 246 [ 247 'wc_order_id' => $order_id, 248 'status' => $new_status, 249 ] 250 ); 251 } 252 } 253 } 254 255 /** 256 * The process used for an order refund. Technically this is the same as an order update. 257 * We pass this through a different function to note it in debug until we have relevant handling. 258 * 259 * @param string|int $order_id The order id. 260 * @param string|int $refund_id Refund id is passed and required but not used here. 261 */ 262 public function execute_order_updated_refund( $order_id, $refund_id ) { 263 $logger = new Logger(); 136 264 137 265 try { 138 $order_id = $order->get_id(); 139 140 if ( isset( $order_id ) && ! empty( $order_id ) ) { 141 $logger->debug( 142 'Stripe verified order triggered', 143 [ 144 'order_id' => $order_id, 145 ] 146 ); 147 148 $this->execute_order_updated( $order_id ); 266 $logger->debug_excess( 267 'Refund order update triggered', 268 [ 269 'order_id' => $order_id, 270 ] 271 ); 272 273 $this->execute_order_updated( $order_id ); 274 } catch ( Throwable $t ) { 275 $logger->warning( 276 'There was an issue updating the order from a refund trigger.', 277 [ 278 'order_id' => $order_id, 279 'message' => $t->getMessage(), 280 ] 281 ); 282 } 283 } 284 285 /** 286 * Stripe documentation is unhelpful but we need to process its updates. We do not use the response but it must be 287 * included in the function args. 288 * 289 * @param object|string $sripe_response Stripe response, unused. 290 * @param string|WC_Order $order Could be order object or order id, stripe does not say. 291 */ 292 public function execute_order_updated_stripe( $sripe_response, $order ) { 293 $logger = new Logger(); 294 295 try { 296 if ( isset( $sripe_response ) && isset( $order ) ) { 297 $wc_order = $this->get_wc_order( $order ); // Be sure we have the WC Order 298 $order_id = $wc_order->get_id(); 299 if ( isset( $order_id ) && ! empty( $order_id ) ) { 300 $logger->debug_excess( 301 'Stripe verified order update triggered', 302 [ 303 'order_id' => $order_id, 304 ] 305 ); 306 307 $this->execute_order_updated( $order_id ); 308 } 149 309 } 150 310 } catch ( Throwable $t ) { … … 152 312 'There was an issue updating the order from stripe.', 153 313 [ 154 'order _id' => $order_id,155 'message' => $t->getMessage(),314 'order' => $order, 315 'message' => $t->getMessage(), 156 316 ] 157 317 ); … … 236 396 } 237 397 } 398 399 /** 400 * Check to make sure we are not double syncing the same data. 401 * 402 * @param WC_Subscription|WC_Order $wc_order The order or subscription. Both carry these functions. 403 * 404 * @return bool 405 */ 406 private function check_update_validity( $wc_order ) { 407 $ac_datahash = $wc_order->get_meta( 'ac_datahash' ); 408 $current_datahash = md5( json_encode( $wc_order->get_data() ) ); 409 $last_synced = $wc_order->get_meta( 'ac_order_last_synced_time' ); 410 $last_status = $wc_order->get_meta( 'ac_last_synced_status' ); 411 412 if ( 413 time() - $last_synced > 120 && 414 isset( $last_status ) && 415 $last_status === $wc_order->get_status() && 416 $ac_datahash === $current_datahash 417 ) { 418 return false; 419 } 420 421 return true; 422 } 238 423 } -
activecampaign-for-woocommerce/trunk/includes/products/class-activecampaign-for-woocommerce-product-sync-job.php
r3049374 r3169593 28 28 */ 29 29 class Activecampaign_For_Woocommerce_Product_Sync_Job implements Executable { 30 use Activecampaign_For_Woocommerce_Data_Validation; 30 use Activecampaign_For_Woocommerce_Data_Validation, 31 Activecampaign_For_Woocommerce_Arg_Data_Gathering; 31 32 /** 32 33 * The custom ActiveCampaign logger … … 232 233 233 234 /** 234 * Gets the product IDs in the format we need.235 *236 * @param int $limit The limit.237 * @param int $offset The offset.238 * @param bool $return_id_only Marker for return IDs only.239 *240 * @return array|stdClass241 */242 private function get_products_by_offset( $limit, $offset, $return_id_only ) {243 // types available 'external', 'grouped', 'simple', 'variable'244 // Do not include groups for now.245 try {246 $safe_product_types = $this->get_cofe_safe_product_types();247 248 $data = [249 'limit' => (int) $limit,250 'offset' => (int) $offset,251 'type' => $safe_product_types,252 'orderby' => 'none',253 'order' => 'ASC',254 ];255 256 if ( $return_id_only ) {257 $data['return'] = 'ids';258 }259 260 $this->logger->debug(261 'Getting products by offset',262 [263 'producttypes' => $safe_product_types,264 'data' => $data,265 'return_id_only' => $return_id_only,266 ]267 );268 269 $products = wc_get_products( $data );270 271 return $products;272 } catch ( Throwable $t ) {273 $this->logger->warning(274 'There was an issue getting products for the product sync',275 [276 'message' => $t->getMessage(),277 'request data' => $data,278 'return_id_only' => $return_id_only,279 ]280 );281 }282 return null;283 }284 285 /**286 235 * Build the product sync schedules based on number of products. 287 236 * … … 625 574 global $activecampaign_for_woocommerce_product_sync_status; 626 575 try { 627 $p_data = Ecom_Cofe_Product::product_array_for_cofe( $product, $connection_id, $parent ); 628 if ( ! is_null( $p_data ) ) { 629 $product_data[] = $p_data; 576 if ( $product->is_type( 'grouped' ) || $product->is_type( 'draft' ) ) { 577 $this->add_failed_product_to_status( $status, $product ); 578 } else { 579 $p_data = Ecom_Cofe_Product::product_array_for_cofe( $product, $connection_id, $parent ); 580 if ( ! is_null( $p_data ) ) { 581 $product_data[] = $p_data; 582 } 630 583 } 631 584 } catch ( Throwable $t ) { … … 692 645 private function add_failed_product_to_status( Sync_Status $status, ?WC_Product $product = null ) { 693 646 if ( $product && self::validate_object( $product, 'get_id' ) && ! empty( $product->get_id() ) ) { 694 $status->failed_ order_id_array[] = $product->get_id();647 $status->failed_id_array[] = $product->get_id(); 695 648 } else { 696 $status->failed_ order_id_array[] = 'Unknown WC Product';649 $status->failed_id_array[] = 'Unknown WC Product'; 697 650 } 698 651 } … … 789 742 } 790 743 791 /**792 * Gets the safe COFE product types. This is a blacklist to remove any types that cause duplicates, conflicts, or issues with sync.793 *794 * @return int[]|string[]795 */796 private function get_cofe_safe_product_types() {797 $product_types = wc_get_product_types();798 799 // Blacklist certain types that cause conflicts & duplicates800 if ( isset( $product_types['grouped'] ) ) {801 unset( $product_types['grouped'] );802 }803 804 if ( isset( $product_types['draft'] ) ) {805 unset( $product_types['draft'] );806 }807 808 // WC returns array as type_name: type readable so return only the keys809 return array_keys( $product_types );810 }811 812 744 public function execute_product_deleted( $product_id ) { 813 745 $logger = new Logger(); -
activecampaign-for-woocommerce/trunk/includes/products/class-activecampaign-for-woocommerce-sync-status.php
r3068573 r3169593 51 51 $data['last_update'], 52 52 $data['end_time'], 53 $data['failed_ order_id_array'],53 $data['failed_id_array'], 54 54 $data['is_running'], 55 55 $data['status_name'] -
activecampaign-for-woocommerce/trunk/includes/subscriptions/class-activecampaign-for-woocommerce-new-subscription-sync-job.php
r3100804 r3169593 150 150 $this->mark_order_as_incompatible( $wc_order_id ); 151 151 return false; 152 }153 154 $ac_customer_id = $this->get_ac_customer_id( $wc_subscription->get_billing_email() );155 $ac_order = $this->single_sync_subscription_cofe_data( $wc_subscription, false, $ac_customer_id );156 157 if ( ! isset( $ac_order ) || ! $ac_order ) {158 $this->logger->warning(159 'The order may have failed to sync to cofe',160 [161 'order_id' => $wc_order_id,162 'sync_data' => $ac_order,163 'ac_code' => 'SSJ_158',164 ]165 );166 167 $this->mark_subscription_as_failed( $wc_order_id );168 152 } else { 169 $ac_id = null; 170 171 if ( self::validate_object( $ac_order, 'get_id' ) ) { 172 $ac_id = $ac_order->get_id(); 153 154 $ac_customer_id = $this->get_ac_customer_id( $wc_subscription->get_billing_email() ); 155 $ac_order = $this->single_sync_subscription_cofe_data( $wc_subscription, false, $ac_customer_id ); 156 157 if ( ! isset( $ac_order ) || ! $ac_order ) { 158 $this->logger->warning( 159 'The order may have failed to sync to cofe', 160 [ 161 'order_id' => $wc_order_id, 162 'sync_data' => $ac_order, 163 'ac_code' => 'SSJ_158', 164 ] 165 ); 166 167 $this->mark_subscription_as_failed( $wc_order_id ); 168 } else { 169 $ac_id = null; 170 171 if ( self::validate_object( $ac_order, 'get_id' ) ) { 172 $ac_id = $ac_order->get_id(); 173 } 174 175 $this->add_meta_to_subscription( $wc_subscription ); 176 $this->add_update_notes( $wc_order_id, $ac_id, $wc_subscription->get_status() ); 177 $this->mark_single_order_synced( $wc_order_id ); 178 $this->update_last_subscription_sync(); 173 179 } 174 175 $this->add_update_notes( $wc_order_id, $ac_id, $wc_subscription->get_status() );176 $this->mark_single_order_synced( $wc_order_id );177 $this->update_last_subscription_sync();178 180 } 179 181 } … … 602 604 } 603 605 } 606 607 /** 608 * @param WC_Subscription $wc_subscription The WooCommerce order object. 609 */ 610 private function add_meta_to_subscription( $wc_subscription ) { 611 // save the status so update checks do not sync the same data 612 $wc_subscription->add_meta_data( 'ac_last_synced_status', $wc_subscription->get_status(), true ); 613 614 $last_sync_time = $wc_subscription->get_meta( 'ac_order_last_synced_time' ); 615 $ac_datahash = $wc_subscription->get_meta( 'ac_datahash' ); 616 617 if ( ! empty( $last_sync_time ) ) { 618 $wc_subscription->update_meta_data( 'ac_order_last_synced_time', time() ); 619 } else { 620 $wc_subscription->add_meta_data( 'ac_order_last_synced_time', time(), true ); 621 } 622 623 if ( ! empty( $ac_datahash ) ) { 624 $wc_subscription->update_meta_data( 'ac_datahash', md5( json_encode( $wc_subscription->get_data() ) ) ); 625 } else { 626 $wc_subscription->add_meta_data( 'ac_datahash', md5( json_encode( $wc_subscription->get_data() ) ), true ); 627 } 628 629 $wc_subscription->save_meta_data(); 630 } 604 631 } -
activecampaign-for-woocommerce/trunk/includes/traits/trait-activecampaign-for-woocommerce-arg-data-gathering.php
r3089566 r3169593 108 108 109 109 } 110 111 /** 112 * Gets the product IDs in the format we need. 113 * 114 * @param int $limit The limit. 115 * @param int $offset The offset. 116 * @param bool $return_id_only Marker for return IDs only. 117 * 118 * @return array|stdClass 119 */ 120 public static function get_products_by_offset( $limit, $offset, $return_id_only ) { 121 // types standard available 'external', 'grouped', 'simple', 'variable' 122 // Do not include groups for now. 123 $logger = new Logger(); 124 try { 125 $safe_product_types = self::get_cofe_safe_product_types(); // This may be causing an issue with some 3rd party plugins due to custom product types. 126 127 $data = [ 128 'limit' => (int) $limit, 129 'offset' => (int) $offset, 130 'orderby' => 'ID', 131 'status' => 'publish', 132 'order' => 'ASC', 133 ]; 134 135 if ( isset( $safe_product_types ) && ! empty( $safe_product_types ) ) { 136 $data['type'] = $safe_product_types; 137 } 138 139 if ( $return_id_only ) { 140 $data['return'] = 'ids'; 141 } 142 143 $logger->debug( 144 'Getting products by offset', 145 [ 146 'producttypes' => $safe_product_types, 147 'data' => $data, 148 'return_id_only' => $return_id_only, 149 ] 150 ); 151 152 $products = wc_get_products( $data ); 153 154 return $products; 155 } catch ( Throwable $t ) { 156 $logger = new Logger(); 157 $logger->warning( 158 'There was an issue getting products for the product sync', 159 [ 160 'message' => $t->getMessage(), 161 'return_id_only' => $return_id_only, 162 ] 163 ); 164 } 165 return null; 166 } 167 168 169 170 public static function get_cofe_safe_product_types() { 171 $product_types = wc_get_product_types(); 172 173 // Blacklist certain types that cause conflicts & duplicates 174 if ( isset( $product_types['grouped'] ) ) { 175 unset( $product_types['grouped'] ); // Grouped products are bundles of existing single products. These cause duplicate records. 176 } 177 178 if ( isset( $product_types['draft'] ) ) { 179 unset( $product_types['draft'] ); // Never sync drafts 180 } 181 182 // WC returns array as type_name: type readable so return only the keys 183 return array_keys( $product_types ); 184 } 185 110 186 }
Note: See TracChangeset
for help on using the changeset viewer.