253 lines
8.7 KiB
PHP
253 lines
8.7 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Affiliate Lifecycle
|
|
*
|
|
* Handles order status changes (refunds, cancellations) and auto-approvals.
|
|
*
|
|
* @package WooNooW\Modules\Affiliate
|
|
*/
|
|
|
|
namespace WooNooW\Modules\Affiliate;
|
|
|
|
if (!defined('ABSPATH')) exit;
|
|
|
|
class AffiliateLifecycle
|
|
{
|
|
/**
|
|
* Initialize lifecycle hooks
|
|
*/
|
|
public static function init()
|
|
{
|
|
// Cancel/Revert on order refund or cancellation
|
|
add_action('woocommerce_order_status_refunded', [__CLASS__, 'handle_order_cancelled']);
|
|
add_action('woocommerce_order_status_cancelled', [__CLASS__, 'handle_order_cancelled']);
|
|
add_action('woocommerce_order_status_failed', [__CLASS__, 'handle_order_cancelled']);
|
|
|
|
// Handle order completion - immediate approval
|
|
add_action('woocommerce_order_status_completed', [__CLASS__, 'handle_order_completed']);
|
|
|
|
// HPOS compatible hooks
|
|
add_action('woocommerce_order_status_changed', [__CLASS__, 'handle_hpos_status_changed'], 10, 4);
|
|
add_action('woocommerce_update_order', [__CLASS__, 'handle_order_updated'], 10, 2);
|
|
|
|
// Handle order deletion (trash + permanent delete)
|
|
add_action('before_delete_post', [__CLASS__, 'handle_order_deleted'], 10, 1);
|
|
add_action('woocommerce_delete_order', [__CLASS__, 'handle_order_deleted'], 10, 1);
|
|
|
|
// Action Scheduler Hook for auto-approval
|
|
add_action('woonoow_approve_referral', [__CLASS__, 'auto_approve_referral']);
|
|
}
|
|
|
|
/**
|
|
* Handle cancelled, refunded, or failed orders
|
|
*/
|
|
public static function handle_order_cancelled($order_id)
|
|
{
|
|
global $wpdb;
|
|
$referrals_table = $wpdb->prefix . 'woonoow_referrals';
|
|
|
|
// Get the order to determine the reason
|
|
$order = wc_get_order($order_id);
|
|
$reason = 'order_cancelled';
|
|
if ($order) {
|
|
$status = $order->get_status();
|
|
$reason = 'order_' . $status;
|
|
}
|
|
|
|
// Find pending or approved referral
|
|
$referral = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT * FROM $referrals_table WHERE order_id = %d AND status IN ('pending', 'approved')",
|
|
$order_id
|
|
));
|
|
|
|
if ($referral) {
|
|
// If was already approved, this is a clawback - decrease affiliate earnings
|
|
if ($referral->status === 'approved') {
|
|
$affiliates_table = $wpdb->prefix . 'woonoow_affiliates';
|
|
$wpdb->query($wpdb->prepare(
|
|
"UPDATE $affiliates_table SET total_earnings = total_earnings - %f WHERE id = %d",
|
|
$referral->commission_amount,
|
|
$referral->affiliate_id
|
|
));
|
|
}
|
|
|
|
// Update status to rejected with reason
|
|
$wpdb->update(
|
|
$referrals_table,
|
|
[
|
|
'status' => 'rejected',
|
|
'cancelled_reason' => $reason,
|
|
'cancelled_at' => current_time('mysql')
|
|
],
|
|
['id' => $referral->id]
|
|
);
|
|
|
|
// Unschedule action if action scheduler exists
|
|
if (function_exists('as_unschedule_all_actions')) {
|
|
as_unschedule_all_actions('woonoow_approve_referral', ['referral_id' => $referral->id], 'woonoow_affiliate');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle order completion - check if referral should be approved
|
|
*/
|
|
public static function handle_order_completed($order_id)
|
|
{
|
|
global $wpdb;
|
|
$referrals_table = $wpdb->prefix . 'woonoow_referrals';
|
|
|
|
// Find pending referral for this order
|
|
$referral = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT * FROM $referrals_table WHERE order_id = %d AND status = 'pending'",
|
|
$order_id
|
|
));
|
|
|
|
if (!$referral) return;
|
|
|
|
// Check if holding period is 0 (immediate approval on completion)
|
|
$holding_period = (int) get_option('woonoow_affiliate_holding_period', 14);
|
|
|
|
if ($holding_period === 0) {
|
|
// Immediate approval
|
|
self::auto_approve_referral($referral->id);
|
|
} else {
|
|
// If order was completed BEFORE the scheduled action time, approve now
|
|
// Otherwise, the scheduled action will approve later
|
|
// Check if the scheduled action time has already passed
|
|
$approval_time = strtotime($referral->created_at) + ($holding_period * DAY_IN_SECONDS);
|
|
|
|
if (time() >= $approval_time) {
|
|
self::auto_approve_referral($referral->id);
|
|
}
|
|
// 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')) {
|
|
as_unschedule_all_actions('woonoow_approve_referral', ['referral_id' => $referral->id], 'woonoow_affiliate');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle HPOS order status change
|
|
*/
|
|
public static function handle_hpos_status_changed($order_id, $from_status, $to_status, $order)
|
|
{
|
|
if ($to_status === 'completed') {
|
|
self::handle_order_completed($order_id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle order update (HPOS compatible)
|
|
*/
|
|
public static function handle_order_updated($order_id, $order)
|
|
{
|
|
if (!$order) return;
|
|
|
|
// Check if order was just completed
|
|
$status = $order->get_status();
|
|
if ($status === 'completed') {
|
|
self::handle_order_completed($order_id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle order deletion (permanent delete or trash)
|
|
*/
|
|
public static function handle_order_deleted($order_id)
|
|
{
|
|
// Check if this is a WooCommerce order
|
|
$order = wc_get_order($order_id);
|
|
if (!$order) return;
|
|
|
|
// Only process shop orders
|
|
$post_type = get_post_type($order_id);
|
|
if ($post_type !== 'shop_order') return;
|
|
|
|
global $wpdb;
|
|
$referrals_table = $wpdb->prefix . 'woonoow_referrals';
|
|
|
|
// Find any referral for this order
|
|
$referral = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT * FROM $referrals_table WHERE order_id = %d",
|
|
$order_id
|
|
));
|
|
|
|
if ($referral) {
|
|
// If was already approved, this is a clawback - decrease affiliate earnings
|
|
if ($referral->status === 'approved') {
|
|
$affiliates_table = $wpdb->prefix . 'woonoow_affiliates';
|
|
$wpdb->query($wpdb->prepare(
|
|
"UPDATE $affiliates_table SET total_earnings = total_earnings - %f WHERE id = %d",
|
|
$referral->commission_amount,
|
|
$referral->affiliate_id
|
|
));
|
|
}
|
|
|
|
// Mark as rejected with "order_deleted" reason
|
|
$wpdb->update(
|
|
$referrals_table,
|
|
[
|
|
'status' => 'rejected',
|
|
'cancelled_reason' => 'order_deleted',
|
|
'cancelled_at' => current_time('mysql')
|
|
],
|
|
['id' => $referral->id]
|
|
);
|
|
|
|
// Unschedule any pending approval action
|
|
if (function_exists('as_unschedule_all_actions')) {
|
|
as_unschedule_all_actions('woonoow_approve_referral', ['referral_id' => $referral->id], 'woonoow_affiliate');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Action Scheduler callback for auto-approving a referral after the holding period
|
|
*/
|
|
public static function auto_approve_referral($referral_id)
|
|
{
|
|
global $wpdb;
|
|
$referrals_table = $wpdb->prefix . 'woonoow_referrals';
|
|
$affiliates_table = $wpdb->prefix . 'woonoow_affiliates';
|
|
|
|
// Find pending referral
|
|
$referral = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT * FROM $referrals_table WHERE id = %d AND status = 'pending'",
|
|
$referral_id
|
|
));
|
|
|
|
if (!$referral) return; // Already processed or deleted
|
|
|
|
// Double check order status
|
|
$order = wc_get_order($referral->order_id);
|
|
if (!$order || in_array($order->get_status(), ['refunded', 'cancelled', 'failed'])) {
|
|
self::handle_order_cancelled($referral->order_id);
|
|
return;
|
|
}
|
|
|
|
// Approve referral
|
|
$wpdb->update(
|
|
$referrals_table,
|
|
[
|
|
'status' => 'approved',
|
|
'approved_at' => current_time('mysql')
|
|
],
|
|
['id' => $referral_id]
|
|
);
|
|
|
|
// Update Affiliate totals
|
|
$wpdb->query($wpdb->prepare(
|
|
"UPDATE $affiliates_table SET
|
|
total_referrals = total_referrals + 1,
|
|
total_earnings = total_earnings + %f
|
|
WHERE id = %d",
|
|
$referral->commission_amount,
|
|
$referral->affiliate_id
|
|
));
|
|
}
|
|
}
|