scheduler() );
$result = $service->start();
add_settings_error(
'aksmb_overview',
'preview',
isset( $result['message'] ) ? (string) $result['message'] : __( 'Preview finished.', 'marginbeacon' ),
! empty( $result['success'] ) ? 'updated' : 'error'
);
set_transient(
'aksmb_overview_settings_errors_' . get_current_user_id(),
get_settings_errors( 'aksmb_overview' ),
30
);
wp_safe_redirect( Tabs::url( Tabs::DASHBOARD, array( 'preview' => 1 ) ) );
exit;
}
/**
* Render page.
*
* @return void
*/
public function render() {
if ( ! Capabilities::current_user_can_manage() ) {
wp_die( esc_html__( 'You do not have permission to access MarginBeacon.', 'marginbeacon' ) );
}
$stored = get_transient( 'aksmb_overview_settings_errors_' . get_current_user_id() );
if ( is_array( $stored ) ) {
foreach ( $stored as $error ) {
add_settings_error( $error['setting'], $error['code'], $error['message'], $error['type'] );
}
delete_transient( 'aksmb_overview_settings_errors_' . get_current_user_id() );
}
settings_errors( 'aksmb_overview' );
$health = ( new HealthService( Plugin::instance()->scheduler() ) )->collect()->to_array();
$coverage = ( new CostCoverageService() )->summarize( 10 );
$wizard = get_option( Constants::OPTION_WIZARD_STATE, array() );
$done = is_array( $wizard ) && ! empty( $wizard['completed'] );
$preview_service = new RecentOrdersPreviewService( Plugin::instance()->scheduler() );
$estimate = $preview_service->estimate();
$preview_state = $preview_service->state();
$risk_counts = ( new OrderRiskRepository() )->severity_counts();
$ack_count = ( new AcknowledgementService() )->count_active_fast();
$ack_display = (string) (int) $ack_count;
$compat = ( new CompatibilityRegistry() )->current();
$freshness = ( new FreshnessService() )->summarize();
$next_step = $this->next_step( $coverage, $done, $risk_counts, $preview_state );
?>
render_next_step( $next_step ); ?>
render_coverage_panel( $coverage, $done ); ?>
render_health_panel( $health, $compat, $freshness, $risk_counts, $ack_display ); ?>
render_preview_panel( $estimate, $preview_state ); ?>
render_getting_started_panel( $done, $coverage, $preview_state ); ?>
render_upgrade_cta_card();
?>
'warning',
'title' => __( 'Next step: finish cost setup', 'marginbeacon' ),
'body' => __( 'MarginBeacon cannot classify a product until it can resolve a tax-exclusive cost. Incomplete coverage never produces Safe.', 'marginbeacon' ),
'primary_label' => __( 'Open COGS Wizard', 'marginbeacon' ),
'primary_url' => Tabs::url( Tabs::COST_SETUP ),
'secondary_label' => __( 'Review thresholds', 'marginbeacon' ),
'secondary_url' => Tabs::url( Tabs::SETTINGS ),
);
}
if ( $missing > 0 ) {
return array(
'tone' => 'warning',
'title' => sprintf(
/* translators: %d: number of supported catalog items without a resolvable cost. */
_n( 'Next step: %d item still has no resolvable cost', 'Next step: %d items still have no resolvable cost', $missing, 'marginbeacon' ),
$missing
),
'body' => __( 'These items are reported as Unknown, never Safe. Add a native or MarginBeacon cost, or enable an assumed-cost fallback.', 'marginbeacon' ),
'primary_label' => __( 'Review cost coverage', 'marginbeacon' ),
'primary_url' => Tabs::url( Tabs::COST_SETUP, array( 'step' => 3 ) ),
'secondary_label' => __( 'Edit products', 'marginbeacon' ),
'secondary_url' => admin_url( 'edit.php?post_type=product' ),
);
}
if ( $critical > 0 ) {
return array(
'tone' => 'critical',
'title' => sprintf(
/* translators: %d: number of orders currently classified Critical. */
_n( 'Next step: %d order is flagged Critical', 'Next step: %d orders are flagged Critical', $critical, 'marginbeacon' ),
$critical
),
'body' => __( 'Open Findings to read the reason, cost source, and freshness for each order before deciding on any action.', 'marginbeacon' ),
'primary_label' => __( 'Open Findings', 'marginbeacon' ),
'primary_url' => Tabs::url( Tabs::FINDINGS ),
'secondary_label' => __( 'View WooCommerce Orders', 'marginbeacon' ),
'secondary_url' => admin_url( 'admin.php?page=wc-orders' ),
);
}
if ( empty( $preview_state['ever_run'] ) ) {
return array(
'tone' => 'info',
'title' => __( 'Next step: test a coupon before you launch it', 'marginbeacon' ),
'body' => __( 'Preflight simulates one native coupon at quantity 1 per eligible product. It never changes the coupon and never blocks checkout.', 'marginbeacon' ),
'primary_label' => __( 'Run preflight', 'marginbeacon' ),
'primary_url' => Tabs::url( Tabs::PREFLIGHT ),
'secondary_label' => __( 'Preview recent orders', 'marginbeacon' ),
'secondary_url' => '#aksmb-recent-preview',
);
}
return array(
'tone' => 'info',
'title' => __( 'Setup complete — keep watching new promotions', 'marginbeacon' ),
'body' => __( 'Cost coverage is resolved and no order is currently Critical. Preflight a coupon before each campaign and review Promo Risk badges on new orders.', 'marginbeacon' ),
'primary_label' => __( 'Run preflight', 'marginbeacon' ),
'primary_url' => Tabs::url( Tabs::PREFLIGHT ),
'secondary_label' => __( 'Open Findings', 'marginbeacon' ),
'secondary_url' => Tabs::url( Tabs::FINDINGS ),
);
}
/**
* Render the priority next-step panel.
*
* @param array $step Step descriptor.
* @return void
*/
private function render_next_step( array $step ) {
$tone = isset( $step['tone'] ) ? (string) $step['tone'] : 'info';
if ( ! in_array( $tone, array( 'info', 'warning', 'critical' ), true ) ) {
$tone = 'info';
}
?>
%2$s%3$s',
esc_attr( $level ),
esc_html( $level_label ),
esc_html( (string) $count ),
esc_attr( $count_label )
);
}
?>
(bool) $done,
'text' => __( 'Complete the COGS Wizard and fill missing product costs.', 'marginbeacon' ),
'url' => Tabs::url( Tabs::COST_SETUP ),
'label' => __( 'Open COGS Wizard', 'marginbeacon' ),
),
array(
'complete' => $done && 0 === (int) $coverage['missing'],
'text' => __( 'Resolve every supported product cost so results stop being Unknown.', 'marginbeacon' ),
'url' => Tabs::url( Tabs::COST_SETUP, array( 'step' => 3 ) ),
'label' => __( 'Review coverage', 'marginbeacon' ),
),
array(
'complete' => false,
'text' => __( 'Run a selected-coupon preflight before launching a campaign.', 'marginbeacon' ),
'url' => Tabs::url( Tabs::PREFLIGHT ),
'label' => __( 'Run preflight', 'marginbeacon' ),
),
array(
'complete' => ! empty( $preview_state['ever_run'] ),
'text' => __( 'Optionally run Recent Orders Preview, then watch Promo Risk badges on Orders.', 'marginbeacon' ),
'url' => Tabs::url( Tabs::FINDINGS ),
'label' => __( 'Open Findings', 'marginbeacon' ),
),
);
?>
render();
}
}