feat(upsell): apply real cart discounts and track performance

This commit is contained in:
2026-05-08 19:16:01 +03:30
parent 8345e94a1b
commit fd9d29a0ee
19 changed files with 747 additions and 206 deletions

View File

@@ -102,11 +102,11 @@ class AdminController {
add_submenu_page(
'sodino-rules',
__('قیمت رقبا (به‌زودی)', 'sodino'),
__('قیمت رقبا (به‌زودی)', 'sodino'),
__('ابزارها و سلامت', 'sodino'),
__('ابزارها و سلامت', 'sodino'),
'manage_options',
'sodino-competitor-price',
[$this, 'competitorPricePage']
'sodino-tools',
[$this, 'toolsPage']
);
add_submenu_page(
@@ -295,10 +295,49 @@ class AdminController {
}
/**
* Competitor price page
* Tools and health page
*/
public function competitorPricePage() {
include SODINO_PLUGIN_DIR . 'admin/views/competitor-price.php';
public function toolsPage() {
$toolsData = $this->getToolsData();
include SODINO_PLUGIN_DIR . 'admin/views/tools.php';
}
public function handleToolsActions() {
if (!current_user_can('manage_options')) {
return;
}
if (($_GET['page'] ?? '') !== 'sodino-tools' || empty($_GET['tool_action'])) {
return;
}
$action = sanitize_key($_GET['tool_action']);
if (!isset($_GET['_wpnonce']) || !wp_verify_nonce($_GET['_wpnonce'], 'sodino_tools_' . $action)) {
wp_die(__('خطای امنیتی رخ داد.', 'sodino'));
}
if ($action === 'clear_cache') {
\Sodino\Core\Cache::getInstance()->clearAll();
$this->redirectWithNotice(admin_url('admin.php?page=sodino-tools'), __('کش سودینو با موفقیت پاک شد.', 'sodino'), 'success');
}
if ($action === 'run_migrations') {
require_once SODINO_PLUGIN_DIR . 'database/migrations.php';
sodino_create_tables();
$this->redirectWithNotice(admin_url('admin.php?page=sodino-tools'), __('ساختار دیتابیس سودینو بررسی و به‌روزرسانی شد.', 'sodino'), 'success');
}
if ($action === 'prune_events') {
$deleted = $this->deleteOldEvents(90);
$this->redirectWithNotice(
admin_url('admin.php?page=sodino-tools'),
sprintf(__('پاک‌سازی انجام شد. %d رویداد قدیمی حذف شد.', 'sodino'), $deleted),
'success'
);
}
wp_safe_redirect(admin_url('admin.php?page=sodino-tools'));
exit;
}
private function listUpsellsPage() {
@@ -385,6 +424,9 @@ class AdminController {
$upsell->target_product_id = max(0, intval($_POST['target_product_id'] ?? 0));
$upsell->discount_type = $discountType;
$upsell->discount_value = max(0, floatval($_POST['discount_value'] ?? 0));
if ($discountType === 'percentage') {
$upsell->discount_value = min(100, $upsell->discount_value);
}
$upsell->priority = max(1, intval($_POST['priority'] ?? 10));
$upsell->status = isset($_POST['status']) ? 1 : 0;
@@ -551,6 +593,80 @@ class AdminController {
wp_send_json($results);
}
private function getToolsData() {
global $wpdb;
$tables = [
'rules' => [
'label' => __('قوانین قیمت‌گذاری', 'sodino'),
'name' => $wpdb->prefix . 'sodino_rules',
],
'upsells' => [
'label' => __('آپسل‌ها', 'sodino'),
'name' => $wpdb->prefix . 'sodino_upsells',
],
'banners' => [
'label' => __('بنرها', 'sodino'),
'name' => $wpdb->prefix . 'sodino_banners',
],
'events' => [
'label' => __('رویدادهای تحلیلی', 'sodino'),
'name' => $wpdb->prefix . 'sodino_events',
],
'analytics_cache' => [
'label' => __('کش تحلیلی', 'sodino'),
'name' => $wpdb->prefix . 'sodino_analytics_cache',
],
];
foreach ($tables as $key => $table) {
$exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table['name']));
$tables[$key]['exists'] = (bool) $exists;
$tables[$key]['count'] = $exists ? (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table['name']}") : 0;
}
$eventsTable = $tables['events']['name'];
$oldEventCount = 0;
$oldestEvent = '';
if ($tables['events']['exists']) {
$cutoff = date('Y-m-d H:i:s', current_time('timestamp') - (90 * DAY_IN_SECONDS));
$oldEventCount = (int) $wpdb->get_var(
$wpdb->prepare("SELECT COUNT(*) FROM {$eventsTable} WHERE created_at < %s", $cutoff)
);
$oldestEvent = (string) $wpdb->get_var("SELECT MIN(created_at) FROM {$eventsTable}");
}
return [
'db_version' => get_option('sodino_db_version', '0'),
'expected_db_version' => defined('SODINO_DB_VERSION') ? SODINO_DB_VERSION : SODINO_VERSION,
'settings' => $this->getSettings(),
'tables' => $tables,
'old_event_count' => $oldEventCount,
'oldest_event' => $oldestEvent,
'actions' => [
'clear_cache' => wp_nonce_url(admin_url('admin.php?page=sodino-tools&tool_action=clear_cache'), 'sodino_tools_clear_cache'),
'run_migrations' => wp_nonce_url(admin_url('admin.php?page=sodino-tools&tool_action=run_migrations'), 'sodino_tools_run_migrations'),
'prune_events' => wp_nonce_url(admin_url('admin.php?page=sodino-tools&tool_action=prune_events'), 'sodino_tools_prune_events'),
],
];
}
private function deleteOldEvents($days) {
global $wpdb;
$days = max(1, (int) $days);
$eventsTable = $wpdb->prefix . 'sodino_events';
$exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $eventsTable));
if (!$exists) {
return 0;
}
$cutoff = date('Y-m-d H:i:s', current_time('timestamp') - ($days * DAY_IN_SECONDS));
$deleted = $wpdb->query($wpdb->prepare("DELETE FROM {$eventsTable} WHERE created_at < %s", $cutoff));
return $deleted === false ? 0 : (int) $deleted;
}
private function getSettingsDefaults() {
return [
'plugin_enabled' => 1,