Subscription module: add gateway capability flow and UX fixes
This commit is contained in:
123
includes/Modules/Subscription/GatewayCapabilities.php
Normal file
123
includes/Modules/Subscription/GatewayCapabilities.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Gateway Capabilities — Subscription auto-renew declaration
|
||||
*
|
||||
* Single source of truth for "can this payment gateway auto-debit a
|
||||
* subscription renewal, or does it fall through to manual?"
|
||||
*
|
||||
* Storage:
|
||||
* wp_option('woonoow_gateway_subscription_capabilities')
|
||||
* shape: [ '<gateway_id>' => [ 'subscription_auto_renew' => bool, ... ], ... ]
|
||||
*
|
||||
* Defaults are explicit per gateway ID so the merchant sees a meaningful
|
||||
* matrix out of the box. The defaults reflect the regulatory reality
|
||||
* discussed in SUBSCRIPTION_MODULE_AUDIT.md §9.5:
|
||||
* - Indonesian VA/QRIS/e-wallet gateways: false (no recurring)
|
||||
* - Indonesian credit-card gateways: false (BI/PCI-DSS re-auth)
|
||||
* - PayPal/Stripe/Dodo: true ONLY when the merchant has a working
|
||||
* adapter that implements process_subscription_renewal_payment;
|
||||
* we still default to true because the integration is the common
|
||||
* case in WooNooW's target market.
|
||||
*
|
||||
* The default for any *unknown* gateway is `false` — the safe side.
|
||||
*
|
||||
* @package WooNooW\Modules\Subscription
|
||||
*/
|
||||
|
||||
namespace WooNooW\Modules\Subscription;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
class GatewayCapabilities
|
||||
{
|
||||
const OPTION_KEY = 'woonoow_gateway_subscription_capabilities';
|
||||
|
||||
/**
|
||||
* Built-in safe defaults. Keyed by WooCommerce payment-gateway ID.
|
||||
*
|
||||
* Filter 'woonoow_gateway_subscription_capabilities' lets adapters
|
||||
* and third-party code extend this list at boot time.
|
||||
*/
|
||||
public static function default_capabilities(): array
|
||||
{
|
||||
return [
|
||||
// Global auto-debit-capable gateways
|
||||
'paypal' => ['subscription_auto_renew' => true],
|
||||
'stripe' => ['subscription_auto_renew' => true],
|
||||
'stripe_cc' => ['subscription_auto_renew' => true],
|
||||
'stripe_sepa' => ['subscription_auto_renew' => true],
|
||||
'dodo' => ['subscription_auto_renew' => true],
|
||||
|
||||
// Indonesian manual-only gateways (VA/QRIS/e-wallet/CC re-auth)
|
||||
'tripay' => ['subscription_auto_renew' => false],
|
||||
'midtrans' => ['subscription_auto_renew' => false],
|
||||
'xendit' => ['subscription_auto_renew' => false],
|
||||
'doku' => ['subscription_auto_renew' => false],
|
||||
'duitku' => ['subscription_auto_renew' => false],
|
||||
|
||||
// Cheques / offline / no auto-debit
|
||||
'cheque' => ['subscription_auto_renew' => false],
|
||||
'bacs' => ['subscription_auto_renew' => false],
|
||||
'cod' => ['subscription_auto_renew' => false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the merged capability map: defaults < stored < filter.
|
||||
* Always returns a fully-populated array (missing keys default to false).
|
||||
*/
|
||||
public static function all(): array
|
||||
{
|
||||
$stored = get_option(self::OPTION_KEY, []);
|
||||
if (!is_array($stored)) {
|
||||
$stored = [];
|
||||
}
|
||||
|
||||
$merged = array_merge(self::default_capabilities(), $stored);
|
||||
$merged = (array) apply_filters('woonoow_gateway_subscription_capabilities', $merged);
|
||||
|
||||
return $merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Single-gateway capability lookup.
|
||||
* Returns true ONLY if explicitly declared true. Anything else is false.
|
||||
*/
|
||||
public static function supports_auto_renew(string $gateway_id): bool
|
||||
{
|
||||
$gateway_id = sanitize_key($gateway_id);
|
||||
if ($gateway_id === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$caps = self::all();
|
||||
if (!isset($caps[$gateway_id])) {
|
||||
return false; // unknown gateway: safe default
|
||||
}
|
||||
|
||||
return !empty($caps[$gateway_id]['subscription_auto_renew']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Site-level kill switch. When true, EVERY gateway is treated as
|
||||
* manual regardless of per-gateway capability.
|
||||
*/
|
||||
public static function force_manual(): bool
|
||||
{
|
||||
$settings = \WooNooW\Core\ModuleRegistry::get_settings('subscription');
|
||||
return !empty($settings['force_manual_renewal']);
|
||||
}
|
||||
|
||||
/**
|
||||
* The single decision function the renewal flow should call.
|
||||
* Combines: kill switch > gateway capability.
|
||||
*/
|
||||
public static function should_attempt_auto_renew(string $gateway_id): bool
|
||||
{
|
||||
if (self::force_manual()) {
|
||||
return false;
|
||||
}
|
||||
return self::supports_auto_renew($gateway_id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user