Files
WooNooW/includes/Modules/Affiliate/AffiliateLifecycle.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
));
}
}