context = 'woocommerce'; add_action( 'woocommerce_before_checkout_form', array( $this, 'action_add_checkout_notice' ) ); add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'checkout_actions' ) ); add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'cart_updated_actions' ) ); add_action( 'woocommerce_checkout_order_processed', array( $this, 'validate_coupon_usage' ), 10, 2 ); add_filter( 'wcs_renewal_order_created', array( $this, 'subscription_actions' ), 10, 2 ); add_action( 'woocommerce_subscription_renewal_payment_complete', array( $this, 'subscription_validate_coupon_usage' ) ); add_action( 'woocommerce_removed_coupon', array( $this, 'delete_coupon_on_removal' ) ); } /** * Add a payment to a referrer * * @access protected * @since 0.1 * @param int $referral_id The referral ID * @return bool false if adding failed, object otherwise */ protected function add_payment( $referral_id ) { // Return if the referral ID isn't valid if( ! is_numeric( $referral_id ) ) { return; } // Get the referral object $referral = affwp_get_referral( $referral_id ); // Get the user id $user_id = affwp_get_affiliate_user_id( $referral->affiliate_id ); // Get the user's current woocommerce credit balance $current_balance = get_user_meta( $user_id, 'affwp_wc_credit_balance', true ); $new_balance = floatval( (float) $current_balance + (float) $referral->amount ); return update_user_meta( $user_id, 'affwp_wc_credit_balance', $new_balance ); } /** * Edit a store credit payment * * @access protected * @since 0.1 * @param int $referral_id The referral ID * @return bool false if adding failed, object otherwise */ protected function edit_payment( $referral_id ) { // Return if the referral ID isn't valid if( ! is_numeric( $referral_id ) ) { return; } // Get the referral object $referral = affwp_get_referral( $referral_id ); // Get the referral amounts $old_amount = $referral->amount; $new_amount = $data['amount']; // Get the user id $user_id = affwp_get_affiliate_user_id( $referral->affiliate_id ); // Get the user's current woocommerce credit balance $current_balance = get_user_meta( $user_id, 'affwp_wc_credit_balance', true ); if ( $new_amount > $old_amount ) { $new_balance = floatval( $current_balance + $new_amount ); } elseif ( $new_amount < $old_amount ) { $new_balance = floatval( $current_balance - $new_amount ); } return update_user_meta( $user_id, 'affwp_wc_credit_balance', $new_balance ); } /** * Remove a payment from a referrer * * @access protected * @since 0.1 * @param int $referral_id The referral ID * @return bool false if removing failed, object otherwise */ protected function remove_payment( $referral_id ) { // Return if the referral ID isn't valid if( ! is_numeric( $referral_id ) ) { return; } // Get the referral object $referral = affwp_get_referral( $referral_id ); // Get the user id $user_id = affwp_get_affiliate_user_id( $referral->affiliate_id ); // Get the user's current woocommerce credit balance $current_balance = get_user_meta( $user_id, 'affwp_wc_credit_balance', true ); $new_balance = floatval( $current_balance - $referral->amount ); return update_user_meta( $user_id, 'affwp_wc_credit_balance', $new_balance ); } /** * Add notice on checkout if user can checkout with coupon * * @access public * @since 0.1 * @return void */ public function action_add_checkout_notice() { $balance = (float) get_user_meta( get_current_user_id(), 'affwp_wc_credit_balance', true ); $cart_coupons = WC()->cart->get_applied_coupons(); $coupon_applied = $this->check_for_coupon( $cart_coupons ); $notice_subject = __( 'You have an account balance of', 'affiliatewp-store-credit' ); $notice_query = __( 'Would you like to use it now?', 'affiliatewp-store-credit' ); $notice_action = __( 'Apply', 'affiliatewp-store-credit' ); // If the user has a credit balance, // and has not already generated and applied a coupon code if( $balance && ! $coupon_applied ) { wc_print_notice( sprintf( '%1$s %2$s. %3$s %5$s', $notice_subject, wc_price( $balance ), $notice_query, add_query_arg( 'affwp_wc_apply_credit', 'true', esc_url( wc_get_checkout_url() ) ), $notice_action ), 'notice' ); } } /** * Process checkout actions * * @access public * @since 0.1 * @return void */ public function checkout_actions() { if( isset( $_GET['affwp_wc_apply_credit'] ) && $_GET['affwp_wc_apply_credit'] ) { $user_id = get_current_user_id(); // Get the credit balance and cart total $credit_balance = (float) get_user_meta( $user_id, 'affwp_wc_credit_balance', true ); $cart_total = (float) $this->calculate_cart_subtotal(); // Determine the max possible coupon value $coupon_total = $this->calculate_coupon_amount( $credit_balance, $cart_total ); // Bail if the coupon value was 0 if( $coupon_total <= 0 ) { return; } // Attempt to generate a coupon code $coupon_code = $this->generate_coupon( $user_id, $coupon_total ); // If a coupon code was successfully generated, apply it if( $coupon_code ) { WC()->cart->add_discount( $coupon_code ); wp_redirect( remove_query_arg( 'affwp_wc_apply_credit' ) ); exit; } } } /** * Calculate the cart subtotal * * @access protected * @since 0.1 * @return float $cart_subtotal The subtotal */ protected function calculate_cart_subtotal() { $cart_subtotal = ( 'excl' == WC()->cart->tax_display_cart ) ? WC()->cart->subtotal_ex_tax : WC()->cart->subtotal; return $cart_subtotal; } /** * Calculate the amount of a coupon * * @access protected * @since 0.1 * @param float $credit_balance The balance of a users account * @param float $cart_total The value of the current cart * @return float $coupon_amount The coupon amount */ protected function calculate_coupon_amount( $credit_balance, $cart_total ) { // If either of these are empty, return 0 if( ! $credit_balance || ! $cart_total ) { return 0; } if( $credit_balance > $cart_total ) { $coupon_amount = $cart_total; } else { $coupon_amount = $credit_balance; } return $coupon_amount; } /** * Generate a coupon * * @access protected * @since 0.1 * @param int $user_id The ID of a given user * @param float $amount The amount of the coupon * @return mixed string $coupon_code The coupon code if successful, false otherwise */ protected function generate_coupon( $user_id = 0, $amount = 0 ){ $amount = floatval( $amount ); if( $amount <= 0 ) { return false; } $affiliate = affiliate_wp()->affiliates->get_by( 'user_id', $user_id ); if ( $affiliate ) { $affiliate_id = $affiliate->affiliate_id; } if ( ! $affiliate_id ) { return false; } $user_id = ( $user_id ) ? $user_id : get_current_user_id(); $user_info = get_userdata( $user_id ); $affiliate_id = is_int( $affiliate_id ) ? $affiliate_id : affwp_get_affiliate_id( $user_id ); $date = current_time( 'YmdHi' ); $coupon_code = 'AFFILIATE-CREDIT-' . $date . '_' . $user_id; $expires = $this->coupon_expires(); // Get the user email and affiliate payment email addresses, to match against customer_email below. $user_emails = array(); $user_emails = array( $user_info->user_email, affwp_get_affiliate_payment_email( $affiliate_id ) ); $coupon_data = apply_filters( 'affwp_store_credit_woocommerce_coupon_data', array( 'discount_type' => 'fixed_cart', 'coupon_amount' => $amount, 'individual_use' => 'no', 'usage_limit' => '1', 'expiry_date' => $expires, 'apply_before_tax' => 'yes', 'free_shipping' => 'no', 'customer_email' => $user_emails, ) ); $coupon = array( 'post_title' => $coupon_code, 'post_content' => '', 'post_status' => 'publish', 'post_author' => 1, 'post_type' => 'shop_coupon', 'meta_input' => $coupon_data ); $new_coupon_id = wp_insert_post( $coupon ); if ( $new_coupon_id ) { return $coupon_code; } return false; } /** * Validate a coupon * * @access public * @since 0.1 * @param int $order_id The ID of an order * @param object $data The order data * @return void|boolean false Calls the processed_used_coupon() method if * the user ID matches the user ID provided within * */ public function validate_coupon_usage( $order_id, $data ) { // Get the order object $order = new WC_Order( $order_id ); // Get the user ID associated with the order $user_id = $order->get_user_id(); // Grab an array of coupons used $coupons = $order->get_used_coupons(); // If the order has coupons if( $coupon_code = $this->check_for_coupon( $coupons ) ) { // Bail if the user ID in the coupon does not match the current user. $user_id_from_coupon = intval( substr( $coupon_code, stripos( $coupon_code, '_' ) +1 ) ); if ( intval( $user_id ) === $user_id_from_coupon ) { // Process the coupon usage and remove the amount from the user's credit balance $this->process_used_coupon( $user_id, $coupon_code ); } else { return false; } } } /** * Check for a coupon * * @access protected * @since 0.1 * @param array $coupons Coupons to check * @return mixed $coupon_code if found, false otherwise */ protected function check_for_coupon( $coupons = array() ) { if( ! empty( $coupons ) ) { foreach ( $coupons as $coupon_code ) { // Return coupon code if an affiliate credit coupon is found if ( false !== stripos( $coupon_code, 'AFFILIATE-CREDIT-' ) ) { return $coupon_code; } } } return false; } /** * Process a used coupon * * @access protected * @since 0.1 * @param int $user_id The ID of a given user * @param string $coupon_code The coupon to process * @return mixed object if successful, false otherwise */ protected function process_used_coupon( $user_id = 0, $coupon_code = '' ) { if( ! $user_id || ! $coupon_code ) { return; } $coupon = new WC_Coupon( $coupon_code ); $coupon_amount = $coupon->get_amount(); if( ! $coupon_amount ) { return; } // Get the user's current woocommerce credit balance $current_balance = get_user_meta( $user_id, 'affwp_wc_credit_balance', true ); $new_balance = floatval( $current_balance - $coupon_amount ); return update_user_meta( $user_id, 'affwp_wc_credit_balance', $new_balance ); } /** * Process subscription renewal actions * * @access public * @since 2.3 * * @param object $renewal_order The renewal order object * @param object $subscription The subscription object * * @return object $renewal_order Renewal order object */ public function subscription_actions( $renewal_order, $subscription ) { $store_credit_woocommerce_subscriptions_enabled = affiliate_wp()->settings->get( 'store-credit-woocommerce-subscriptions' ); if ( ! $store_credit_woocommerce_subscriptions_enabled ) { return $renewal_order; } if ( ! $renewal_order instanceof WC_Order ) { return $renewal_order; } $user_id = $subscription->get_user_id(); // Get the credit balance and cart total. $credit_balance = (float) get_user_meta( $user_id, 'affwp_wc_credit_balance', true ); $order_total = (float) $renewal_order->get_total(); // Determine the max possible coupon value. $coupon_total = $this->calculate_coupon_amount( $credit_balance, $order_total ); // Bail if the coupon value was 0. if ( $coupon_total <= 0 ) { return $renewal_order; } // Attempt to generate a coupon code. $coupon_code = $this->generate_coupon( $user_id, $coupon_total ); if ( $coupon_code ) { $renewal_order->apply_coupon( $coupon_code ); } return $renewal_order; } /** * Validate a coupon for a subscription order * * @access public * @since 2.3 * * @param object $subscription The subscription object * * @return void|false * */ public function subscription_validate_coupon_usage( $subscription ) { $store_credit_woocommerce_subscriptions_enabled = affiliate_wp()->settings->get( 'store-credit-woocommerce-subscriptions' ); if ( ! $store_credit_woocommerce_subscriptions_enabled ) { return; } $last_order = $subscription->get_last_order( 'all' ); // Get the user ID associated with the order. $user_id = $last_order->get_user_id(); // Grab an array of coupons used. $coupons = $last_order->get_used_coupons(); // If the order has coupons. if ( $coupon_code = $this->check_for_coupon( $coupons ) ) { // Bail if the user ID in the coupon does not match the current user. $user_id_from_coupon = intval( substr( $coupon_code, stripos( $coupon_code, '_' ) + 1 ) ); if ( intval( $user_id ) === $user_id_from_coupon ) { // Process the coupon usage and remove the amount from the user's credit balance $this->process_used_coupon( $user_id, $coupon_code ); } else { return false; } } } /** * Update the coupon when a cart action occurs * * @access public * @since 2.3.1 * * @return void */ public function cart_updated_actions() { $coupons = WC()->cart->get_applied_coupons(); if ( $coupon_code = $this->check_for_coupon( $coupons ) ) { $cart_total = (float) $this->calculate_cart_subtotal(); $coupon = new WC_Coupon( $coupon_code ); $coupon_amount = (float) $coupon->get_amount(); // Delete and remove coupon when the cart is emptied if ( 0 == $cart_total ) { $coupon_id = $coupon->get_id(); if ( ! empty( $coupon_id ) ) { WC()->cart->remove_coupon( $coupon_code ); wp_delete_post( $coupon_id ); } return; } // Update coupon amount when the cart is updated if ( $cart_total == $coupon_amount ) { return; } $user_id = get_current_user_id(); // Get the credit balance and cart total $credit_balance = (float) get_user_meta( $user_id, 'affwp_wc_credit_balance', true ); // Determine the max possible coupon value $coupon_total = $this->calculate_coupon_amount( $credit_balance, $cart_total ); $coupon_id = $coupon->get_id(); if ( ! empty( $coupon_id ) ) { // Update coupon amount with the new max possible coupon value update_post_meta( $coupon_id, 'coupon_amount', $coupon_total ); } } } /** * Delete a coupon when it is removed * * @access public * @since 2.3.1 * * @param string $coupon_code The coupon code * * @return void */ public function delete_coupon_on_removal( $coupon_code ) { if ( false !== stripos( $coupon_code, 'AFFILIATE-CREDIT-' ) ) { $applied_coupons = isset( WC()->cart->applied_coupons ) ? WC()->cart->applied_coupons : array(); if ( ! in_array( $coupon_code, $applied_coupons ) ) { $coupon = new WC_Coupon( $coupon_code ); $coupon_id = $coupon->get_id(); if ( ! empty( $coupon_id ) ) { wp_delete_post( $coupon_id ); } } } } } new AffiliateWP_Store_Credit_WooCommerce;