balance) >= $threshold && !empty($creator->paypal_email)) { WPDD_Admin_Payouts::create_payout($creator->ID, 'automatic'); } } } public static function process_payout($payout_id) { global $wpdb; // Get payout details $payout = $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wpdd_payouts WHERE id = %d", $payout_id )); if (!$payout) { return array('success' => false, 'error' => 'Payout not found'); } // Get PayPal credentials $mode = get_option('wpdd_paypal_mode', 'sandbox'); $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'); } // Get access token $token_result = self::get_access_token($client_id, $secret, $mode); if (!$token_result['success']) { return array('success' => false, 'error' => $token_result['error']); } $access_token = $token_result['token']; // Create payout batch $batch_result = self::create_payout_batch($payout, $access_token, $mode); if ($batch_result['success']) { return array( 'success' => true, 'transaction_id' => $batch_result['batch_id'] ); } else { return array( 'success' => false, 'error' => $batch_result['error'] ); } } private static function get_access_token($client_id, $secret, $mode) { $base_url = $mode === 'sandbox' ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com'; $response = wp_remote_post( $base_url . '/v1/oauth2/token', array( 'headers' => array( 'Authorization' => 'Basic ' . base64_encode($client_id . ':' . $secret), 'Content-Type' => 'application/x-www-form-urlencoded' ), 'body' => 'grant_type=client_credentials', 'timeout' => 30 ) ); if (is_wp_error($response)) { return array('success' => false, 'error' => $response->get_error_message()); } $body = json_decode(wp_remote_retrieve_body($response), true); if (isset($body['access_token'])) { return array('success' => true, 'token' => $body['access_token']); } else { $error = isset($body['error_description']) ? $body['error_description'] : 'Failed to get access token'; return array('success' => false, 'error' => $error); } } private static function create_payout_batch($payout, $access_token, $mode) { $base_url = $mode === 'sandbox' ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com'; $batch_id = 'WPDD_' . $payout->id . '_' . time(); // Ensure currency is set, fallback to USD if empty $currency = !empty($payout->currency) ? $payout->currency : 'USD'; $payout_data = array( 'sender_batch_header' => array( 'sender_batch_id' => $batch_id, 'email_subject' => 'You have received a payout!', 'email_message' => 'You have received a payout from ' . get_bloginfo('name') ), 'items' => array( array( 'recipient_type' => 'EMAIL', 'amount' => array( 'value' => number_format($payout->amount, 2, '.', ''), 'currency' => $currency ), 'receiver' => $payout->paypal_email, 'note' => 'Payout for your sales on ' . get_bloginfo('name'), 'sender_item_id' => 'payout_' . $payout->id ) ) ); // Log the payout data for debugging error_log('WPDD PayPal Payout Data: ' . json_encode($payout_data)); $response = wp_remote_post( $base_url . '/v1/payments/payouts', array( 'headers' => array( 'Authorization' => 'Bearer ' . $access_token, 'Content-Type' => 'application/json' ), 'body' => json_encode($payout_data), 'timeout' => 30 ) ); if (is_wp_error($response)) { return array('success' => false, 'error' => $response->get_error_message()); } $response_code = wp_remote_retrieve_response_code($response); $body = json_decode(wp_remote_retrieve_body($response), true); if ($response_code === 201 && isset($body['batch_header']['payout_batch_id'])) { return array( 'success' => true, 'batch_id' => $body['batch_header']['payout_batch_id'] ); } else { $error = 'Failed to create payout batch'; if (isset($body['message'])) { $error = $body['message']; } elseif (isset($body['error_description'])) { $error = $body['error_description']; } return array('success' => false, 'error' => $error); } } public static function check_batch_status($batch_id, $mode = null) { if (!$mode) { $mode = get_option('wpdd_paypal_mode', 'sandbox'); } $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'); } // Get access token $token_result = self::get_access_token($client_id, $secret, $mode); if (!$token_result['success']) { return array('success' => false, 'error' => $token_result['error']); } $access_token = $token_result['token']; $base_url = $mode === 'sandbox' ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com'; $response = wp_remote_get( $base_url . '/v1/payments/payouts/' . $batch_id, array( 'headers' => array( 'Authorization' => 'Bearer ' . $access_token, 'Content-Type' => 'application/json' ), 'timeout' => 30 ) ); if (is_wp_error($response)) { return array('success' => false, 'error' => $response->get_error_message()); } $body = json_decode(wp_remote_retrieve_body($response), true); if (isset($body['batch_header'])) { return array( 'success' => true, 'status' => $body['batch_header']['batch_status'], 'data' => $body ); } else { return array('success' => false, 'error' => 'Failed to get batch status'); } } public static function deactivate() { wp_clear_scheduled_hook('wpdd_process_automatic_payouts'); } }