This repository has been archived on 2026-04-06. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
woo-alipay-subscriptions/inc/class-wc-alipay-subscriptions.php
feibisi b0c733a63c Add Woo Alipay Subscriptions integration
Introduce a new plugin to integrate Woo Alipay with WooCommerce Subscriptions. This includes admin settings, agreement signing and callbacks, auto-debit charge logic, retry scheduling, email enhancements, and a custom payment token for Alipay agreements. The code prepares for both manual and automatic renewal flows, with hooks for agreement management and payment retries.
2025-10-04 10:43:37 +08:00

147 lines
6.8 KiB
PHP

<?php
if ( ! defined( 'ABSPATH' ) ) { exit; }
class WC_Alipay_Subscriptions {
public function __construct() {
// Hook for automatic renewals (will only run when gateway supports automatic payments)
add_action( 'woocommerce_scheduled_subscription_payment_alipay', array( $this, 'scheduled_subscription_payment' ), 10, 2 );
// Allow extensions to customize notify_url when needed (kept as pass-through for now)
add_filter( 'woo_alipay_gateway_notify_url', array( $this, 'maybe_route_notify_url' ), 10, 2 );
}
/**
* Optionally route notify_url for subscription-specific callbacks.
*/
public function maybe_route_notify_url( $notify_url, $order_id ) {
// Placeholder: keep original notify URL. We can route to a dedicated endpoint when adding agreement callbacks.
return $notify_url;
}
/**
* Handle scheduled subscription payment for gateway ID "alipay".
*
* @param float $amount_to_charge
* @param WC_Order $renewal_order
*/
public function scheduled_subscription_payment( $amount_to_charge, $renewal_order ) {
if ( ! $renewal_order || ! is_a( $renewal_order, 'WC_Order' ) ) {
return;
}
$logger = wc_get_logger();
$context = array( 'source' => 'alipay-subscriptions' );
// Phase 1: manual renewal mode by default
$auto_debit_enabled = ( 'yes' === get_option( 'woo_alipay_subscriptions_enable_auto_debit', 'no' ) );
if ( ! $auto_debit_enabled ) {
$renewal_order->add_order_note( __( '未启用自动代扣或未完成签约:将使用手动续费。', 'woo-alipay-subscriptions' ) );
$renewal_order->update_status( 'failed', __( '自动代扣未启用或未签约,标记为失败以触发手动续费。', 'woo-alipay-subscriptions' ) );
$logger->log( 'info', 'Auto debit disabled, renewal order set to failed: #' . $renewal_order->get_id(), $context );
return;
}
// Look up an Alipay agreement token for this customer
$user_id = $renewal_order->get_user_id();
$token = $this->get_user_agreement_token( $user_id );
if ( ! $token ) {
$renewal_order->add_order_note( __( '未找到支付宝代扣协议,无法自动续费。', 'woo-alipay-subscriptions' ) );
$renewal_order->update_status( 'failed', __( '未找到支付宝代扣协议,标记为失败以触发手动续费。', 'woo-alipay-subscriptions' ) );
$logger->log( 'warning', 'No Alipay agreement token for user #' . $user_id . ', order #' . $renewal_order->get_id(), $context );
return;
}
// Execute charge using agreement
$agreement_no = method_exists( $token, 'get_agreement_no' ) ? $token->get_agreement_no() : $token->get_token();
$product_code = get_option( 'woo_alipay_subscriptions_product_code', 'GENERAL_WITHHOLDING' );
$result = WC_Alipay_Subscriptions_Charge::charge_with_agreement( $renewal_order, $amount_to_charge, $agreement_no, $product_code );
if ( is_wp_error( $result ) ) {
$renewal_order->add_order_note( sprintf( __( '自动代扣失败:%s', 'woo-alipay-subscriptions' ), $result->get_error_message() ) );
$logger->log( 'error', 'Auto debit failed for order #' . $renewal_order->get_id() . ' - ' . $result->get_error_message(), $context );
// Schedule retry according to plan
$this->maybe_schedule_retry( $renewal_order );
$renewal_order->update_status( 'failed' );
return;
}
// Payment created successfully; mark as paid
$renewal_order->payment_complete( $result['trade_no'] );
$renewal_order->add_order_note( sprintf( __( '自动代扣成功 - 交易号: %s', 'woo-alipay-subscriptions' ), $result['trade_no'] ) );
}
/**
* Schedule retry attempts based on settings (0,1,3,7 days).
*/
private function maybe_schedule_retry( WC_Order $order ) {
$plan_raw = get_option( 'woo_alipay_subscriptions_retry_plan', '0,1,3,7' );
$plan = array_values( array_filter( array_map( 'absint', array_map( 'trim', explode( ',', $plan_raw ) ) ), function( $v ){ return $v >= 0; } ) );
if ( empty( $plan ) ) { $plan = array( 1, 3, 7 ); }
$attempt = absint( $order->get_meta( '_woo_alipay_retry_attempt', true ) );
if ( $attempt >= count( $plan ) ) {
return; // no more retries
}
$delay_days = $plan[ $attempt ];
$timestamp = time() + ( $delay_days * DAY_IN_SECONDS );
$order->update_meta_data( '_woo_alipay_retry_attempt', $attempt + 1 );
$order->save();
wp_schedule_single_event( $timestamp, 'woo_alipay_subscriptions_retry_charge', array( $order->get_id() ) );
}
/**
* Get a customer Alipay agreement token if available.
*
* @param int $user_id
* @return WC_Payment_Token_Alipay_Agreement|null
*/
private function get_user_agreement_token( $user_id ) {
if ( ! $user_id ) {
return null;
}
$tokens = WC_Payment_Tokens::get_customer_tokens( $user_id, 'alipay_agreement' );
if ( empty( $tokens ) ) {
return null;
}
// Return the first available token
$token = is_array( $tokens ) ? array_shift( $tokens ) : $tokens;
return ( $token instanceof WC_Payment_Token ) ? $token : null;
}
/**
* Handle our retry event.
*/
public function handle_retry_event( $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order || $order->is_paid() ) {
return;
}
$user_id = $order->get_user_id();
$token = $this->get_user_agreement_token( $user_id );
if ( ! $token ) {
return;
}
$amount = (float) $order->get_total();
$agreement_no = method_exists( $token, 'get_agreement_no' ) ? $token->get_agreement_no() : $token->get_token();
$product_code = get_option( 'woo_alipay_subscriptions_product_code', 'GENERAL_WITHHOLDING' );
$result = WC_Alipay_Subscriptions_Charge::charge_with_agreement( $order, $amount, $agreement_no, $product_code );
if ( is_wp_error( $result ) ) {
$order->add_order_note( sprintf( __( '自动代扣重试失败:%s', 'woo-alipay-subscriptions' ), $result->get_error_message() ) );
$this->maybe_schedule_retry( $order );
return;
}
$order->payment_complete( $result['trade_no'] );
$order->add_order_note( sprintf( __( '自动代扣成功(重试) - 交易号: %s', 'woo-alipay-subscriptions' ), $result['trade_no'] ) );
}
}
// Initialize the class
$__woo_alipay_subs = new WC_Alipay_Subscriptions();
// Bind retry action
add_action( 'woo_alipay_subscriptions_retry_charge', array( $__woo_alipay_subs, 'handle_retry_event' ), 10, 1 );