🔧 Bug Fixes: - Fixed download limits defaulting to 5 instead of 0 for unlimited downloads - Fixed software license filename sanitization (spaces→dashes, dots→underscores, proper .zip extension) - Software downloads now show as "Test-Plugin-v2-2-0.zip" instead of "Test Plugin v2.2.0" ✨ UI/UX Enhancements: - Redesigned license key display to span full table width with FontAwesome copy icons - Added responsive CSS styling for license key rows - Integrated FontAwesome CDN for modern copy icons 🏗️ Architecture Improvements: - Added comprehensive filename sanitization in both download handler and API paths - Enhanced software license product handling for local package files - Improved error handling and logging throughout download processes 📦 Infrastructure: - Added Gitea workflows for automated releases on push to main - Created comprehensive .gitignore excluding test files and browser automation - Updated documentation with all recent improvements and technical insights 🔍 Technical Details: - Software license products served from wp-content/uploads/wpdd-packages/ - Download flow: token → process_download_by_token() → process_download() → deliver_file() - Dual path coverage for both API downloads and regular file delivery - Version placeholder system for automated deployment 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			903 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			903 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
if (!defined('ABSPATH')) {
 | 
						|
    exit;
 | 
						|
}
 | 
						|
 | 
						|
class WPDD_Admin_Payouts {
 | 
						|
    
 | 
						|
    public static function init() {
 | 
						|
        add_action('admin_menu', array(__CLASS__, 'add_menu_page'));
 | 
						|
        add_action('admin_post_wpdd_process_payout', array(__CLASS__, 'process_payout'));
 | 
						|
        add_action('admin_post_wpdd_bulk_payouts', array(__CLASS__, 'process_bulk_payouts'));
 | 
						|
        add_action('admin_post_wpdd_process_payout_request', array(__CLASS__, 'process_payout_request'));
 | 
						|
        add_action('admin_post_wpdd_reject_payout_request', array(__CLASS__, 'reject_payout_request'));
 | 
						|
        add_action('admin_post_wpdd_manual_payout', array(__CLASS__, 'process_manual_payout'));
 | 
						|
        add_action('admin_post_wpdd_adjust_balance', array(__CLASS__, 'adjust_creator_balance'));
 | 
						|
        add_action('admin_enqueue_scripts', array(__CLASS__, 'enqueue_scripts'));
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function add_menu_page() {
 | 
						|
        add_submenu_page(
 | 
						|
            'edit.php?post_type=wpdd_product',
 | 
						|
            __('Creator Payouts', 'wp-digital-download'),
 | 
						|
            __('Payouts', 'wp-digital-download'),
 | 
						|
            'manage_options',
 | 
						|
            'wpdd-payouts',
 | 
						|
            array(__CLASS__, 'render_page')
 | 
						|
        );
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function enqueue_scripts($hook) {
 | 
						|
        if ($hook !== 'wpdd_product_page_wpdd-payouts') {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        
 | 
						|
        wp_enqueue_script('wpdd-admin-payouts', WPDD_PLUGIN_URL . 'assets/js/admin-payouts.js', array('jquery'), WPDD_VERSION, true);
 | 
						|
        wp_localize_script('wpdd-admin-payouts', 'wpdd_payouts', array(
 | 
						|
            'ajax_url' => admin_url('admin-ajax.php'),
 | 
						|
            'nonce' => wp_create_nonce('wpdd_payouts'),
 | 
						|
            'confirm_payout' => __('Are you sure you want to process this payout?', 'wp-digital-download'),
 | 
						|
            'confirm_bulk' => __('Are you sure you want to process all selected payouts?', 'wp-digital-download')
 | 
						|
        ));
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function render_page() {
 | 
						|
        global $wpdb;
 | 
						|
        
 | 
						|
        // Get filter parameters
 | 
						|
        $status_filter = isset($_GET['status']) ? sanitize_text_field($_GET['status']) : 'pending';
 | 
						|
        $creator_filter = isset($_GET['creator']) ? intval($_GET['creator']) : 0;
 | 
						|
        
 | 
						|
        // Get creators with balance
 | 
						|
        $creators = WPDD_Creator::get_creators_with_balance();
 | 
						|
        $currency = get_option('wpdd_currency', 'USD');
 | 
						|
        $threshold = floatval(get_option('wpdd_payout_threshold', 0));
 | 
						|
        
 | 
						|
        // Get payout requests (requested status)
 | 
						|
        $payout_requests = $wpdb->get_results(
 | 
						|
            "SELECT p.*, u.display_name, u.user_email 
 | 
						|
             FROM {$wpdb->prefix}wpdd_payouts p
 | 
						|
             INNER JOIN {$wpdb->users} u ON p.creator_id = u.ID
 | 
						|
             WHERE p.status = 'requested'
 | 
						|
             ORDER BY p.created_at ASC"
 | 
						|
        );
 | 
						|
        
 | 
						|
        // Get payout history
 | 
						|
        $query = "SELECT p.*, u.display_name, u.user_email 
 | 
						|
                  FROM {$wpdb->prefix}wpdd_payouts p
 | 
						|
                  INNER JOIN {$wpdb->users} u ON p.creator_id = u.ID
 | 
						|
                  WHERE 1=1";
 | 
						|
        
 | 
						|
        if ($status_filter && $status_filter !== 'all') {
 | 
						|
            $query .= $wpdb->prepare(" AND p.status = %s", $status_filter);
 | 
						|
        }
 | 
						|
        
 | 
						|
        if ($creator_filter) {
 | 
						|
            $query .= $wpdb->prepare(" AND p.creator_id = %d", $creator_filter);
 | 
						|
        }
 | 
						|
        
 | 
						|
        $query .= " ORDER BY p.created_at DESC LIMIT 100";
 | 
						|
        
 | 
						|
        $payouts = $wpdb->get_results($query);
 | 
						|
        
 | 
						|
        ?>
 | 
						|
        <div class="wrap">
 | 
						|
            <h1><?php _e('Creator Payouts', 'wp-digital-download'); ?></h1>
 | 
						|
            
 | 
						|
            <?php if (isset($_GET['message'])) : ?>
 | 
						|
                <?php if ($_GET['message'] === 'success') : ?>
 | 
						|
                    <div class="notice notice-success is-dismissible">
 | 
						|
                        <p><?php _e('Payout processed successfully.', 'wp-digital-download'); ?></p>
 | 
						|
                    </div>
 | 
						|
                <?php elseif ($_GET['message'] === 'error') : ?>
 | 
						|
                    <div class="notice notice-error is-dismissible">
 | 
						|
                        <p>
 | 
						|
                            <?php _e('Error processing payout:', 'wp-digital-download'); ?>
 | 
						|
                            <?php 
 | 
						|
                            $error_detail = isset($_GET['error_detail']) ? sanitize_text_field(urldecode($_GET['error_detail'])) : '';
 | 
						|
                            echo $error_detail ? '<strong>' . esc_html($error_detail) . '</strong>' : __('Unknown error occurred. Please try again.', 'wp-digital-download'); 
 | 
						|
                            ?>
 | 
						|
                        </p>
 | 
						|
                    </div>
 | 
						|
                <?php elseif ($_GET['message'] === 'balance_adjusted') : ?>
 | 
						|
                    <div class="notice notice-success is-dismissible">
 | 
						|
                        <p><?php _e('Creator balance adjusted successfully.', 'wp-digital-download'); ?></p>
 | 
						|
                    </div>
 | 
						|
                <?php endif; ?>
 | 
						|
            <?php endif; ?>
 | 
						|
            
 | 
						|
            <?php if (!empty($payout_requests)) : ?>
 | 
						|
            <div class="wpdd-payout-requests" style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 4px; padding: 20px; margin: 20px 0;">
 | 
						|
                <h2 style="margin-top: 0;"><?php _e('Payout Requests', 'wp-digital-download'); ?> <span class="count">(<?php echo count($payout_requests); ?>)</span></h2>
 | 
						|
                <p><?php _e('Creators have requested the following payouts:', 'wp-digital-download'); ?></p>
 | 
						|
                
 | 
						|
                <table class="wp-list-table widefat fixed striped">
 | 
						|
                    <thead>
 | 
						|
                        <tr>
 | 
						|
                            <th><?php _e('Creator', 'wp-digital-download'); ?></th>
 | 
						|
                            <th><?php _e('Amount', 'wp-digital-download'); ?></th>
 | 
						|
                            <th><?php _e('PayPal Email', 'wp-digital-download'); ?></th>
 | 
						|
                            <th><?php _e('Request Date', 'wp-digital-download'); ?></th>
 | 
						|
                            <th><?php _e('Actions', 'wp-digital-download'); ?></th>
 | 
						|
                        </tr>
 | 
						|
                    </thead>
 | 
						|
                    <tbody>
 | 
						|
                        <?php foreach ($payout_requests as $request) : ?>
 | 
						|
                        <tr>
 | 
						|
                            <td>
 | 
						|
                                <strong><?php echo esc_html($request->display_name); ?></strong><br>
 | 
						|
                                <small><?php echo esc_html($request->user_email); ?></small>
 | 
						|
                            </td>
 | 
						|
                            <td><strong><?php echo wpdd_format_price($request->amount, $request->currency); ?></strong></td>
 | 
						|
                            <td><?php echo esc_html($request->paypal_email); ?></td>
 | 
						|
                            <td><?php echo esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($request->created_at))); ?></td>
 | 
						|
                            <td>
 | 
						|
                                <form method="post" action="<?php echo admin_url('admin-post.php'); ?>" style="display: inline;">
 | 
						|
                                    <input type="hidden" name="action" value="wpdd_process_payout_request">
 | 
						|
                                    <input type="hidden" name="payout_id" value="<?php echo esc_attr($request->id); ?>">
 | 
						|
                                    <?php wp_nonce_field('wpdd_process_payout_request_' . $request->id, 'wpdd_nonce'); ?>
 | 
						|
                                    <button type="submit" class="button button-primary">
 | 
						|
                                        <?php _e('Process Now', 'wp-digital-download'); ?>
 | 
						|
                                    </button>
 | 
						|
                                </form>
 | 
						|
                                <form method="post" action="<?php echo admin_url('admin-post.php'); ?>" style="display: inline; margin-left: 5px;">
 | 
						|
                                    <input type="hidden" name="action" value="wpdd_reject_payout_request">
 | 
						|
                                    <input type="hidden" name="payout_id" value="<?php echo esc_attr($request->id); ?>">
 | 
						|
                                    <?php wp_nonce_field('wpdd_reject_payout_request_' . $request->id, 'wpdd_nonce'); ?>
 | 
						|
                                    <button type="submit" class="button button-secondary" onclick="return confirm('<?php _e('Are you sure you want to reject this payout request?', 'wp-digital-download'); ?>')">
 | 
						|
                                        <?php _e('Reject', 'wp-digital-download'); ?>
 | 
						|
                                    </button>
 | 
						|
                                </form>
 | 
						|
                            </td>
 | 
						|
                        </tr>
 | 
						|
                        <?php endforeach; ?>
 | 
						|
                    </tbody>
 | 
						|
                </table>
 | 
						|
            </div>
 | 
						|
            <?php endif; ?>
 | 
						|
            
 | 
						|
            <!-- Manual Actions Section -->
 | 
						|
            <div class="wpdd-manual-actions" style="display: flex; gap: 20px; margin: 20px 0;">
 | 
						|
                <!-- Manual Payout Form -->
 | 
						|
                <div style="background: white; border: 1px solid #ddd; border-radius: 4px; padding: 20px; flex: 1;">
 | 
						|
                    <h3 style="margin-top: 0;"><?php _e('Manual Payout', 'wp-digital-download'); ?></h3>
 | 
						|
                    <p><?php _e('Process a payout for off-site sales or manual adjustments.', 'wp-digital-download'); ?></p>
 | 
						|
                    
 | 
						|
                    <form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
 | 
						|
                        <input type="hidden" name="action" value="wpdd_manual_payout">
 | 
						|
                        <?php wp_nonce_field('wpdd_manual_payout', 'wpdd_nonce'); ?>
 | 
						|
                        
 | 
						|
                        <table class="form-table" style="margin: 0;">
 | 
						|
                            <tr>
 | 
						|
                                <th><label for="creator_id"><?php _e('Creator', 'wp-digital-download'); ?></label></th>
 | 
						|
                                <td>
 | 
						|
                                    <select name="creator_id" id="creator_id" class="wpdd-creator-select" required style="width: 100%;">
 | 
						|
                                        <option value=""><?php _e('Select Creator', 'wp-digital-download'); ?></option>
 | 
						|
                                        <?php 
 | 
						|
                                        $all_creators = get_users(array('role' => 'wpdd_creator'));
 | 
						|
                                        foreach ($all_creators as $creator) : 
 | 
						|
                                            $paypal_email = get_user_meta($creator->ID, 'wpdd_paypal_email', true);
 | 
						|
                                            $balance = WPDD_Creator::get_creator_balance($creator->ID);
 | 
						|
                                        ?>
 | 
						|
                                        <option value="<?php echo esc_attr($creator->ID); ?>" 
 | 
						|
                                                data-balance="<?php echo esc_attr($balance); ?>" 
 | 
						|
                                                data-paypal="<?php echo esc_attr($paypal_email); ?>"
 | 
						|
                                                <?php echo empty($paypal_email) ? 'disabled' : ''; ?>>
 | 
						|
                                            <?php echo esc_html($creator->display_name); ?>
 | 
						|
                                            <?php echo empty($paypal_email) ? ' (' . __('No PayPal email', 'wp-digital-download') . ')' : ' (' . esc_html($paypal_email) . ')'; ?>
 | 
						|
                                        </option>
 | 
						|
                                        <?php endforeach; ?>
 | 
						|
                                    </select>
 | 
						|
                                    <div id="creator_balance_display" style="margin-top: 10px; display: none;">
 | 
						|
                                        <strong><?php _e('Current Balance:', 'wp-digital-download'); ?></strong> <span id="creator_balance_amount"></span>
 | 
						|
                                    </div>
 | 
						|
                                </td>
 | 
						|
                            </tr>
 | 
						|
                            <tr>
 | 
						|
                                <th><label for="payout_amount"><?php _e('Amount', 'wp-digital-download'); ?></label></th>
 | 
						|
                                <td>
 | 
						|
                                    <input type="number" name="payout_amount" id="payout_amount" step="0.01" min="0.01" required style="width: 150px;">
 | 
						|
                                    <span><?php echo esc_html($currency); ?></span>
 | 
						|
                                </td>
 | 
						|
                            </tr>
 | 
						|
                            <tr>
 | 
						|
                                <th><label for="payout_reason"><?php _e('Reason/Note', 'wp-digital-download'); ?></label></th>
 | 
						|
                                <td>
 | 
						|
                                    <textarea name="payout_reason" id="payout_reason" rows="3" style="width: 100%;" placeholder="<?php _e('e.g., Off-site sale, manual adjustment, etc.', 'wp-digital-download'); ?>"></textarea>
 | 
						|
                                </td>
 | 
						|
                            </tr>
 | 
						|
                        </table>
 | 
						|
                        
 | 
						|
                        <p class="submit" style="margin: 15px 0 0 0;">
 | 
						|
                            <button type="submit" class="button button-primary">
 | 
						|
                                <?php _e('Process Manual Payout', 'wp-digital-download'); ?>
 | 
						|
                            </button>
 | 
						|
                        </p>
 | 
						|
                    </form>
 | 
						|
                </div>
 | 
						|
                
 | 
						|
                <!-- Balance Adjustment Form -->
 | 
						|
                <div style="background: white; border: 1px solid #ddd; border-radius: 4px; padding: 20px; flex: 1;">
 | 
						|
                    <h3 style="margin-top: 0;"><?php _e('Adjust Creator Balance', 'wp-digital-download'); ?></h3>
 | 
						|
                    <p><?php _e('Add or subtract funds from a creator\'s balance.', 'wp-digital-download'); ?></p>
 | 
						|
                    
 | 
						|
                    <form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
 | 
						|
                        <input type="hidden" name="action" value="wpdd_adjust_balance">
 | 
						|
                        <?php wp_nonce_field('wpdd_adjust_balance', 'wpdd_nonce'); ?>
 | 
						|
                        
 | 
						|
                        <table class="form-table" style="margin: 0;">
 | 
						|
                            <tr>
 | 
						|
                                <th><label for="adj_creator_id"><?php _e('Creator', 'wp-digital-download'); ?></label></th>
 | 
						|
                                <td>
 | 
						|
                                    <select name="creator_id" id="adj_creator_id" class="wpdd-creator-select" required style="width: 100%;">
 | 
						|
                                        <option value=""><?php _e('Select Creator', 'wp-digital-download'); ?></option>
 | 
						|
                                        <?php foreach ($all_creators as $creator) : 
 | 
						|
                                            $balance = WPDD_Creator::get_creator_balance($creator->ID);
 | 
						|
                                        ?>
 | 
						|
                                        <option value="<?php echo esc_attr($creator->ID); ?>" data-balance="<?php echo esc_attr($balance); ?>">
 | 
						|
                                            <?php echo esc_html($creator->display_name); ?>
 | 
						|
                                        </option>
 | 
						|
                                        <?php endforeach; ?>
 | 
						|
                                    </select>
 | 
						|
                                    <div id="adj_creator_balance_display" style="margin-top: 10px; display: none;">
 | 
						|
                                        <strong><?php _e('Current Balance:', 'wp-digital-download'); ?></strong> <span id="adj_creator_balance_amount"></span>
 | 
						|
                                    </div>
 | 
						|
                                </td>
 | 
						|
                            </tr>
 | 
						|
                            <tr>
 | 
						|
                                <th><label for="adjustment_type"><?php _e('Type', 'wp-digital-download'); ?></label></th>
 | 
						|
                                <td>
 | 
						|
                                    <select name="adjustment_type" id="adjustment_type" required>
 | 
						|
                                        <option value="add"><?php _e('Add Funds', 'wp-digital-download'); ?></option>
 | 
						|
                                        <option value="subtract"><?php _e('Subtract Funds', 'wp-digital-download'); ?></option>
 | 
						|
                                    </select>
 | 
						|
                                </td>
 | 
						|
                            </tr>
 | 
						|
                            <tr>
 | 
						|
                                <th><label for="adjustment_amount"><?php _e('Amount', 'wp-digital-download'); ?></label></th>
 | 
						|
                                <td>
 | 
						|
                                    <input type="number" name="adjustment_amount" id="adjustment_amount" step="0.01" min="0.01" required style="width: 150px;">
 | 
						|
                                    <span><?php echo esc_html($currency); ?></span>
 | 
						|
                                </td>
 | 
						|
                            </tr>
 | 
						|
                            <tr>
 | 
						|
                                <th><label for="adjustment_reason"><?php _e('Reason/Note', 'wp-digital-download'); ?></label></th>
 | 
						|
                                <td>
 | 
						|
                                    <textarea name="adjustment_reason" id="adjustment_reason" rows="3" style="width: 100%;" placeholder="<?php _e('e.g., Manual adjustment, refund, bonus, etc.', 'wp-digital-download'); ?>" required></textarea>
 | 
						|
                                </td>
 | 
						|
                            </tr>
 | 
						|
                        </table>
 | 
						|
                        
 | 
						|
                        <p class="submit" style="margin: 15px 0 0 0;">
 | 
						|
                            <button type="submit" class="button button-secondary">
 | 
						|
                                <?php _e('Adjust Balance', 'wp-digital-download'); ?>
 | 
						|
                            </button>
 | 
						|
                        </p>
 | 
						|
                    </form>
 | 
						|
                </div>
 | 
						|
            </div>
 | 
						|
            
 | 
						|
            <div class="wpdd-payout-stats">
 | 
						|
                <h2><?php _e('Pending Payouts', 'wp-digital-download'); ?></h2>
 | 
						|
                
 | 
						|
                <?php if (!empty($creators)) : ?>
 | 
						|
                <form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
 | 
						|
                    <input type="hidden" name="action" value="wpdd_bulk_payouts">
 | 
						|
                    <?php wp_nonce_field('wpdd_bulk_payouts', 'wpdd_nonce'); ?>
 | 
						|
                    
 | 
						|
                    <table class="wp-list-table widefat fixed striped">
 | 
						|
                        <thead>
 | 
						|
                            <tr>
 | 
						|
                                <th class="check-column">
 | 
						|
                                    <input type="checkbox" id="select-all-creators">
 | 
						|
                                </th>
 | 
						|
                                <th><?php _e('Creator', 'wp-digital-download'); ?></th>
 | 
						|
                                <th><?php _e('PayPal Email', 'wp-digital-download'); ?></th>
 | 
						|
                                <th><?php _e('Current Balance', 'wp-digital-download'); ?></th>
 | 
						|
                                <th><?php _e('Total Sales', 'wp-digital-download'); ?></th>
 | 
						|
                                <th><?php _e('Net Earnings', 'wp-digital-download'); ?></th>
 | 
						|
                                <th><?php _e('Actions', 'wp-digital-download'); ?></th>
 | 
						|
                            </tr>
 | 
						|
                        </thead>
 | 
						|
                        <tbody>
 | 
						|
                            <?php foreach ($creators as $creator) : 
 | 
						|
                                $total_earnings = WPDD_Creator::get_creator_total_earnings($creator->ID);
 | 
						|
                                $net_earnings = WPDD_Creator::get_creator_net_earnings($creator->ID);
 | 
						|
                                $can_payout = !empty($creator->paypal_email) && floatval($creator->balance) > 0;
 | 
						|
                                $auto_eligible = $threshold > 0 && floatval($creator->balance) >= $threshold;
 | 
						|
                            ?>
 | 
						|
                            <tr <?php echo $auto_eligible ? 'style="background-color: #d4edda;"' : ''; ?>>
 | 
						|
                                <td>
 | 
						|
                                    <?php if ($can_payout) : ?>
 | 
						|
                                    <input type="checkbox" name="creator_ids[]" value="<?php echo esc_attr($creator->ID); ?>">
 | 
						|
                                    <?php endif; ?>
 | 
						|
                                </td>
 | 
						|
                                <td>
 | 
						|
                                    <strong><?php echo esc_html($creator->display_name); ?></strong><br>
 | 
						|
                                    <small><?php echo esc_html($creator->user_email); ?></small>
 | 
						|
                                </td>
 | 
						|
                                <td>
 | 
						|
                                    <?php if (!empty($creator->paypal_email)) : ?>
 | 
						|
                                        <?php echo esc_html($creator->paypal_email); ?>
 | 
						|
                                    <?php else : ?>
 | 
						|
                                        <span style="color: #dc3545;"><?php _e('Not set', 'wp-digital-download'); ?></span>
 | 
						|
                                    <?php endif; ?>
 | 
						|
                                </td>
 | 
						|
                                <td>
 | 
						|
                                    <strong><?php echo wpdd_format_price($creator->balance, $currency); ?></strong>
 | 
						|
                                    <?php if ($auto_eligible) : ?>
 | 
						|
                                        <br><span class="dashicons dashicons-yes" style="color: #28a745;"></span>
 | 
						|
                                        <small><?php _e('Auto-payout eligible', 'wp-digital-download'); ?></small>
 | 
						|
                                    <?php endif; ?>
 | 
						|
                                </td>
 | 
						|
                                <td><?php echo wpdd_format_price($total_earnings, $currency); ?></td>
 | 
						|
                                <td><?php echo wpdd_format_price($net_earnings, $currency); ?></td>
 | 
						|
                                <td>
 | 
						|
                                    <?php if ($can_payout) : ?>
 | 
						|
                                    <form method="post" action="<?php echo admin_url('admin-post.php'); ?>" style="display: inline;">
 | 
						|
                                        <input type="hidden" name="action" value="wpdd_process_payout">
 | 
						|
                                        <input type="hidden" name="creator_id" value="<?php echo esc_attr($creator->ID); ?>">
 | 
						|
                                        <?php wp_nonce_field('wpdd_process_payout_' . $creator->ID, 'wpdd_nonce'); ?>
 | 
						|
                                        <button type="submit" class="button button-primary wpdd-payout-btn">
 | 
						|
                                            <?php _e('Process Payout', 'wp-digital-download'); ?>
 | 
						|
                                        </button>
 | 
						|
                                    </form>
 | 
						|
                                    <?php else : ?>
 | 
						|
                                        <button class="button" disabled><?php _e('Cannot Process', 'wp-digital-download'); ?></button>
 | 
						|
                                    <?php endif; ?>
 | 
						|
                                </td>
 | 
						|
                            </tr>
 | 
						|
                            <?php endforeach; ?>
 | 
						|
                        </tbody>
 | 
						|
                    </table>
 | 
						|
                    
 | 
						|
                    <div class="tablenav bottom">
 | 
						|
                        <div class="alignleft actions">
 | 
						|
                            <button type="submit" class="button button-primary" name="bulk_action" value="process">
 | 
						|
                                <?php _e('Process Selected Payouts', 'wp-digital-download'); ?>
 | 
						|
                            </button>
 | 
						|
                            <?php if ($threshold > 0) : ?>
 | 
						|
                            <button type="submit" class="button" name="bulk_action" value="auto">
 | 
						|
                                <?php printf(__('Process All Above %s', 'wp-digital-download'), wpdd_format_price($threshold, $currency)); ?>
 | 
						|
                            </button>
 | 
						|
                            <?php endif; ?>
 | 
						|
                        </div>
 | 
						|
                    </div>
 | 
						|
                </form>
 | 
						|
                <?php else : ?>
 | 
						|
                    <p><?php _e('No creators with pending payouts.', 'wp-digital-download'); ?></p>
 | 
						|
                <?php endif; ?>
 | 
						|
            </div>
 | 
						|
            
 | 
						|
            <div class="wpdd-payout-history">
 | 
						|
                <h2><?php _e('Payout History', 'wp-digital-download'); ?></h2>
 | 
						|
                
 | 
						|
                <div class="tablenav top">
 | 
						|
                    <div class="alignleft actions">
 | 
						|
                        <select name="status_filter" onchange="window.location.href='<?php echo admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts'); ?>&status=' + this.value">
 | 
						|
                            <option value="all" <?php selected($status_filter, 'all'); ?>><?php _e('All Statuses', 'wp-digital-download'); ?></option>
 | 
						|
                            <option value="pending" <?php selected($status_filter, 'pending'); ?>><?php _e('Pending', 'wp-digital-download'); ?></option>
 | 
						|
                            <option value="completed" <?php selected($status_filter, 'completed'); ?>><?php _e('Completed', 'wp-digital-download'); ?></option>
 | 
						|
                            <option value="failed" <?php selected($status_filter, 'failed'); ?>><?php _e('Failed', 'wp-digital-download'); ?></option>
 | 
						|
                        </select>
 | 
						|
                    </div>
 | 
						|
                </div>
 | 
						|
                
 | 
						|
                <?php if (!empty($payouts)) : ?>
 | 
						|
                <table class="wp-list-table widefat fixed striped">
 | 
						|
                    <thead>
 | 
						|
                        <tr>
 | 
						|
                            <th><?php _e('Date', 'wp-digital-download'); ?></th>
 | 
						|
                            <th><?php _e('Creator', 'wp-digital-download'); ?></th>
 | 
						|
                            <th><?php _e('Amount', 'wp-digital-download'); ?></th>
 | 
						|
                            <th><?php _e('PayPal Email', 'wp-digital-download'); ?></th>
 | 
						|
                            <th><?php _e('Transaction ID', 'wp-digital-download'); ?></th>
 | 
						|
                            <th><?php _e('Status', 'wp-digital-download'); ?></th>
 | 
						|
                            <th><?php _e('Method', 'wp-digital-download'); ?></th>
 | 
						|
                            <th><?php _e('Processed By', 'wp-digital-download'); ?></th>
 | 
						|
                        </tr>
 | 
						|
                    </thead>
 | 
						|
                    <tbody>
 | 
						|
                        <?php foreach ($payouts as $payout) : 
 | 
						|
                            $processor = $payout->processed_by ? get_userdata($payout->processed_by) : null;
 | 
						|
                        ?>
 | 
						|
                        <tr>
 | 
						|
                            <td>
 | 
						|
                                <?php echo esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($payout->created_at))); ?>
 | 
						|
                                <?php if ($payout->processed_at) : ?>
 | 
						|
                                    <br><small><?php _e('Processed:', 'wp-digital-download'); ?> <?php echo esc_html(date_i18n(get_option('date_format'), strtotime($payout->processed_at))); ?></small>
 | 
						|
                                <?php endif; ?>
 | 
						|
                            </td>
 | 
						|
                            <td>
 | 
						|
                                <strong><?php echo esc_html($payout->display_name); ?></strong><br>
 | 
						|
                                <small><?php echo esc_html($payout->user_email); ?></small>
 | 
						|
                            </td>
 | 
						|
                            <td><strong><?php echo wpdd_format_price($payout->amount, $payout->currency); ?></strong></td>
 | 
						|
                            <td><?php echo esc_html($payout->paypal_email); ?></td>
 | 
						|
                            <td>
 | 
						|
                                <?php echo esc_html($payout->transaction_id ?: '-'); ?>
 | 
						|
                                <?php if ($payout->notes) : ?>
 | 
						|
                                    <br><small><?php echo esc_html($payout->notes); ?></small>
 | 
						|
                                <?php endif; ?>
 | 
						|
                            </td>
 | 
						|
                            <td>
 | 
						|
                                <?php 
 | 
						|
                                $status_class = '';
 | 
						|
                                switch($payout->status) {
 | 
						|
                                    case 'completed':
 | 
						|
                                        $status_class = 'notice-success';
 | 
						|
                                        break;
 | 
						|
                                    case 'failed':
 | 
						|
                                        $status_class = 'notice-error';
 | 
						|
                                        break;
 | 
						|
                                    case 'pending':
 | 
						|
                                        $status_class = 'notice-warning';
 | 
						|
                                        break;
 | 
						|
                                }
 | 
						|
                                ?>
 | 
						|
                                <span class="notice <?php echo esc_attr($status_class); ?>" style="padding: 2px 8px; display: inline-block;">
 | 
						|
                                    <?php echo esc_html(ucfirst($payout->status)); ?>
 | 
						|
                                </span>
 | 
						|
                            </td>
 | 
						|
                            <td><?php echo esc_html(ucfirst($payout->payout_method)); ?></td>
 | 
						|
                            <td>
 | 
						|
                                <?php if ($processor) : ?>
 | 
						|
                                    <?php echo esc_html($processor->display_name); ?>
 | 
						|
                                <?php else : ?>
 | 
						|
                                    <?php echo $payout->payout_method === 'automatic' ? __('System', 'wp-digital-download') : '-'; ?>
 | 
						|
                                <?php endif; ?>
 | 
						|
                            </td>
 | 
						|
                        </tr>
 | 
						|
                        <?php endforeach; ?>
 | 
						|
                    </tbody>
 | 
						|
                </table>
 | 
						|
                <?php else : ?>
 | 
						|
                    <p><?php _e('No payout history found.', 'wp-digital-download'); ?></p>
 | 
						|
                <?php endif; ?>
 | 
						|
            </div>
 | 
						|
            
 | 
						|
            <style>
 | 
						|
                .wpdd-payout-stats,
 | 
						|
                .wpdd-payout-history {
 | 
						|
                    margin-top: 30px;
 | 
						|
                    background: #fff;
 | 
						|
                    padding: 20px;
 | 
						|
                    border: 1px solid #ccd0d4;
 | 
						|
                    box-shadow: 0 1px 1px rgba(0,0,0,.04);
 | 
						|
                }
 | 
						|
                .wpdd-payout-btn:hover {
 | 
						|
                    cursor: pointer;
 | 
						|
                }
 | 
						|
                #select-all-creators {
 | 
						|
                    margin: 0;
 | 
						|
                }
 | 
						|
            </style>
 | 
						|
            
 | 
						|
            <script>
 | 
						|
                jQuery(document).ready(function($) {
 | 
						|
                    $('#select-all-creators').on('change', function() {
 | 
						|
                        $('input[name="creator_ids[]"]').prop('checked', this.checked);
 | 
						|
                    });
 | 
						|
                    
 | 
						|
                    $('.wpdd-payout-btn').on('click', function(e) {
 | 
						|
                        if (!confirm(wpdd_payouts.confirm_payout)) {
 | 
						|
                            e.preventDefault();
 | 
						|
                        }
 | 
						|
                    });
 | 
						|
                    
 | 
						|
                    $('button[name="bulk_action"]').on('click', function(e) {
 | 
						|
                        var checkedCount = $('input[name="creator_ids[]"]:checked').length;
 | 
						|
                        if (checkedCount === 0) {
 | 
						|
                            alert('Please select at least one creator for payout.');
 | 
						|
                            e.preventDefault();
 | 
						|
                        } else if (!confirm(wpdd_payouts.confirm_bulk)) {
 | 
						|
                            e.preventDefault();
 | 
						|
                        }
 | 
						|
                    });
 | 
						|
                });
 | 
						|
            </script>
 | 
						|
        </div>
 | 
						|
        <?php
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function process_payout() {
 | 
						|
        if (!current_user_can('manage_options')) {
 | 
						|
            wp_die(__('You do not have permission to perform this action.', 'wp-digital-download'));
 | 
						|
        }
 | 
						|
        
 | 
						|
        $creator_id = isset($_POST['creator_id']) ? intval($_POST['creator_id']) : 0;
 | 
						|
        
 | 
						|
        if (!$creator_id || !wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_process_payout_' . $creator_id)) {
 | 
						|
            wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error'));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        $result = self::create_payout($creator_id);
 | 
						|
        
 | 
						|
        if ($result['success']) {
 | 
						|
            wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=success'));
 | 
						|
        } else {
 | 
						|
            $error_message = urlencode($result['error'] ?? 'Unknown error occurred');
 | 
						|
            wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error&error_detail=' . $error_message));
 | 
						|
        }
 | 
						|
        exit;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function process_bulk_payouts() {
 | 
						|
        if (!current_user_can('manage_options')) {
 | 
						|
            wp_die(__('You do not have permission to perform this action.', 'wp-digital-download'));
 | 
						|
        }
 | 
						|
        
 | 
						|
        if (!wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_bulk_payouts')) {
 | 
						|
            wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error'));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        $bulk_action = isset($_POST['bulk_action']) ? sanitize_text_field($_POST['bulk_action']) : '';
 | 
						|
        
 | 
						|
        if ($bulk_action === 'auto') {
 | 
						|
            // Process all creators above threshold
 | 
						|
            $threshold = floatval(get_option('wpdd_payout_threshold', 0));
 | 
						|
            if ($threshold > 0) {
 | 
						|
                $creators = WPDD_Creator::get_creators_with_balance();
 | 
						|
                foreach ($creators as $creator) {
 | 
						|
                    if (floatval($creator->balance) >= $threshold && !empty($creator->paypal_email)) {
 | 
						|
                        self::create_payout($creator->ID);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            // Process selected creators
 | 
						|
            $creator_ids = isset($_POST['creator_ids']) ? array_map('intval', $_POST['creator_ids']) : array();
 | 
						|
            foreach ($creator_ids as $creator_id) {
 | 
						|
                self::create_payout($creator_id);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=success'));
 | 
						|
        exit;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function create_payout($creator_id, $method = 'manual') {
 | 
						|
        global $wpdb;
 | 
						|
        
 | 
						|
        // Validate creator
 | 
						|
        $creator = get_userdata($creator_id);
 | 
						|
        if (!$creator) {
 | 
						|
            return array('success' => false, 'error' => 'Creator not found');
 | 
						|
        }
 | 
						|
        
 | 
						|
        $balance = WPDD_Creator::get_creator_balance($creator_id);
 | 
						|
        $paypal_email = get_user_meta($creator_id, 'wpdd_paypal_email', true);
 | 
						|
        
 | 
						|
        if ($balance <= 0) {
 | 
						|
            return array('success' => false, 'error' => 'Creator has zero balance to payout');
 | 
						|
        }
 | 
						|
        
 | 
						|
        if (empty($paypal_email)) {
 | 
						|
            return array('success' => false, 'error' => 'Creator has no PayPal email configured');
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Validate PayPal credentials are configured
 | 
						|
        $client_id = get_option('wpdd_paypal_client_id');
 | 
						|
        $secret = get_option('wpdd_paypal_secret');
 | 
						|
        if (empty($client_id) || empty($secret)) {
 | 
						|
            return array('success' => false, 'error' => 'PayPal credentials not configured in settings');
 | 
						|
        }
 | 
						|
        
 | 
						|
        $currency = get_option('wpdd_currency', 'USD');
 | 
						|
        $current_user_id = get_current_user_id();
 | 
						|
        
 | 
						|
        // Create payout record
 | 
						|
        $wpdb->insert(
 | 
						|
            $wpdb->prefix . 'wpdd_payouts',
 | 
						|
            array(
 | 
						|
                'creator_id' => $creator_id,
 | 
						|
                'amount' => $balance,
 | 
						|
                'currency' => $currency,
 | 
						|
                'paypal_email' => $paypal_email,
 | 
						|
                'status' => 'pending',
 | 
						|
                'payout_method' => $method,
 | 
						|
                'processed_by' => $current_user_id,
 | 
						|
                'created_at' => current_time('mysql')
 | 
						|
            ),
 | 
						|
            array('%d', '%f', '%s', '%s', '%s', '%s', '%d', '%s')
 | 
						|
        );
 | 
						|
        
 | 
						|
        $payout_id = $wpdb->insert_id;
 | 
						|
        
 | 
						|
        if (!$payout_id) {
 | 
						|
            return array('success' => false, 'error' => 'Failed to create payout record in database');
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Try to process via PayPal API
 | 
						|
        $result = WPDD_PayPal_Payouts::process_payout($payout_id);
 | 
						|
        
 | 
						|
        if ($result['success']) {
 | 
						|
            // Update payout status
 | 
						|
            $wpdb->update(
 | 
						|
                $wpdb->prefix . 'wpdd_payouts',
 | 
						|
                array(
 | 
						|
                    'status' => 'completed',
 | 
						|
                    'transaction_id' => $result['transaction_id'],
 | 
						|
                    'processed_at' => current_time('mysql')
 | 
						|
                ),
 | 
						|
                array('id' => $payout_id),
 | 
						|
                array('%s', '%s', '%s'),
 | 
						|
                array('%d')
 | 
						|
            );
 | 
						|
            
 | 
						|
            // Mark all available earnings for this creator as paid
 | 
						|
            $wpdb->update(
 | 
						|
                $wpdb->prefix . 'wpdd_creator_earnings',
 | 
						|
                array(
 | 
						|
                    'payout_id' => $payout_id,
 | 
						|
                    'payout_status' => 'paid'
 | 
						|
                ),
 | 
						|
                array(
 | 
						|
                    'creator_id' => $creator_id,
 | 
						|
                    'payout_status' => 'available'
 | 
						|
                ),
 | 
						|
                array('%d', '%s'),
 | 
						|
                array('%d', '%s')
 | 
						|
            );
 | 
						|
            
 | 
						|
            // Reset creator balance
 | 
						|
            update_user_meta($creator_id, 'wpdd_creator_balance', 0);
 | 
						|
            
 | 
						|
            return array('success' => true, 'message' => 'Payout processed successfully');
 | 
						|
        } else {
 | 
						|
            // Update with error
 | 
						|
            $wpdb->update(
 | 
						|
                $wpdb->prefix . 'wpdd_payouts',
 | 
						|
                array(
 | 
						|
                    'status' => 'failed',
 | 
						|
                    'notes' => $result['error']
 | 
						|
                ),
 | 
						|
                array('id' => $payout_id),
 | 
						|
                array('%s', '%s'),
 | 
						|
                array('%d')
 | 
						|
            );
 | 
						|
            
 | 
						|
            return array('success' => false, 'error' => $result['error'] ?? 'PayPal payout processing failed');
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function process_payout_request() {
 | 
						|
        if (!current_user_can('manage_options')) {
 | 
						|
            wp_die(__('You do not have permission to perform this action.', 'wp-digital-download'));
 | 
						|
        }
 | 
						|
        
 | 
						|
        $payout_id = isset($_POST['payout_id']) ? intval($_POST['payout_id']) : 0;
 | 
						|
        
 | 
						|
        if (!$payout_id || !wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_process_payout_request_' . $payout_id)) {
 | 
						|
            wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error'));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        global $wpdb;
 | 
						|
        
 | 
						|
        // Get the payout request
 | 
						|
        $payout = $wpdb->get_row($wpdb->prepare(
 | 
						|
            "SELECT * FROM {$wpdb->prefix}wpdd_payouts WHERE id = %d AND status = 'requested'",
 | 
						|
            $payout_id
 | 
						|
        ));
 | 
						|
        
 | 
						|
        if (!$payout) {
 | 
						|
            wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error'));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Process via PayPal API
 | 
						|
        $result = WPDD_PayPal_Payouts::process_payout($payout_id);
 | 
						|
        
 | 
						|
        if ($result['success']) {
 | 
						|
            // Update payout status
 | 
						|
            $wpdb->update(
 | 
						|
                $wpdb->prefix . 'wpdd_payouts',
 | 
						|
                array(
 | 
						|
                    'status' => 'completed',
 | 
						|
                    'transaction_id' => $result['transaction_id'],
 | 
						|
                    'processed_by' => get_current_user_id(),
 | 
						|
                    'processed_at' => current_time('mysql')
 | 
						|
                ),
 | 
						|
                array('id' => $payout_id),
 | 
						|
                array('%s', '%s', '%d', '%s'),
 | 
						|
                array('%d')
 | 
						|
            );
 | 
						|
            
 | 
						|
            wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=success'));
 | 
						|
        } else {
 | 
						|
            // Update with error
 | 
						|
            $wpdb->update(
 | 
						|
                $wpdb->prefix . 'wpdd_payouts',
 | 
						|
                array(
 | 
						|
                    'status' => 'failed',
 | 
						|
                    'notes' => $result['error']
 | 
						|
                ),
 | 
						|
                array('id' => $payout_id),
 | 
						|
                array('%s', '%s'),
 | 
						|
                array('%d')
 | 
						|
            );
 | 
						|
            
 | 
						|
            wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error'));
 | 
						|
        }
 | 
						|
        exit;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function reject_payout_request() {
 | 
						|
        if (!current_user_can('manage_options')) {
 | 
						|
            wp_die(__('You do not have permission to perform this action.', 'wp-digital-download'));
 | 
						|
        }
 | 
						|
        
 | 
						|
        $payout_id = isset($_POST['payout_id']) ? intval($_POST['payout_id']) : 0;
 | 
						|
        
 | 
						|
        if (!$payout_id || !wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_reject_payout_request_' . $payout_id)) {
 | 
						|
            wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error'));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        global $wpdb;
 | 
						|
        
 | 
						|
        // Get the payout request
 | 
						|
        $payout = $wpdb->get_row($wpdb->prepare(
 | 
						|
            "SELECT * FROM {$wpdb->prefix}wpdd_payouts WHERE id = %d AND status = 'requested'",
 | 
						|
            $payout_id
 | 
						|
        ));
 | 
						|
        
 | 
						|
        if (!$payout) {
 | 
						|
            wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error'));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Update status to failed/rejected
 | 
						|
        $wpdb->update(
 | 
						|
            $wpdb->prefix . 'wpdd_payouts',
 | 
						|
            array(
 | 
						|
                'status' => 'failed',
 | 
						|
                'notes' => 'Request rejected by administrator',
 | 
						|
                'processed_by' => get_current_user_id(),
 | 
						|
                'processed_at' => current_time('mysql')
 | 
						|
            ),
 | 
						|
            array('id' => $payout_id),
 | 
						|
            array('%s', '%s', '%d', '%s'),
 | 
						|
            array('%d')
 | 
						|
        );
 | 
						|
        
 | 
						|
        // Restore balance to creator
 | 
						|
        update_user_meta($payout->creator_id, 'wpdd_creator_balance', $payout->amount);
 | 
						|
        
 | 
						|
        wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=success'));
 | 
						|
        exit;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function process_manual_payout() {
 | 
						|
        if (!current_user_can('manage_options') || 
 | 
						|
            !wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_manual_payout')) {
 | 
						|
            wp_die(__('Security check failed', 'wp-digital-download'));
 | 
						|
        }
 | 
						|
        
 | 
						|
        $creator_id = intval($_POST['creator_id']);
 | 
						|
        $amount = floatval($_POST['payout_amount']);
 | 
						|
        $reason = sanitize_textarea_field($_POST['payout_reason']);
 | 
						|
        
 | 
						|
        if (!$creator_id || $amount <= 0) {
 | 
						|
            wp_redirect(add_query_arg('message', 'error', wp_get_referer()));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        $creator = get_userdata($creator_id);
 | 
						|
        if (!$creator || !in_array('wpdd_creator', $creator->roles)) {
 | 
						|
            wp_redirect(add_query_arg('message', 'error', wp_get_referer()));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        $paypal_email = get_user_meta($creator_id, 'wpdd_paypal_email', true);
 | 
						|
        if (empty($paypal_email)) {
 | 
						|
            wp_redirect(add_query_arg('message', 'error', wp_get_referer()));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        global $wpdb;
 | 
						|
        
 | 
						|
        // Create the payout record
 | 
						|
        $result = $wpdb->insert(
 | 
						|
            $wpdb->prefix . 'wpdd_payouts',
 | 
						|
            array(
 | 
						|
                'creator_id' => $creator_id,
 | 
						|
                'amount' => $amount,
 | 
						|
                'currency' => get_option('wpdd_currency', 'USD'),
 | 
						|
                'paypal_email' => $paypal_email,
 | 
						|
                'status' => 'pending',
 | 
						|
                'payout_method' => 'manual',
 | 
						|
                'notes' => $reason,
 | 
						|
                'created_at' => current_time('mysql'),
 | 
						|
                'processed_by' => get_current_user_id()
 | 
						|
            ),
 | 
						|
            array('%d', '%f', '%s', '%s', '%s', '%s', '%s', '%s', '%d')
 | 
						|
        );
 | 
						|
        
 | 
						|
        if (!$result) {
 | 
						|
            wp_redirect(add_query_arg('message', 'error', wp_get_referer()));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        $payout_id = $wpdb->insert_id;
 | 
						|
        
 | 
						|
        // Try to process via PayPal
 | 
						|
        if (class_exists('WPDD_PayPal_Payouts')) {
 | 
						|
            $paypal_result = WPDD_PayPal_Payouts::process_payout($payout_id);
 | 
						|
            
 | 
						|
            if (!$paypal_result) {
 | 
						|
                // Update status to failed
 | 
						|
                $wpdb->update(
 | 
						|
                    $wpdb->prefix . 'wpdd_payouts',
 | 
						|
                    array('status' => 'failed'),
 | 
						|
                    array('id' => $payout_id),
 | 
						|
                    array('%s'),
 | 
						|
                    array('%d')
 | 
						|
                );
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        wp_redirect(add_query_arg('message', 'success', wp_get_referer()));
 | 
						|
        exit;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static function adjust_creator_balance() {
 | 
						|
        if (!current_user_can('manage_options') || 
 | 
						|
            !wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_adjust_balance')) {
 | 
						|
            wp_die(__('Security check failed', 'wp-digital-download'));
 | 
						|
        }
 | 
						|
        
 | 
						|
        $creator_id = intval($_POST['creator_id']);
 | 
						|
        $adjustment_type = sanitize_text_field($_POST['adjustment_type']);
 | 
						|
        $amount = floatval($_POST['adjustment_amount']);
 | 
						|
        $reason = sanitize_textarea_field($_POST['adjustment_reason']);
 | 
						|
        
 | 
						|
        if (!$creator_id || $amount <= 0 || !in_array($adjustment_type, array('add', 'subtract'))) {
 | 
						|
            wp_redirect(add_query_arg('message', 'error', wp_get_referer()));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        $creator = get_userdata($creator_id);
 | 
						|
        if (!$creator || !in_array('wpdd_creator', $creator->roles)) {
 | 
						|
            wp_redirect(add_query_arg('message', 'error', wp_get_referer()));
 | 
						|
            exit;
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Get current balance
 | 
						|
        $current_balance = floatval(get_user_meta($creator_id, 'wpdd_creator_balance', true));
 | 
						|
        
 | 
						|
        // Calculate new balance
 | 
						|
        if ($adjustment_type === 'add') {
 | 
						|
            $new_balance = $current_balance + $amount;
 | 
						|
        } else {
 | 
						|
            $new_balance = max(0, $current_balance - $amount); // Don't allow negative balance
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Update the balance
 | 
						|
        update_user_meta($creator_id, 'wpdd_creator_balance', $new_balance);
 | 
						|
        
 | 
						|
        // Create a record of this adjustment
 | 
						|
        global $wpdb;
 | 
						|
        $wpdb->insert(
 | 
						|
            $wpdb->prefix . 'wpdd_balance_adjustments',
 | 
						|
            array(
 | 
						|
                'creator_id' => $creator_id,
 | 
						|
                'adjustment_type' => $adjustment_type,
 | 
						|
                'amount' => $amount,
 | 
						|
                'previous_balance' => $current_balance,
 | 
						|
                'new_balance' => $new_balance,
 | 
						|
                'reason' => $reason,
 | 
						|
                'adjusted_by' => get_current_user_id(),
 | 
						|
                'created_at' => current_time('mysql')
 | 
						|
            ),
 | 
						|
            array('%d', '%s', '%f', '%f', '%f', '%s', '%d', '%s')
 | 
						|
        );
 | 
						|
        
 | 
						|
        wp_redirect(add_query_arg('message', 'balance_adjusted', wp_get_referer()));
 | 
						|
        exit;
 | 
						|
    }
 | 
						|
}
 |