Some checks failed
Create Release / build (push) Failing after 3s
🔧 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>
189 lines
6.9 KiB
PHP
189 lines
6.9 KiB
PHP
<?php
|
|
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
class WPDD_Earnings_Processor {
|
|
|
|
public static function init() {
|
|
// Schedule the cron job
|
|
add_action('wp', array(__CLASS__, 'schedule_earnings_processing'));
|
|
add_action('wpdd_process_pending_earnings', array(__CLASS__, 'process_pending_earnings'));
|
|
|
|
// Hook to plugin activation/deactivation
|
|
register_activation_hook(WPDD_PLUGIN_PATH . 'wp-digital-download.php', array(__CLASS__, 'schedule_earnings_processing'));
|
|
register_deactivation_hook(WPDD_PLUGIN_PATH . 'wp-digital-download.php', array(__CLASS__, 'clear_scheduled_earnings_processing'));
|
|
}
|
|
|
|
public static function schedule_earnings_processing() {
|
|
if (!wp_next_scheduled('wpdd_process_pending_earnings')) {
|
|
// Run every hour to check for earnings that should be made available
|
|
wp_schedule_event(time(), 'hourly', 'wpdd_process_pending_earnings');
|
|
}
|
|
}
|
|
|
|
public static function clear_scheduled_earnings_processing() {
|
|
wp_clear_scheduled_hook('wpdd_process_pending_earnings');
|
|
}
|
|
|
|
public static function process_pending_earnings() {
|
|
global $wpdb;
|
|
|
|
// Find all earnings that are pending and past their available_at date
|
|
$pending_earnings = $wpdb->get_results(
|
|
"SELECT * FROM {$wpdb->prefix}wpdd_creator_earnings
|
|
WHERE payout_status = 'pending'
|
|
AND available_at <= NOW()
|
|
AND available_at IS NOT NULL"
|
|
);
|
|
|
|
if (empty($pending_earnings)) {
|
|
return; // Nothing to process
|
|
}
|
|
|
|
// Update all pending earnings to available
|
|
$updated = $wpdb->query(
|
|
"UPDATE {$wpdb->prefix}wpdd_creator_earnings
|
|
SET payout_status = 'available'
|
|
WHERE payout_status = 'pending'
|
|
AND available_at <= NOW()
|
|
AND available_at IS NOT NULL"
|
|
);
|
|
|
|
if ($updated > 0) {
|
|
// Log the processing
|
|
error_log("WPDD: Processed $updated pending earnings to available status");
|
|
|
|
// Update creator balances for affected creators
|
|
$affected_creators = $wpdb->get_col(
|
|
"SELECT DISTINCT creator_id
|
|
FROM {$wpdb->prefix}wpdd_creator_earnings
|
|
WHERE payout_status = 'available'
|
|
AND available_at <= NOW()"
|
|
);
|
|
|
|
foreach ($affected_creators as $creator_id) {
|
|
// Trigger balance recalculation
|
|
$current_balance = WPDD_Creator::get_creator_balance($creator_id);
|
|
update_user_meta($creator_id, 'wpdd_creator_balance', $current_balance);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Manually process a specific earning (for admin override)
|
|
*/
|
|
public static function release_earning_immediately($earning_id) {
|
|
global $wpdb;
|
|
|
|
$result = $wpdb->update(
|
|
$wpdb->prefix . 'wpdd_creator_earnings',
|
|
array(
|
|
'payout_status' => 'available',
|
|
'available_at' => current_time('mysql')
|
|
),
|
|
array(
|
|
'id' => $earning_id,
|
|
'payout_status' => 'pending'
|
|
),
|
|
array('%s', '%s'),
|
|
array('%d', '%s')
|
|
);
|
|
|
|
if ($result) {
|
|
// Get the creator and update their balance
|
|
$earning = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT creator_id FROM {$wpdb->prefix}wpdd_creator_earnings WHERE id = %d",
|
|
$earning_id
|
|
));
|
|
|
|
if ($earning) {
|
|
$current_balance = WPDD_Creator::get_creator_balance($earning->creator_id);
|
|
update_user_meta($earning->creator_id, 'wpdd_creator_balance', $current_balance);
|
|
}
|
|
}
|
|
|
|
return $result > 0;
|
|
}
|
|
|
|
/**
|
|
* Cancel/refund a specific earning (for order cancellations)
|
|
*/
|
|
public static function cancel_earning($earning_id, $reason = 'Order cancelled/refunded') {
|
|
global $wpdb;
|
|
|
|
// Get the earning details
|
|
$earning = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT * FROM {$wpdb->prefix}wpdd_creator_earnings WHERE id = %d",
|
|
$earning_id
|
|
));
|
|
|
|
if (!$earning) {
|
|
return false;
|
|
}
|
|
|
|
// Only cancel if not already paid out
|
|
if ($earning->payout_status === 'paid') {
|
|
return false; // Cannot cancel paid earnings
|
|
}
|
|
|
|
// Update to cancelled status
|
|
$result = $wpdb->update(
|
|
$wpdb->prefix . 'wpdd_creator_earnings',
|
|
array(
|
|
'payout_status' => 'cancelled',
|
|
'available_at' => null
|
|
),
|
|
array('id' => $earning_id),
|
|
array('%s', '%s'),
|
|
array('%d')
|
|
);
|
|
|
|
if ($result) {
|
|
// Log the cancellation
|
|
$wpdb->insert(
|
|
$wpdb->prefix . 'wpdd_balance_adjustments',
|
|
array(
|
|
'creator_id' => $earning->creator_id,
|
|
'adjustment_type' => 'subtract',
|
|
'amount' => $earning->creator_earning,
|
|
'previous_balance' => WPDD_Creator::get_creator_balance($earning->creator_id),
|
|
'new_balance' => WPDD_Creator::get_creator_balance($earning->creator_id) - $earning->creator_earning,
|
|
'reason' => $reason . ' (Order #' . $earning->order_id . ')',
|
|
'adjusted_by' => get_current_user_id(),
|
|
'created_at' => current_time('mysql')
|
|
),
|
|
array('%d', '%s', '%f', '%f', '%f', '%s', '%d', '%s')
|
|
);
|
|
|
|
// Update creator balance
|
|
$current_balance = WPDD_Creator::get_creator_balance($earning->creator_id);
|
|
update_user_meta($earning->creator_id, 'wpdd_creator_balance', $current_balance - $earning->creator_earning);
|
|
}
|
|
|
|
return $result > 0;
|
|
}
|
|
|
|
/**
|
|
* Get earnings summary for a creator
|
|
*/
|
|
public static function get_earnings_summary($creator_id) {
|
|
global $wpdb;
|
|
|
|
$summary = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT
|
|
COUNT(*) as total_earnings,
|
|
SUM(CASE WHEN payout_status = 'pending' THEN creator_earning ELSE 0 END) as pending_amount,
|
|
SUM(CASE WHEN payout_status = 'available' THEN creator_earning ELSE 0 END) as available_amount,
|
|
SUM(CASE WHEN payout_status = 'paid' THEN creator_earning ELSE 0 END) as paid_amount,
|
|
SUM(CASE WHEN payout_status = 'cancelled' THEN creator_earning ELSE 0 END) as cancelled_amount,
|
|
SUM(creator_earning) as total_amount
|
|
FROM {$wpdb->prefix}wpdd_creator_earnings
|
|
WHERE creator_id = %d",
|
|
$creator_id
|
|
));
|
|
|
|
return $summary;
|
|
}
|
|
} |