get_referral( $referral_id ); if ( ! $referral ) { return; } $recipient = $settings->reward_recipient(); if ( in_array( $recipient, [ 'sender', 'both' ], true ) ) { $this->create_reward( $referral_id, (int) $referral->referrer_id, 'sender' ); } if ( in_array( $recipient, [ 'receiver', 'both' ], true ) ) { $referee_id = (int) $referral->referee_id; if ( $referee_id > 0 ) { $this->create_reward( $referral_id, $referee_id, 'receiver' ); } } // Update referral status $db->update_referral_status( $referral_id, 'rewarded', [ 'rewarded_at' => current_time( 'mysql', true ), ] ); } /** * Create a single reward record for a user. */ private function create_reward( int $referral_id, int $user_id, string $role ): void { $settings = ADSD_RCC_Settings::instance(); $db = ADSD_RCC_DB::instance(); $codegen = ADSD_RCC_Code_Generator::instance(); [ $type, $value ] = $this->calculate_reward( $settings, $role ); $expiry_days = $settings->code_expiry_days(); $expires_at = $expiry_days > 0 ? gmdate( 'Y-m-d H:i:s', strtotime( "+{$expiry_days} days" ) ) : null; $code = $codegen->generate(); $reward_id = $db->insert_reward( [ 'referral_id' => $referral_id, 'user_id' => $user_id, 'reward_code' => $code, 'reward_type' => $type, 'reward_value' => $value, 'status' => 'active', 'expires_at' => $expires_at, ] ); if ( ! $reward_id ) { $db->log( 'reward_create_failed', $user_id, $referral_id, "Failed to create {$role} reward." ); return; } $reward = $db->get_reward( $reward_id ); $user = get_user_by( 'id', $user_id ); if ( $user && $reward ) { $this->send_reward_email( $user, $reward ); } $db->log( 'reward_created', $user_id, $reward_id, "Reward created for {$role}.", [ 'code' => $code, 'type' => $type, 'value' => $value, ] ); } /** * Calculate reward value based on settings and role. * * @return array [type, value] */ private function calculate_reward( ADSD_RCC_Settings $s, string $role ): array { $recipient = $s->reward_recipient(); // Separate sender/receiver settings when BOTH is active if ( $recipient === 'both' ) { $offer_key = ( $role === 'sender' ) ? 'sender_offer_type' : 'receiver_offer_type'; $offer_type = $s->get( $offer_key, 'automatic' ); } else { $offer_type = $s->offer_type(); } switch ( $offer_type ) { case 'automatic': $min = (float) $s->get( ( $recipient === 'both' ) ? "{$role}_offer_min" : 'offer_min', 20 ); $max = (float) $s->get( ( $recipient === 'both' ) ? "{$role}_offer_max" : 'offer_max', 100 ); // Use random_int for uniform distribution; multiply by 100 to get 2 decimal precision $value = round( random_int( (int) ( $min * 100 ), (int) ( $max * 100 ) ) / 100, 2 ); return [ 'fixed', $value ]; case 'manual': // In "both" mode use per-role fixed value; otherwise use the shared field $value = (float) $s->get( ( $recipient === 'both' ) ? "{$role}_offer_fixed" : 'offer_fixed', 50 ); return [ 'fixed', $value ]; case 'automatic_percent': $min = (float) $s->get( ( $recipient === 'both' ) ? "{$role}_offer_min" : 'offer_min', 10 ); $max = (float) $s->get( ( $recipient === 'both' ) ? "{$role}_offer_max" : 'offer_max', 30 ); $value = round( random_int( (int) ( $min * 100 ), (int) ( $max * 100 ) ) / 100, 2 ); return [ 'percent', $value ]; case 'manual_percent': // In "both" mode use per-role fixed %; otherwise use the shared field $value = (float) $s->get( ( $recipient === 'both' ) ? "{$role}_offer_percent_fixed" : 'offer_percent_fixed', 20 ); return [ 'percent', $value ]; default: return [ 'fixed', 50.0 ]; } } /** * Format reward value for display. */ public static function format_value( object $reward ): string { if ( $reward->reward_type === 'percent' ) { return number_format_i18n( (float) $reward->reward_value, 2 ) . '%'; } if ( ADSD_RCC_Plugin::is_woocommerce_active() ) { return wc_price( (float) $reward->reward_value ); } // Fallback when WooCommerce is not active — use generic currency symbol $symbol = function_exists( 'get_woocommerce_currency_symbol' ) ? get_woocommerce_currency_symbol() : '$'; return $symbol . number_format_i18n( (float) $reward->reward_value, 2 ); } private function send_reward_email( WP_User $user, object $reward ): void { $mailer = ADSD_RCC_Mailer::instance(); $s = ADSD_RCC_Settings::instance(); $vars = [ '{user_email}' => $user->user_email, '{reward_code}' => $reward->reward_code, '{reward_value}' => self::format_value( $reward ), '{expiry_date}' => $reward->expires_at ? date_i18n( get_option( 'date_format' ), strtotime( $reward->expires_at ) ) : __( 'No expiry', 'adsd-referral-couponcore' ), '{button_url}' => $s->page_url( 'reward_list' ), ]; $mailer->send( $user->user_email, 'reward_generated', $vars ); } /** * Send reward-used notification. */ public function send_used_email( WP_User $user, object $reward ): void { $vars = [ '{user_email}' => $user->user_email, '{reward_code}' => $reward->reward_code, ]; ADSD_RCC_Mailer::instance()->send( $user->user_email, 'reward_used', $vars ); } /** * Send reward-expired notification. */ public function send_expired_email( WP_User $user, object $reward ): void { $vars = [ '{user_email}' => $user->user_email, '{reward_code}' => $reward->reward_code, '{expiry_date}' => $reward->expires_at ? date_i18n( get_option( 'date_format' ), strtotime( $reward->expires_at ) ) : '', '{button_url}' => ADSD_RCC_Settings::instance()->page_url( 'dashboard' ), ]; ADSD_RCC_Mailer::instance()->send( $user->user_email, 'reward_expired', $vars ); } }