__( 'You do not have permission to do this.', ACHP_TEXT_DOMAIN ) ], 403 ); } check_ajax_referer( self::PURGE_NONCE, 'nonce' ); if ( ! class_exists( 'ACHP_Status_Poller' ) ) { wp_send_json_error( [ 'message' => __( 'Status poller is not available.', ACHP_TEXT_DOMAIN ) ], 500 ); } try { $cancelled = ACHP_Status_Poller::purge_all_scheduled(); } catch ( \Throwable $e ) { wc_get_logger()->error( sprintf( 'Manual schedule purge failed: %s', $e->getMessage() ), [ 'source' => 'ach-processing' ] ); wp_send_json_error( [ 'message' => __( 'Purge failed. See WooCommerce → Status → Logs (ach-processing) for details.', ACHP_TEXT_DOMAIN ) ], 500 ); } $summary = sprintf( /* translators: %d: number of stale scheduled actions removed. */ _n( 'Purge complete. Removed %d stale scheduled action.', 'Purge complete. Removed %d stale scheduled actions.', (int) $cancelled, ACHP_TEXT_DOMAIN ), (int) $cancelled ); wp_send_json_success( [ 'message' => $summary, 'cancelled' => (int) $cancelled, ] ); } /** * Manual trigger for the status poller, fired by the "Check Status" * button on the gateway settings screen. */ public function ajax_run_poll_now() { if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( [ 'message' => __( 'You do not have permission to run the status check.', ACHP_TEXT_DOMAIN ) ], 403 ); } check_ajax_referer( self::POLL_NOW_NONCE, 'nonce' ); if ( ! class_exists( 'ACHP_Status_Poller' ) ) { wp_send_json_error( [ 'message' => __( 'Status poller is not available.', ACHP_TEXT_DOMAIN ) ], 500 ); } try { $stats = ACHP_Status_Poller::run( true ); // Manual trigger bypasses the scheduling floor. } catch ( \Throwable $e ) { wc_get_logger()->error( sprintf( 'Manual status poll failed: %s', $e->getMessage() ), [ 'source' => 'ach-processing' ] ); wp_send_json_error( [ 'message' => __( 'Status check failed. See WooCommerce → Status → Logs (ach-processing) for details.', ACHP_TEXT_DOMAIN ) ], 500 ); } $stats = is_array( $stats ) ? $stats : []; $updated = (int) ( $stats['updated'] ?? 0 ); $summary = sprintf( /* translators: %d: number of orders whose status was updated. */ _n( 'Status check complete. %d order updated.', 'Status check complete. %d orders updated.', $updated, ACHP_TEXT_DOMAIN ), $updated ); wp_send_json_success( [ 'message' => $summary, 'stats' => $stats, ] ); } public function webhook_callback() { $request_body = file_get_contents( 'php://input' ); wc_get_logger()->debug( print_r( $request_body, true ), [ 'source' => 'ach-processing-webhook' ] ); } public function add_token_notice() { // Only surface this on the WooCommerce settings screen to avoid // polluting every admin page. $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( ! $screen || 'woocommerce_page_wc-settings' !== $screen->id ) { return; } $token = get_option( 'achp_access_token' ); $expiry = (int) get_option( 'achp_access_token_expiry' ); $now = time(); $missing = empty( $token ) || 0 === $expiry; $expired = ! $missing && $now > $expiry; if ( ! $missing && ! $expired ) { return; } $message = $missing ? __( 'ACH Processing access token is missing. Verify API credentials and save settings to generate one.', ACHP_TEXT_DOMAIN ) : __( 'ACH Processing access token has expired. It will be refreshed automatically on the next scheduled run.', ACHP_TEXT_DOMAIN ); ?>