plugin = $plugin; } /** * Register hooks. * * @return void */ public function register() { add_filter( 'plugin_action_links_' . AKSMB_PLUGIN_BASENAME, array( $this, 'action_links' ) ); $scheduler = $this->plugin->scheduler(); if ( $scheduler ) { add_action( Constants::ACTION_EVALUATE_ORDER, array( $scheduler, 'handle_evaluate_order' ), 10, 3 ); add_action( Constants::ACTION_SEED_PRICE_REVISIONS, array( $scheduler, 'handle_seed_price_revisions' ), 10, 1 ); add_action( Constants::ACTION_RECONCILE_PRICE_REVISIONS, array( $scheduler, 'handle_reconcile_price_revisions' ), 10, 1 ); add_action( Constants::ACTION_RUN_SELECTED_PREFLIGHT, array( $scheduler, 'handle_run_selected_preflight' ), 10, 2 ); add_action( Constants::ACTION_SYNC_ACK_COUPON, array( $scheduler, 'handle_sync_ack_coupon' ), 10, 2 ); add_action( Constants::ACTION_COGS_MIGRATION_BATCH, array( $scheduler, 'handle_cogs_migration_batch' ), 10, 1 ); } // Pro AS/cron handlers are registered by marginbeacon-pro companion (ProHooks). if ( ! wp_next_scheduled( 'aksmb_daily_retention_cleanup' ) ) { $scheduled = wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'aksmb_daily_retention_cleanup', array(), true ); if ( false === $scheduled || is_wp_error( $scheduled ) ) { $this->record_cron_schedule_failure( 'retention', 'aksmb_daily_retention_cleanup' ); } } add_action( 'aksmb_daily_retention_cleanup', array( $this, 'run_retention_cleanup' ) ); // Daily bounded reconciliation of price provenance (admin/background only). if ( ! wp_next_scheduled( 'aksmb_daily_price_reconcile' ) ) { $scheduled = wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'aksmb_daily_price_reconcile', array(), true ); if ( false === $scheduled || is_wp_error( $scheduled ) ) { $this->record_cron_schedule_failure( 'price_reconcile', 'aksmb_daily_price_reconcile' ); } } add_action( 'aksmb_daily_price_reconcile', array( $this, 'schedule_price_reconcile' ) ); } /** * @param string $domain Event domain. * @param string $hook Cron hook. * @return void */ private function record_cron_schedule_failure( $domain, $hook ) { if ( ! OperationalEventThrottle::allow( 'cron_schedule_failed:' . $hook ) ) { return; } ( new OperationalEventsRepository() )->record( $domain, 'daily', 'failed', 'schedule_failed', array( 'hook' => $hook ), 'cron_schedule_failed' ); } /** * Plugin row action links. * * @param array $links Existing links. * @return array */ public function action_links( $links ) { $url = admin_url( 'admin.php?page=marginbeacon' ); array_unshift( $links, sprintf( '%s', esc_url( $url ), esc_html__( 'Open MarginBeacon', 'marginbeacon' ) ) ); return $links; } /** * Enqueue bounded daily price revision reconciliation. * * @return void */ public function schedule_price_reconcile() { $scheduler = $this->plugin->scheduler(); if ( ! $scheduler ) { return; } $action_id = $scheduler->enqueue( Constants::ACTION_RECONCILE_PRICE_REVISIONS, array( 'batch' => 0 ), Constants::SCHEDULER_GROUP, null, 'reconcile_daily' ); if ( ! \Kayvandra\MarginBeacon\Infrastructure\Scheduler\SchedulerResult::is_enqueued( $action_id ) ) { update_option( 'aksmb_price_reconcile_continuation_failed', array( 'batch' => 0, 'at_gmt' => gmdate( 'Y-m-d H:i:s' ), 'error' => 'daily_enqueue_failed', ), false ); ( new \Kayvandra\MarginBeacon\Infrastructure\Persistence\OperationalEventsRepository() )->record( 'price_reconcile', 'daily', 'failed', 'continuation_failed', array( 'batch' => 0, 'phase' => 'daily_cron', ), 'scheduler_enqueue_failed' ); } } /** * Daily retention purge for expired operational rows. * * @return void */ public function run_retention_cleanup() { ( new \Kayvandra\MarginBeacon\Application\Retention\RetentionCleanupService() )->run(); do_action( 'aksmb_retention_cleanup' ); } }