Affiliate module: fix referral approval lifecycle and settings reads
This commit is contained in:
@@ -5,6 +5,7 @@ namespace WooNooW\Api\Controllers;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
use WP_REST_Server;
|
||||
use WooNooW\Modules\Affiliate\AffiliateSettings;
|
||||
|
||||
class AffiliateCustomerController
|
||||
{
|
||||
@@ -74,8 +75,20 @@ class AffiliateCustomerController
|
||||
? (float) $affiliate['custom_commission_rate']
|
||||
: $global_rate;
|
||||
|
||||
$referrals_table = $wpdb->prefix . 'woonoow_referrals';
|
||||
$earnings = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT
|
||||
SUM(CASE WHEN status = 'approved' THEN commission_amount ELSE 0 END) as total_earnings,
|
||||
SUM(CASE WHEN status = 'pending' THEN commission_amount ELSE 0 END) as pending_earnings
|
||||
FROM $referrals_table
|
||||
WHERE affiliate_id = %d",
|
||||
$affiliate['id']
|
||||
));
|
||||
|
||||
$affiliate['global_commission_rate'] = $global_rate;
|
||||
$affiliate['commission_rate'] = $effective_rate;
|
||||
$affiliate['total_earnings'] = $earnings->total_earnings ?: 0;
|
||||
$affiliate['pending_earnings'] = $earnings->pending_earnings ?: 0;
|
||||
|
||||
return rest_ensure_response($affiliate);
|
||||
}
|
||||
@@ -136,16 +149,51 @@ class AffiliateCustomerController
|
||||
return rest_ensure_response([]);
|
||||
}
|
||||
|
||||
$referrals = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT r.*,
|
||||
$limit = (int) $request->get_param('limit');
|
||||
$page = max(1, (int) $request->get_param('page'));
|
||||
$order_id = $request->get_param('order_id') ? (int) $request->get_param('order_id') : null;
|
||||
|
||||
$where = $wpdb->prepare("WHERE r.affiliate_id = %d", $affiliate->id);
|
||||
if ($order_id) {
|
||||
$where .= $wpdb->prepare(" AND r.order_id = %d", $order_id);
|
||||
}
|
||||
|
||||
$sql = "SELECT r.*,
|
||||
COALESCE(NULLIF(r.cancelled_reason, ''), NULL) as cancelled_reason,
|
||||
COALESCE(r.approved_at, r.created_at) as approved_at
|
||||
FROM $referrals_table r
|
||||
WHERE r.affiliate_id = %d
|
||||
ORDER BY r.created_at DESC",
|
||||
$affiliate->id
|
||||
), ARRAY_A);
|
||||
return rest_ensure_response($referrals);
|
||||
$where
|
||||
ORDER BY r.created_at DESC";
|
||||
|
||||
if ($limit > 0) {
|
||||
$offset = ($page - 1) * $limit;
|
||||
$sql .= $wpdb->prepare(" LIMIT %d OFFSET %d", $limit, $offset);
|
||||
}
|
||||
|
||||
$referrals = $wpdb->get_results($sql, ARRAY_A);
|
||||
|
||||
$total = $wpdb->get_var("SELECT COUNT(r.id) FROM $referrals_table r $where");
|
||||
|
||||
// Attach customer data if enabled
|
||||
if (!empty($referrals) && AffiliateSettings::get_setting('woonoow_affiliate_share_customer_data', false)) {
|
||||
foreach ($referrals as &$ref) {
|
||||
if (!empty($ref['order_id'])) {
|
||||
$order = wc_get_order($ref['order_id']);
|
||||
if ($order) {
|
||||
$ref['customer_name'] = trim($order->get_billing_first_name() . ' ' . $order->get_billing_last_name());
|
||||
$ref['customer_email'] = $order->get_billing_email();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rest_ensure_response([
|
||||
'referrals' => $referrals,
|
||||
'total' => (int) $total,
|
||||
'page' => $page,
|
||||
'limit' => $limit > 0 ? $limit : (int) $total,
|
||||
'total_pages' => $limit > 0 ? ceil($total / $limit) : 1
|
||||
]);
|
||||
}
|
||||
|
||||
public function get_payouts(WP_REST_Request $request)
|
||||
|
||||
@@ -107,11 +107,13 @@ class AffiliateLifecycle
|
||||
if (!$referral) return;
|
||||
|
||||
// Check if holding period is 0 (immediate approval on completion)
|
||||
$holding_period = (int) get_option('woonoow_affiliate_holding_period', 14);
|
||||
$holding_period = (int) AffiliateSettings::get_setting('woonoow_affiliate_holding_period', 14);
|
||||
$handled_now = false;
|
||||
|
||||
if ($holding_period === 0) {
|
||||
// Immediate approval
|
||||
self::auto_approve_referral($referral->id);
|
||||
$handled_now = true;
|
||||
} else {
|
||||
// If order was completed BEFORE the scheduled action time, approve now
|
||||
// Otherwise, the scheduled action will approve later
|
||||
@@ -120,12 +122,13 @@ class AffiliateLifecycle
|
||||
|
||||
if (time() >= $approval_time) {
|
||||
self::auto_approve_referral($referral->id);
|
||||
$handled_now = true;
|
||||
}
|
||||
// If not, the scheduled Action Scheduler job will handle it
|
||||
}
|
||||
|
||||
// Cancel the scheduled auto-approval since we're handling it now
|
||||
if (function_exists('as_unschedule_all_actions')) {
|
||||
// Only unschedule if we actually approved now.
|
||||
if ($handled_now && function_exists('as_unschedule_all_actions')) {
|
||||
as_unschedule_all_actions('woonoow_approve_referral', ['referral_id' => $referral->id], 'woonoow_affiliate');
|
||||
}
|
||||
}
|
||||
@@ -222,13 +225,23 @@ class AffiliateLifecycle
|
||||
|
||||
if (!$referral) return; // Already processed or deleted
|
||||
|
||||
// Double check order status
|
||||
// Double check order status.
|
||||
// Referrals must never be approved before the order is completed.
|
||||
$order = wc_get_order($referral->order_id);
|
||||
if (!$order || in_array($order->get_status(), ['refunded', 'cancelled', 'failed'])) {
|
||||
if (!$order) {
|
||||
return;
|
||||
}
|
||||
|
||||
$order_status = $order->get_status();
|
||||
if (in_array($order_status, ['refunded', 'cancelled', 'failed'])) {
|
||||
self::handle_order_cancelled($referral->order_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($order_status !== 'completed') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Approve referral
|
||||
$wpdb->update(
|
||||
$referrals_table,
|
||||
|
||||
@@ -64,8 +64,32 @@ class AffiliateSettings {
|
||||
'description' => __('Allow affiliates to earn commission when their own user account places an order.', 'woonoow'),
|
||||
'default' => false,
|
||||
],
|
||||
'woonoow_affiliate_share_customer_data' => [
|
||||
'type' => 'toggle',
|
||||
'label' => __('Share Customer Data with Affiliates', 'woonoow'),
|
||||
'description' => __('Allow affiliates to see the name and email of the customers they refer.', 'woonoow'),
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
|
||||
return $schemas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read Affiliate module setting from module settings storage with legacy fallback.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get_setting($key, $default = null)
|
||||
{
|
||||
$module_settings = get_option('woonoow_module_affiliate_settings', []);
|
||||
if (is_array($module_settings) && array_key_exists($key, $module_settings)) {
|
||||
return $module_settings[$key];
|
||||
}
|
||||
|
||||
// Legacy fallback for older installs that may store direct option keys.
|
||||
return get_option($key, $default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,7 +363,7 @@ class AffiliateTracker
|
||||
|
||||
// Schedule auto-approval (e.g., 14 days) via Action Scheduler
|
||||
if (function_exists('as_schedule_single_action')) {
|
||||
$approval_days = get_option('woonoow_affiliate_holding_period', 14);
|
||||
$approval_days = (int) AffiliateSettings::get_setting('woonoow_affiliate_holding_period', 14);
|
||||
$timestamp = time() + ($approval_days * DAY_IN_SECONDS);
|
||||
as_schedule_single_action($timestamp, 'woonoow_approve_referral', ['referral_id' => $referral_id], 'woonoow_affiliate');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user