Adding more functionality

This commit is contained in:
2025-08-29 18:54:14 -07:00
parent 5aa0777fd3
commit 6d797ef686
17 changed files with 4237 additions and 85 deletions

View File

@@ -10,6 +10,10 @@ class WPDD_Admin_Payouts {
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'));
}
@@ -50,6 +54,15 @@ class WPDD_Admin_Payouts {
$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
@@ -81,9 +94,172 @@ class WPDD_Admin_Payouts {
<div class="notice notice-error is-dismissible">
<p><?php _e('Error processing payout. 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" 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);
?>
<option value="<?php echo esc_attr($creator->ID); ?>" <?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>
</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" required style="width: 100%;">
<option value=""><?php _e('Select Creator', 'wp-digital-download'); ?></option>
<?php foreach ($all_creators as $creator) : ?>
<option value="<?php echo esc_attr($creator->ID); ?>">
<?php echo esc_html($creator->display_name); ?>
</option>
<?php endforeach; ?>
</select>
</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>
@@ -432,4 +608,241 @@ class WPDD_Admin_Payouts {
return false;
}
}
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_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_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;
}
}