Changeset 3462779
- Timestamp:
- 02/16/2026 05:47:51 PM (3 weeks ago)
- Location:
- autoship-cloud/trunk
- Files:
-
- 18 added
- 19 edited
-
app/Core/FeatureManagerInterface.php (modified) (1 diff)
-
app/Core/Implementations/WordPressFeatureManager.php (modified) (4 diffs)
-
app/Core/Plugin.php (modified) (7 diffs)
-
app/Domain/AbstractPaymentGateway.php (added)
-
app/Domain/PaymentIntegrationFactory.php (modified) (3 diffs)
-
app/Domain/PaymentIntegrations/AuthorizeNetPaymentIntegration.php (modified) (4 diffs)
-
app/Domain/PaymentIntegrations/PayPalPaymentIntegration.php (modified) (6 diffs)
-
app/Domain/PaymentIntegrations/SquarePaymentIntegration.php (modified) (5 diffs)
-
app/Domain/PaymentIntegrations/StripePaymentIntegration.php (modified) (6 diffs)
-
app/Modules/Payments (added)
-
app/Modules/Payments/Compatibility (added)
-
app/Modules/Payments/Compatibility/AbstractPaymentCompatibility.php (added)
-
app/Modules/Payments/Compatibility/AuthorizeNetPaymentCompatibility.php (added)
-
app/Modules/Payments/Compatibility/PayPalPaymentCompatibility.php (added)
-
app/Modules/Payments/Compatibility/PaymentsCompatibilityManager.php (added)
-
app/Modules/Payments/Compatibility/SquarePaymentCompatibility.php (added)
-
app/Modules/Payments/Compatibility/StripePaymentCompatibility.php (added)
-
app/Modules/Payments/PaymentsModule.php (added)
-
app/Modules/Payments/Services (added)
-
app/Modules/Payments/Services/PaymentGatewayRegistry.php (added)
-
app/Modules/Payments/Services/PaymentGatewayService.php (added)
-
app/Modules/Payments/Services/PaymentMethodDataBuilder.php (added)
-
app/Modules/Payments/Services/PaymentMethodService.php (added)
-
app/Modules/Payments/Services/PaymentsCompatibilityService.php (added)
-
app/Services/QPilot/Implementations/FeatureFlagManagement.php (added)
-
app/Services/QPilot/Interfaces/FeatureFlagManagementInterface.php (added)
-
app/Services/QPilot/QPilotServiceClient.php (modified) (4 diffs)
-
app/Services/QPilot/QPilotServiceInterface.php (modified) (2 diffs)
-
autoship.php (modified) (2 diffs)
-
languages/autoship.pot (modified) (1 diff)
-
readme.txt (modified) (2 diffs)
-
src/payments.php (modified) (9 diffs)
-
vendor/autoload.php (modified) (1 diff)
-
vendor/composer/InstalledVersions.php (modified) (3 diffs)
-
vendor/composer/autoload_classmap.php (modified) (4 diffs)
-
vendor/composer/autoload_static.php (modified) (6 diffs)
-
vendor/composer/platform_check.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
autoship-cloud/trunk/app/Core/FeatureManagerInterface.php
r3453277 r3462779 25 25 */ 26 26 public function is_enabled( string $feature ): bool; 27 28 /** 29 * Gets the value indicating if a payment gateway feature is enabled. 30 * 31 * This method checks both the main 'payments' feature flag and the 32 * individual gateway feature flag. 33 * 34 * @param string $gateway_id The payment gateway ID (e.g., 'stripe', 'braintree_credit_card'). 35 * 36 * @return bool 37 */ 38 public function is_payment_gateway_enabled( string $gateway_id ): bool; 27 39 } -
autoship-cloud/trunk/app/Core/Implementations/WordPressFeatureManager.php
r3453277 r3462779 10 10 11 11 use Autoship\Core\FeatureManagerInterface; 12 use Autoship\Services\Logging\Logger; 12 13 13 14 /** 14 15 * WordPress implementation of the feature manager. 16 * 17 * For payment gateway flags (payments_gateway_*), this implementation supports 18 * a two-tier priority chain: 19 * 20 * 1. QPilot remote flags (authoritative when available) 21 * 2. Hardcoded defaults (fallback) - the $features array below 15 22 * 16 23 * @package Autoship … … 18 25 */ 19 26 class WordPressFeatureManager implements FeatureManagerInterface { 27 28 /** 29 * Prefix identifying payment gateway feature flags. 30 * 31 * @var string 32 */ 33 const PAYMENT_GATEWAY_PREFIX = 'payments_gateway_'; 20 34 21 35 /** … … 40 54 'quicklinks' => true, 41 55 'qmc_components' => true, 56 'payments' => true, 57 58 // Per-gateway payment feature flags. 59 'payments_gateway_stripe' => false, // Stripe enabled. 60 'payments_gateway_stripe_sepa' => false, // Stripe SEPA enabled. 61 'payments_gateway_authorize_net' => false, // Authorize.Net enabled. 62 'payments_gateway_braintree' => false, // Braintree disabled by default. 63 'payments_gateway_square' => false, // Square enabled. 64 'payments_gateway_paypal' => false, // PayPal enabled. 65 'payments_gateway_nmi' => false, // NMI disabled by default. 66 'payments_gateway_cybersource' => false, // CyberSource disabled by default. 67 'payments_gateway_trustcommerce' => false, // TrustCommerce disabled by default. 68 'payments_gateway_sage' => false, // Sage disabled by default. 69 'payments_gateway_checkoutcom' => false, // Checkout.com disabled by default. 70 'payments_gateway_opayo' => false, // Opayo disabled by default. 71 'payments_gateway_paya' => false, // Paya disabled by default. 42 72 ); 43 73 44 74 /** 75 * Mapping of gateway IDs to feature keys. 76 * 77 * Multiple WooCommerce gateway IDs can map to a single feature flag. 78 * 79 * @var array<string, string> 80 */ 81 protected array $gateway_feature_map = array( 82 'stripe' => 'stripe', 83 'stripe_sepa' => 'stripe_sepa', 84 'authorize_net_cim_credit_card' => 'authorize_net', 85 'braintree_credit_card' => 'braintree', 86 'braintree_paypal' => 'braintree', 87 'square_credit_card' => 'square', 88 'square_cash_app_pay' => 'square', 89 'paypal' => 'paypal', 90 'ppcp-gateway' => 'paypal', 91 'nmi_gateway_woocommerce' => 'nmi', 92 'cybersource_credit_card' => 'cybersource', 93 'trustcommerce' => 'trustcommerce', 94 'sagepaymentsusaapi' => 'sage', 95 'checkoutcom_card_payment' => 'checkoutcom', 96 'opayo_direct' => 'opayo', 97 'paya_gateway_credit_card' => 'paya', 98 ); 99 100 /** 101 * A callable that returns an array of remotely enabled feature flag names, 102 * or null if remote flags are unavailable. 103 * 104 * @var callable|null 105 */ 106 private $remote_flags_provider = null; 107 108 /** 109 * Cached result from the remote flags provider. 110 * 111 * @var array<string>|null 112 */ 113 private ?array $remote_flags = null; 114 115 /** 116 * Whether remote flags have already been resolved. 117 * 118 * @var bool 119 */ 120 private bool $remote_flags_resolved = false; 121 122 /** 123 * Set the remote flags provider. 124 * 125 * The provider is a callable that returns an array of enabled feature flag 126 * names from QPilot, or null if remote flags are unavailable. 127 * 128 * @param callable $provider A callable returning array<string>|null. 129 * 130 * @return void 131 */ 132 public function set_remote_flags_provider( callable $provider ): void { 133 $this->remote_flags_provider = $provider; 134 $this->remote_flags = null; 135 $this->remote_flags_resolved = false; 136 } 137 138 /** 45 139 * Gets the value indicating if the feature is enabled or not. 46 140 * 141 * For payment gateway flags (payments_gateway_*), the priority chain is: 142 * 1. QPilot remote flags (authoritative when available) 143 * 2. Hardcoded default in $features array 144 * 145 * For all other flags, returns the hardcoded default. 146 * 47 147 * @param string $feature The name of the feature. 48 148 * … … 50 150 */ 51 151 public function is_enabled( string $feature ): bool { 152 // For payment gateway flags, check QPilot remote flags first. 153 if ( $this->is_payment_gateway_feature( $feature ) ) { 154 $remote_flags = $this->resolve_remote_flags(); 155 Logger::log( 'Feature Manager', "Checking feature '{$feature}' - Remote flags: " . ( is_array( $remote_flags ) ? implode( ', ', $remote_flags ) : 'null' ) ); 156 if ( null !== $remote_flags ) { 157 return in_array( $feature, $remote_flags, true ); 158 } 159 } 160 161 // Hardcoded default (for all flags, and fallback for payment flags). 52 162 return ! empty( $this->features[ $feature ] ); 53 163 } 164 165 /** 166 * Gets the value indicating if a payment gateway feature is enabled. 167 * 168 * This method checks both the main 'payments' feature flag and the 169 * individual gateway feature flag. 170 * 171 * @param string $gateway_id The payment gateway ID (e.g., 'stripe', 'braintree_credit_card'). 172 * 173 * @return bool 174 */ 175 public function is_payment_gateway_enabled( string $gateway_id ): bool { 176 // First check if the main payments module is enabled. 177 if ( ! $this->is_enabled( 'payments' ) ) { 178 return false; 179 } 180 181 // Normalize gateway ID to feature key and check. 182 $feature_key = self::PAYMENT_GATEWAY_PREFIX . $this->normalize_gateway_id( $gateway_id ); 183 184 return $this->is_enabled( $feature_key ); 185 } 186 187 /** 188 * Normalize a gateway ID to its feature key. 189 * 190 * Maps various WooCommerce gateway IDs to their corresponding feature keys. 191 * For example, 'braintree_credit_card' and 'braintree_paypal' both map to 'braintree'. 192 * 193 * @param string $gateway_id The gateway ID. 194 * 195 * @return string The normalized feature key. 196 */ 197 protected function normalize_gateway_id( string $gateway_id ): string { 198 // Check if we have a specific mapping. 199 if ( isset( $this->gateway_feature_map[ $gateway_id ] ) ) { 200 return $this->gateway_feature_map[ $gateway_id ]; 201 } 202 203 // Fall back to sanitizing the gateway ID. 204 return str_replace( array( '-', ' ' ), '_', strtolower( $gateway_id ) ); 205 } 206 207 /** 208 * Check if a feature name is a payment gateway feature. 209 * 210 * @param string $feature The feature name. 211 * 212 * @return bool True if the feature is a payment gateway flag. 213 */ 214 private function is_payment_gateway_feature( string $feature ): bool { 215 return 0 === strpos( $feature, self::PAYMENT_GATEWAY_PREFIX ); 216 } 217 218 /** 219 * Lazily resolve remote feature flags from the provider. 220 * 221 * The provider is only called once per request. Subsequent calls 222 * return the cached result. 223 * 224 * @return array<string>|null The list of enabled flag names, or null if unavailable. 225 */ 226 private function resolve_remote_flags(): ?array { 227 if ( $this->remote_flags_resolved ) { 228 return $this->remote_flags; 229 } 230 231 $this->remote_flags_resolved = true; 232 233 if ( null === $this->remote_flags_provider ) { 234 return null; 235 } 236 237 $this->remote_flags = call_user_func( $this->remote_flags_provider ); 238 239 return $this->remote_flags; 240 } 54 241 } -
autoship-cloud/trunk/app/Core/Plugin.php
r3453277 r3462779 18 18 use Autoship\Core\Implementations\WordPressOAuthService; 19 19 use Autoship\Core\Implementations\WordPressSettings; 20 use Autoship\Services\QPilot\QPilotServiceFactory; 20 21 use Autoship\Modules\Nextime\NextimeModule; 22 use Autoship\Modules\Payments\PaymentsModule; 21 23 use Autoship\Modules\Quicklaunch\QuicklaunchModule; 22 24 use Autoship\Modules\QuickLinks\QuickLinksModule; … … 24 26 use Autoship\Services\Logging\AutoshipLogger; 25 27 use Autoship\Services\Logging\Implementations\WordPressLoggingSettings; 28 use Autoship\Services\Logging\Logger; 26 29 use Autoship\Services\Logging\LoggerInterface; 27 30 use Autoship\Services\Logging\LoggingSettingsInterface; … … 74 77 * @throws Exception If the boot process fails. 75 78 */ 76 public function boot(): void {79 public function boot(): void { 77 80 $this->register_core_services(); 78 81 $this->initialize_logging(); … … 90 93 FeatureManagerInterface::class, 91 94 function () { 92 return new WordPressFeatureManager(); 95 $manager = new WordPressFeatureManager(); 96 $manager->set_remote_flags_provider( array( $this, 'fetch_qpilot_feature_flags' ) ); 97 98 return $manager; 93 99 } 94 100 ); … … 220 226 $this->module_manager->register_module( new QuickLinksModule() ); 221 227 } 228 229 if ( $features->is_enabled( 'payments' ) ) { 230 $this->module_manager->register_module( new PaymentsModule() ); 231 } 222 232 } 223 233 … … 227 237 * @return void 228 238 */ 229 protected function boot_modules(): void {239 protected function boot_modules(): void { 230 240 $this->module_manager->boot(); 231 241 } … … 247 257 protected function uninstall_modules(): void { 248 258 $this->module_manager->uninstall(); 259 } 260 261 /** 262 * Fetch feature flags from the QPilot API. 263 * 264 * Retrieves both global and site-specific flags, merges them, 265 * and caches the result in a WordPress transient for 1 hour. 266 * 267 * @return array<string>|null List of enabled flag names, or null on failure. 268 */ 269 public function fetch_qpilot_feature_flags(): ?array { 270 $cache_key = 'autoship_qpilot_feature_flags'; 271 $cached = get_transient( $cache_key ); 272 273 if ( false !== $cached ) { 274 Logger::debug( 'Feature Flags', 'Returning cached remote flags.' ); 275 return $cached; 276 } 277 278 $token = get_option( 'autoship_token_auth', '' ); 279 $site_id = (int) get_option( 'autoship_site_id', 0 ); 280 281 if ( empty( $token ) || $site_id <= 0 ) { 282 Logger::debug( 'Feature Flags', 'No QPilot credentials configured. Using hardcoded defaults.' ); 283 return null; 284 } 285 286 try { 287 $environment = $this->container->get( EnvironmentInterface::class ); 288 $client = QPilotServiceFactory::create( 289 $environment->get_api_url(), 290 $token, 291 $site_id 292 ); 293 } catch ( \Exception $e ) { 294 Logger::error( 'Feature Flags', 'Failed to initialize QPilot client: ' . $e->getMessage() ); 295 return null; 296 } 297 298 // Fetch global and site-specific flags independently so one 299 // failure does not prevent the other from being used. 300 $global_flags = array(); 301 $global_success = false; 302 $site_flags = array(); 303 $site_success = false; 304 305 try { 306 $global_flags = $client->get_feature_flags(); 307 $global_success = true; 308 } catch ( \Exception $e ) { 309 Logger::error( 'Feature Flags', 'Failed to fetch global feature flags: ' . $e->getMessage() ); 310 } 311 312 try { 313 $site_flags = $client->get_site_feature_flags(); 314 $site_success = true; 315 } catch ( \Exception $e ) { 316 Logger::error( 'Feature Flags', 'Failed to fetch site feature flags: ' . $e->getMessage() ); 317 } 318 319 // If both calls failed, return null to fall back to hardcoded defaults. 320 if ( ! $global_success && ! $site_success ) { 321 Logger::error( 'Feature Flags', 'Both QPilot feature flag endpoints failed. Using hardcoded defaults.' ); 322 return null; 323 } 324 325 $all_flags = array_values( array_unique( array_merge( $global_flags, $site_flags ) ) ); 326 327 set_transient( $cache_key, $all_flags, 5 * MINUTE_IN_SECONDS ); 328 329 Logger::debug( 'Feature Flags', 'Resolved remote flags: ' . implode( ', ', $all_flags ) ); 330 331 return $all_flags; 249 332 } 250 333 -
autoship-cloud/trunk/app/Domain/PaymentIntegrationFactory.php
r3387754 r3462779 51 51 case 'stripe': 52 52 case 'stripe_sepa': 53 case 'fkwcs_stripe': 54 case 'fkwcs_stripe_ach': 55 case 'link': 53 56 return StripePaymentIntegration::build( $gateway_id, $settings ); 54 57 case 'nmi_gateway_woocommerce_credit_card': … … 65 68 return CyberSourceV2PaymentIntegration::build( $gateway_id, $settings ); 66 69 case 'square_credit_card': 70 case 'square_cash_app_pay': 67 71 return SquarePaymentIntegration::build( $gateway_id, $settings ); 68 72 case 'ppec_paypal': … … 76 80 case 'sagepaydirect': 77 81 return SagePaymentIntegration::build( $gateway_id, $settings ); 78 case 'fkwcs_stripe':79 case 'fkwcs_stripe_ach':80 return FunnelKitPaymentIntegration::build( $gateway_id, $settings );81 82 case 'airwallex_card': 82 83 return AirwallexPaymentIntegration::build( $gateway_id, $settings ); -
autoship-cloud/trunk/app/Domain/PaymentIntegrations/AuthorizeNetPaymentIntegration.php
r3303202 r3462779 9 9 namespace Autoship\Domain\PaymentIntegrations; 10 10 11 use Autoship\Domain\PaymentIntegration; 11 use Autoship\Domain\AbstractPaymentGateway; 12 use Autoship\Services\Logging\Logger; 12 13 use Autoship\Domain\PaymentMethodType; 13 14 use Exception; 15 use QPilotPaymentData; 16 use WC_Order; 17 use WC_Payment_Token; 14 18 15 19 /** … … 19 23 * @since 2.8.7 20 24 */ 21 class AuthorizeNetPaymentIntegration extends PaymentIntegration{25 class AuthorizeNetPaymentIntegration extends AbstractPaymentGateway { 22 26 23 27 /** … … 29 33 'authorize_net_cim_credit_card', 30 34 ); 35 36 /** 37 * Initializes the payment integration. 38 * 39 * @return void 40 */ 41 public function initialize(): void { 42 Logger::log( 'Authorize.Net Payment Integration', 'Initializing Authorize.Net payment integration.' ); 43 } 31 44 32 45 /** … … 86 99 return true; 87 100 } 101 102 /** 103 * Handles the SkyVerge add payment method transaction result filter. 104 * Adds the payment method to QPilot when a transaction is approved. 105 * 106 * @param array $result The transaction result. 107 * @param object $response The gateway API response. 108 * @param object $order The order object. 109 * @param object $client The gateway client instance. 110 * @return array The transaction result. 111 */ 112 public function add_transaction_payment_method( $result, $response, $order, $client ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed 113 $types = autoship_standard_gateway_id_types(); 114 115 if ( $response->transaction_approved() && ! isset( $types['authorize_net_cim_credit_card'] ) ) { 116 autoship_add_non_wc_token_payment_method( $response, $order, 'authorize_net_cim_credit_card' ); 117 } 118 119 return $result; 120 } 121 122 /** 123 * Get order payment data for QPilot. 124 * 125 * @param int $order_id The order ID. 126 * @param WC_Order $order The order object. 127 * 128 * @return ?QPilotPaymentData The payment data. 129 */ 130 public function get_order_payment_data( int $order_id, WC_Order $order ): ?QPilotPaymentData { 131 $token_string = $order->get_meta( '_wc_authorize_net_cim_credit_card_payment_token' ); 132 $customer_id = $order->get_meta( '_wc_authorize_net_cim_credit_card_customer_id' ); 133 134 if ( ! empty( $token_string ) && ! empty( $customer_id ) ) { 135 $payment_data = new QPilotPaymentData(); 136 $card_type = $order->get_meta( '_wc_authorize_net_cim_credit_card_card_type' ); 137 $last_four = $order->get_meta( '_wc_authorize_net_cim_credit_card_account_four' ); 138 139 // Authnet Stores Expiration in YY-MM format so we need to adjust for Autoship 140 // Expiration in format 23-02 should be 0223. 141 $expiry_date = $order->get_meta( '_wc_authorize_net_cim_credit_card_card_expiry_date' ); 142 $expiration = explode( '-', $expiry_date ); 143 144 $payment_data->description = isset( $expiration[1] ) ? sprintf( '%s ending in %s (expires %s)', ucfirst( $card_type ), $last_four, $expiration[1] . '/' . $expiration[0] ) : sprintf( '%s ending in %s', ucfirst( $card_type ), $last_four ); 145 $payment_data->type = 'AuthorizeNet'; 146 $payment_data->gateway_payment_id = $token_string; 147 $payment_data->gateway_customer_id = $customer_id; 148 $payment_data->last_four = $last_four; 149 $payment_data->expiration = isset( $expiration[1] ) ? $expiration[1] . $expiration[0] : null; 150 151 return $payment_data; 152 } 153 154 return null; 155 } 156 157 /** 158 * Add payment method data for QPilot. 159 * 160 * @param array $payment_method_data The payment method data. 161 * @param string $type The payment method type. 162 * @param WC_Payment_Token $token The payment token. 163 * @return array The modified payment method data. 164 */ 165 public function add_payment_method( array $payment_method_data, string $type, WC_Payment_Token $token ): array { 166 // Apply the test filters. 167 $test_ext = apply_filters( 'autoship_payment_method_sandbox_metadata_field_test_ext', '_test', 'authorize_net_cim_credit_card' ); 168 169 // ex. _wc_authorize_net_cim_credit_card_payment_tokens_test or _wc_authorize_net_cim_credit_card_payment_tokens. 170 $meta_ext = apply_filters( 'autoship_payment_method_sandbox_metadata_field_ext', '', $test_ext, 'authorize_net_cim_credit_card' ); 171 172 // Authnet uses the customer id from user meta as Gateway Customer ID. 173 $user_id = $token->get_user_id(); 174 $payment_method_data['gatewayCustomerId'] = get_user_meta( $user_id, 'wc_authorize_net_cim_customer_profile_id' . $meta_ext, true ); 175 176 return $payment_method_data; 177 } 178 179 /* i. authorize.net Payment Method - Functions moved to src/payments-authorize-net.php */ 180 181 /** 182 * Adds the Skyverge Payment Method to QPilot After Checkout 183 * Fired when a payment is processed for an order. 184 * 185 * @param WC_Order $order The WC Order object. 186 * @param object $gateway The payment gateway instance. 187 */ 188 public function add_skyverge_payment_method( WC_Order $order, object $gateway ) { 189 190 // Get the types to see if this is legacy or new. 191 $types = autoship_standard_gateway_id_types(); 192 193 if ( ! isset( $types[ $gateway->id ] ) ) { 194 return; 195 } 196 197 // Retrieve the Token based off the token id & run it through the partial token filter. 198 $token = autoship_get_related_tokenized_id( $order->payment->token, true ); 199 200 // Check for failed token retrieval. 201 if ( is_null( $token ) || empty( $token ) || ! $token ) { 202 return; 203 } 204 205 $token = autoship_tokenize_non_fully_implemented_token_classes( $token ); 206 207 // Upsert the Token to the API. 208 autoship_add_general_payment_method( $token ); 209 } 210 211 /** 212 * Fires after a new Skyverge payment method is added by a customer. 213 * 214 * @param string $token new token. 215 */ 216 public function add_my_account_skyverge_payment_method( string $token ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed 217 218 if ( is_checkout() ) { 219 return; 220 } 221 222 // Retrieve the Token based off the token id & run it through the partial token filter. 223 $token = autoship_get_related_tokenized_id( $token, true ); 224 225 // Check for failed token retrieval. 226 if ( is_null( $token ) || empty( $token ) || ! $token ) { 227 return; 228 } 229 230 $token = autoship_tokenize_non_fully_implemented_token_classes( $token ); 231 232 autoship_add_general_payment_method( $token ); 233 } 234 235 /** 236 * Authorize.Net Gateway: Fires additional autoship actions after a payment method is saved. 237 * 238 * @param string $token_id new token ID. 239 */ 240 public function after_save_authorize_net_payment_method_notice( string $token_id ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed 241 242 // Get the types to see if this is legacy or new Authnet. 243 $types = autoship_standard_gateway_id_types(); 244 245 // Only Display Notice if this is the legacy Authnet Gateway. 246 if ( ! isset( $types['authorize_net_cim_credit_card'] ) ) { 247 autoship_after_save_payment_method_autoship_action_notice( $token_id, 'authorize_net_cim_credit_card', '' ); 248 } 249 } 250 251 /** 252 * Delete payment method validation. 253 * 254 * @param bool $valid Current validation status. 255 * @param string $type The payment method type. 256 * @param WC_Payment_Token $token The payment token. 257 * @param object $method The QPilot payment method. 258 * @return bool Whether the deletion is valid. 259 */ 260 public function delete_payment_method( bool $valid, string $type, WC_Payment_Token $token, object $method ): bool { 261 if ( 'AuthorizeNet' === $type ) { 262 // Apply the test filters. 263 $test_ext = apply_filters( 'autoship_payment_method_sandbox_metadata_field_test_ext', '_test', 'authorize_net_cim_credit_card' ); 264 $meta_ext = apply_filters( 'autoship_payment_method_sandbox_metadata_field_ext', '', $test_ext, 'authorize_net_cim_credit_card' ); 265 266 $user_id = $token->get_user_id(); 267 $customer_id = get_user_meta( $user_id, 'wc_authorize_net_cim_customer_profile_id' . $meta_ext, true ); 268 269 return ( $method->gatewayCustomerId === $customer_id && $method->gatewayPaymentId === $token->get_token() ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 270 } 271 272 return $valid; 273 } 274 275 /** 276 * Add metadata to payment. 277 * 278 * @param array $payment_meta The payment metadata. 279 * @param WC_Order $order The order object. 280 * @param array $payment_method The payment method. 281 * @return array The updated payment metadata. 282 */ 283 public function add_metadata( array $payment_meta, WC_Order $order, array $payment_method ): array { 284 $expiration = $payment_method['expiration'] ?? ''; 285 $exp_year = ! empty( $expiration ) && ( strlen( $expiration ) > 2 ) ? substr( $expiration, - 2 ) : $expiration; 286 $exp_month = ! empty( $expiration ) && ( strlen( $expiration ) > 2 ) ? substr( $expiration, 0, 2 ) : $expiration; 287 288 $metadata = array( 289 '_wc_authorize_net_cim_credit_card_trans_id' => $payment_meta['transId'], 290 '_wc_authorize_net_cim_credit_card_authorization_code' => $payment_meta['authCode'], 291 '_wc_authorize_net_cim_credit_card_customer_id' => $payment_method['gatewayCustomerId'], 292 '_wc_authorize_net_cim_credit_card_account_four' => $payment_method['lastFourDigits'], 293 '_wc_authorize_net_cim_credit_card_card_expiry_date' => $exp_year . '-' . $exp_month, 294 '_wc_authorize_net_cim_credit_card_charge_captured' => 'yes', 295 ); 296 297 $order->set_transaction_id( $payment_meta['transId'] ); 298 299 foreach ( $metadata as $key => $value ) { 300 $order->update_meta_data( $key, $value ); 301 } 302 303 $order->save(); 304 305 return $payment_meta; 306 } 307 308 /** 309 * Display apply to all orders button. 310 * 311 * @param array $list_item The list item data. 312 * @param mixed $payment_token The payment token (WC_Payment_Token or SkyVerge payment profile). 313 * @return string The button HTML. 314 */ 315 public function display_apply_to_all_orders_button( array $list_item, $payment_token ): array { 316 return autoship_display_apply_payment_method_to_all_scheduled_orders_skyverge_btn( $list_item, $payment_token, null, 'authorize_net_cim_credit_card' ); 317 } 88 318 } -
autoship-cloud/trunk/app/Domain/PaymentIntegrations/PayPalPaymentIntegration.php
r3352156 r3462779 9 9 namespace Autoship\Domain\PaymentIntegrations; 10 10 11 use Autoship\Domain\PaymentIntegration; 11 use Autoship\Domain\AbstractPaymentGateway; 12 use Autoship\Services\Logging\Logger; 12 13 use Autoship\Domain\PaymentMethodType; 13 14 use Exception; 15 use WC_Payment_Tokens; 16 use QPilotPaymentData; 17 use WC_Order; 18 use RuntimeException; 19 use WC_Payment_Token; 14 20 15 21 /** … … 19 25 * @since 2.8.7 20 26 */ 21 class PayPalPaymentIntegration extends PaymentIntegration { 27 class PayPalPaymentIntegration extends AbstractPaymentGateway { 28 22 29 /** 23 30 * The allowed payment gateways for this integration. … … 29 36 'ppec_paypal', 30 37 ); 38 39 /** 40 * Initializes the payment integration. 41 * 42 * @return void 43 */ 44 public function initialize(): void { 45 Logger::log( 'PayPal Payment Integration', 'Initializing PayPal payment integration.' ); 46 } 31 47 32 48 /** … … 50 66 $integration->set_authorize_only( false ); 51 67 52 $environment = 'sandbox' === $settings['environment']? 'test' : 'live';68 $environment = 'sandbox' === ( $settings['environment'] ?? '' ) ? 'test' : 'live'; 53 69 54 70 if ( 'test' === $environment ) { … … 81 97 } 82 98 83 // NMI should containthe username, password and signature.99 // PayPal requires the username, password and signature. 84 100 if ( empty( $this->get_api_account() ) || empty( $this->get_api_key_1() ) || empty( $this->get_api_key_2() ) ) { 85 101 return false; … … 88 104 return true; 89 105 } 106 107 /** 108 * Get order payment data for QPilot. 109 * 110 * @param int $order_id The order ID. 111 * @param WC_Order $order The order object. 112 * 113 * @return ?QPilotPaymentData The payment data. 114 */ 115 public function get_order_payment_data( int $order_id, WC_Order $order ): ?QPilotPaymentData { 116 // PayPal Express Checkout stores the billing agreement ID. 117 $payment_agreement_id = $order->get_meta( '_ppec_billing_agreement_id' ); 118 119 if ( ! empty( $payment_agreement_id ) ) { 120 $payment_data = new QPilotPaymentData(); 121 $card_type = 'PayPal'; 122 $last_four = substr( $payment_agreement_id, -4 ); 123 $payment_data->description = sprintf( '%s ending in %s', ucfirst( $card_type ), $last_four ); 124 $payment_data->type = 'PayPal'; 125 $payment_data->gateway_payment_id = $payment_agreement_id; 126 127 return $payment_data; 128 } 129 130 $gateway_payment_token = array(); 131 $gateway_customer_id = null; 132 $gateway_payment_token = null; 133 $user_id = $order->get_user_id(); 134 $wc_tokens = WC_Payment_Tokens::get_customer_tokens( $user_id, 'ppcp-gateway' ); 135 136 if ( $wc_tokens ) { 137 $gateway_customer_id = get_user_meta( $user_id, '_ppcp_target_customer_id', true ); 138 if ( ! $gateway_customer_id ) { 139 $gateway_customer_id = get_user_meta( $user_id, 'ppcp_customer_id', true ); 140 } 141 142 $customer_tokens = autoship_get_paypal_payments_tokens_for_customer( $gateway_customer_id ); 143 144 $customer_token_ids = array(); 145 foreach ( $customer_tokens as $customer_token ) { 146 $customer_token_ids[] = $customer_token['id']; 147 } 148 149 foreach ( $wc_tokens as $token ) { 150 if ( ! in_array( $token->get_token(), $customer_token_ids, true ) ) { 151 continue; 152 } 153 $gateway_payment_token = $token->get_token(); 154 break; 155 } 156 } else { 157 // Get payment data from PayPal if not found in WP. 158 $order_id_value = $order->get_meta( \WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway::ORDER_ID_META_KEY ); 159 $order_id = $order_id_value ? $order_id_value : wc_clean( wp_unslash( $_POST['paypal_order_id'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized 160 $order_endpoint = \WooCommerce\PayPalCommerce\PPCP::container()->get( 'api.endpoint.order' ); 161 162 if ( is_string( $order_id ) && $order_id ) { 163 try { 164 $ordder = $order_endpoint->order( $order_id ); 165 } catch ( RuntimeException ) { 166 throw new Exception( esc_html( __( 'Could not retrieve PayPal order:' ) ), 'woocommerce-paypal-payments' ); 167 } 168 169 $payment_source = $ordder->payment_source(); 170 assert( $payment_source instanceof \WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource ); 171 $payment_vault_attributes = $payment_source->properties()->attributes->vault ?? null; 172 if ( $payment_vault_attributes ) { 173 $gateway_customer_id = $payment_vault_attributes->customer->id ?? ''; 174 $gateway_payment_token = $payment_vault_attributes->id ?? ''; 175 } 176 } 177 } 178 179 if ( ! empty( $gateway_payment_token ) ) { 180 $payment_data = new QPilotPaymentData(); 181 $payment_data->description = 'PayPal Payments'; 182 $payment_data->type = 'PayPalV3'; 183 $payment_data->gateway_payment_id = $gateway_payment_token; 184 $payment_data->gateway_customer_id = $gateway_customer_id; 185 $payment_data->gateway_payment_type = 25; 186 187 return $payment_data; 188 } 189 190 return null; 191 } 192 193 /** 194 * Add payment method data for QPilot. 195 * 196 * @param array $payment_method_data The payment method data. 197 * @param string $type The payment method type. 198 * @param WC_Payment_Token $token The payment token. 199 * @return array The modified payment method data. 200 */ 201 public function add_payment_method( array $payment_method_data, string $type, WC_Payment_Token $token ): array { 202 // PayPal Express Checkout doesn't use a customer ID in the same way as credit card gateways. 203 // The billing agreement ID serves as both the payment token and identifier. 204 // PayPal Payments adjustments. 205 if ( 'PayPalV3' === $type ) { 206 $gateway = $token->get_gateway_id(); 207 $wc_customer_id = $token->get_user_id(); 208 209 if ( 'ppcp-credit-card-gateway' === $gateway ) { 210 $payment_method_data['gatewayPaymentType'] = 26; 211 } 212 213 if ( 'ppcp-gateway' === $gateway ) { 214 $payment_method_data['gatewayPaymentType'] = 25; 215 $payment_method_data['description'] = 'PayPal Payments'; 216 } 217 218 $gateway_customer_id = get_user_meta( $wc_customer_id, '_ppcp_target_customer_id', true ); 219 if ( ! $gateway_customer_id ) { 220 $gateway_customer_id = get_user_meta( $wc_customer_id, 'ppcp_customer_id', true ); 221 } 222 223 if ( $gateway_customer_id ) { 224 $payment_method_data['gatewayCustomerId'] = $gateway_customer_id; 225 } 226 } 227 228 return $payment_method_data; 229 } 230 231 /** 232 * Delete payment method validation. 233 * 234 * @param bool $valid Current validation status. 235 * @param string $type The payment method type. 236 * @param WC_Payment_Token $token The payment token. 237 * @param object $method The QPilot payment method. 238 * @return bool Whether the deletion is valid. 239 */ 240 public function delete_payment_method( bool $valid, string $type, WC_Payment_Token $token, object $method ): bool { 241 if ( 'PayPal' === $type ) { 242 // PayPal uses the billing agreement ID as the gateway payment ID. 243 return ( $method->gatewayPaymentId === $token->get_token() ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 244 } 245 246 if ( 'PayPalV3' === $type ) { 247 $gateway_customer_id = get_user_meta( $token->get_user_id(), '_ppcp_target_customer_id', true ); 248 if ( ! $gateway_customer_id ) { 249 $gateway_customer_id = get_user_meta( $token->get_user_id(), 'ppcp_customer_id', true ); 250 } 251 252 return ( $method->gatewayCustomerId === $gateway_customer_id && $method->gatewayPaymentId === $token->get_token() ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 253 } 254 255 return $valid; 256 } 257 258 /** 259 * Adds Support for the PayPal Payments (PayPal V3) 260 * 261 * @param array $types The current types array. 262 * 263 * @return array The filtered types 264 */ 265 public function add_paypal_v3_token_support( $types ) { 266 267 if ( class_exists( '\WooCommerce\PayPalCommerce\PPCP' ) ) { 268 $ppcp_settings = \WooCommerce\PayPalCommerce\PPCP::container()->get( 'wcgateway.settings' ); 269 if ( $ppcp_settings->has( 'vault_enabled' ) && $ppcp_settings->get( 'vault_enabled' ) ) { 270 $types['ppcp-gateway'] = 'PayPalV3'; 271 } 272 273 if ( $ppcp_settings->has( 'vault_enabled_dcc' ) && $ppcp_settings->get( 'vault_enabled_dcc' ) ) { 274 $types['ppcp-credit-card-gateway'] = 'PayPalV3'; 275 } 276 } 277 278 return $types; 279 } 280 281 /** 282 * Add metadata to payment. 283 * 284 * @param array $payment_meta The payment metadata. 285 * @param WC_Order $order The order object. 286 * @param array $payment_method The payment method. 287 * @return array The updated payment metadata. 288 */ 289 public function add_metadata( array $payment_meta, WC_Order $order, array $payment_method ): array { 290 // Set the status for the transaction. 291 $status = 'Completed' === ( $payment_meta['PAYMENTSTATUS'] ?? '' ) ? $payment_meta['PAYMENTSTATUS'] : ( $payment_meta['PAYMENTSTATUS'] ?? '' ) . '_' . ( $payment_meta['PENDINGREASON'] ?? '' ); 292 293 $metadata = array( 294 '_woo_pp_txnData' => array( 295 'refundable_txns' => array( 296 array( 297 'txnID' => $payment_meta['TRANSACTIONID'] ?? '', 298 'amount' => $order->get_total(), 299 'status' => $status, 300 ), 301 ), 302 ), 303 ); 304 305 $order->set_transaction_id( $payment_meta['TRANSACTIONID'] ?? '' ); 306 307 foreach ( $metadata as $key => $value ) { 308 $order->update_meta_data( $key, $value ); 309 } 310 311 $order->save(); 312 313 return $payment_meta; 314 } 315 316 /** 317 * Adds the refund metadata for PayPal v2 318 * 319 * @param array $payment_meta The gateway response data. 320 * @param WC_Order $order The wc order. 321 * @param array $payment_method The associated payment method data. 322 */ 323 public function add_adjusted_gateway_metadata_ppep_paypal( $payment_meta, $order, $payment_method ) { 324 325 $order->update_meta_data( 'payment_token_id', $payment_method['gatewayPaymentId'] ); 326 $order->update_meta_data( '_ppcp_paypal_order_id', $payment_meta['id'] ); 327 $order->update_meta_data( '_ppcp_paypal_intent', 'CAPTURE' ); 328 $order->save(); 329 330 /** 331 * Check if Test Mode or Live 332 * 333 * @HACK Need better way to test if this is a live or test payment process. 334 */ 335 if ( isset( $payment_meta['links'] ) && ! empty( $payment_meta['links'] ) && ( strpos( $payment_meta['links'][0]['href'], 'https://api.sandbox.paypal.com' ) !== false ) ) { 336 $order->update_meta_data( '_ppcp_paypal_payment_mode', 'sandbox' ); 337 $order->save(); 338 } 90 339 } 340 } -
autoship-cloud/trunk/app/Domain/PaymentIntegrations/SquarePaymentIntegration.php
r3352156 r3462779 9 9 namespace Autoship\Domain\PaymentIntegrations; 10 10 11 use Autoship\Domain\ PaymentIntegration;11 use Autoship\Domain\AbstractPaymentGateway; 12 12 use Autoship\Domain\PaymentMethodType; 13 use Autoship\Services\Logging\Logger; 13 14 use Exception; 15 use QPilotPaymentData; 16 use WC_Order; 17 use WC_Payment_Token; 14 18 15 19 /** … … 19 23 * @since 2.8.7 20 24 */ 21 class SquarePaymentIntegration extends PaymentIntegration { 25 class SquarePaymentIntegration extends AbstractPaymentGateway { 26 27 /** 28 * Indicates if integration has been initialized. 29 * 30 * @var bool 31 */ 32 private static bool $initialized = false; 33 34 /** 35 * Initializing. 36 * 37 * @return void 38 */ 39 public function initialize(): void { 40 if ( self::$initialized ) { 41 return; 42 } 43 44 Logger::trace( 'Square Initialize', 'Initializing filters and actions for Square' ); 45 46 // Hook for adding the payment method. 47 add_action( 'wc_payment_gateway_square_payment_method_added', array( $this, 'autoship_after_save_square_credit_card_payment_method_notice' ), 10, 3 ); 48 49 // Hook for displaying apply payment method to all scheduled orders button. 50 add_filter( 'wc_square_my_payment_methods_table_method_actions', array( $this, 'autoship_display_apply_payment_method_to_all_scheduled_orders_square_btn' ), 10, 3 ); 51 52 // Square force save payment method filter. 53 add_filter( 'wc_square_credit_card_force_save_source', array( self::class, 'force_save_source' ) ); 54 55 // Square create customer request filter. 56 add_filter( 'wc_square_create_customer_request', array( self::class, 'filter_customer_request' ), 30, 2 ); 57 58 // Hook for adding gateway metadata during scheduled order updates. 59 add_action( 'autoship_update_scheduled_orders_on_processing_square_gateway', array( $this, 'add_adjusted_gateway_metadata' ), 10, 3 ); 60 61 // Hook for deleting the payment method. 62 add_action( 'wc_payment_gateway_square_credit_card_payment_method_deleted', array( $this, 'delete_payment_method' ), 10, 2 ); 63 64 self::$initialized = true; 65 } 22 66 23 67 /** … … 28 72 private static array $allowed = array( 29 73 'square_credit_card', 74 'square_cash_app_pay', 30 75 ); 31 76 … … 59 104 $integration->set_test_mode( true ); 60 105 } else { 61 // The option table said sandbox_token instead of production_token. Need to validate this. 62 $integration->set_api_key_1( $options['sandbox_token'] ?? '' ); 106 $integration->set_api_key_1( $options['production_token'] ?? '' ); 63 107 $integration->set_api_key_2( $options['production_location_id'] ?? '' ); 64 108 $integration->set_test_mode( false ); … … 89 133 return true; 90 134 } 135 136 /** 137 * Get order payment data for QPilot. 138 * 139 * @param int $order_id The order ID. 140 * @param WC_Order $order The order object. 141 * 142 * @return ?QPilotPaymentData The payment data. 143 */ 144 public function get_order_payment_data( int $order_id, WC_Order $order ): ?QPilotPaymentData { 145 $payment_method = $order->get_payment_method(); 146 147 if ( ! in_array( $payment_method, self::$allowed, true ) ) { 148 return null; 149 } 150 151 $token_id = $order->get_meta( '_square_credit_card_payment_token' ); 152 $customer_id = $order->get_meta( '_square_customer_id' ); 153 154 if ( ! empty( $token_id ) ) { 155 $payment_data = new QPilotPaymentData(); 156 $card_type = $order->get_meta( '_wc_square_credit_card_card_type' ); 157 $last_four = $order->get_meta( '_wc_square_credit_card_account_four' ); 158 $expiry_date = $order->get_meta( '_wc_square_credit_card_card_expiry_date' ); 159 160 $expiry_date = explode( '-', $expiry_date ); 161 $expiry_date[0] = strlen( $expiry_date[0] ) > 2 ? substr( $expiry_date[0], - 2 ) : $expiry_date[0]; 162 $payment_data->description = sprintf( '%s ending in %s (expires %s)', ucfirst( $card_type ), $last_four, $expiry_date[1] . '/' . $expiry_date[0] ); 163 $payment_data->type = 'Square'; 164 $payment_data->gateway_payment_id = $token_id; 165 $payment_data->gateway_customer_id = $customer_id; 166 $payment_data->last_four = $last_four; 167 168 // Get Expiration in MMYY format for Qpilot. 169 $expiration = $expiry_date[1] . $expiry_date[0]; 170 $payment_data->expiration = $expiration; 171 172 return $payment_data; 173 } 174 175 return null; 176 } 177 178 /** 179 * Adds the Square credit card Payment Method to QPilot 180 * Does not use the woocommerce_payment_tokens tables 181 * 182 * @param array $result The result array. 183 * @param \SV_WC_Payment_Gateway_API_Create_Payment_Token_Response $response The API response object. 184 * @param \WC_Order $order The WC Order object. 185 * @param \SV_WC_Payment_Gateway_Direct $client The Direct Gateway instance. 186 * 187 * @return mixed 188 * @see wc_payment_gateway_' . $this->get_id() . '_add_payment_method_transaction_result hook. 189 * 190 * Result: { 191 * @type string $message notice message to render 192 * @type bool $success true to redirect to my account, false to stay on page 193 * } 194 */ 195 public function add_payment_method_data( $result, $response, $order, $client ) { 196 // Check if the transaction has been approved. 197 if ( $response->transaction_approved() ) { 198 autoship_add_non_wc_token_payment_method( $response, $order, 'square_credit_card' ); 199 } 200 201 return $result; 202 } 203 204 /** 205 * Add payment method data for QPilot. 206 * 207 * @param array $payment_method_data The payment method data. 208 * @param string $type The payment method type. 209 * @param WC_Payment_Token $token The payment token. 210 * @return array The modified payment method data. 211 */ 212 public function add_payment_method( array $payment_method_data, string $type, WC_Payment_Token $token ): array { 213 $ext_type = 'square_credit_card'; 214 215 // Apply the test filters. 216 $test_ext = apply_filters( 'autoship_payment_method_sandbox_metadata_field_test_ext', '_test', $ext_type ); 217 // ex. _wc_authorize_net_cim_credit_card_payment_tokens_test or _wc_authorize_net_cim_credit_card_payment_tokens. 218 $meta_ext = apply_filters( 'autoship_payment_method_sandbox_metadata_field_ext', '', $test_ext, $ext_type ); 219 220 $user_id = $token->get_user_id(); 221 $payment_method_data['gatewayCustomerId'] = get_user_meta( $user_id, 'wc_square_customer_id' . $meta_ext, true ); 222 223 return $payment_method_data; 224 } 225 226 /** 227 * Square_credit_card Gateway: Fires additional autoship actions after a payment method is saved. 228 * 229 * @param string $token_id new token ID. 230 * @param int $user_id user ID. 231 * @param \SV_WC_Payment_Gateway_API_Response $response API response object. 232 */ 233 public function autoship_after_save_square_credit_card_payment_method_notice( $token_id, $user_id, $response ): void { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed 234 autoship_after_save_payment_method_autoship_action_notice( $token_id, 'square_credit_card', '' ); 235 } 236 237 /** 238 * Square 239 * Non-Standard skyverge framework Gateways actions 240 * Outputs the apply action button after each payment method 241 * 242 * @param array $list_item The list item array. 243 * @param \SV_WC_Payment_Gateway_Payment_Token $payment_token The payment token object. 244 * @param \SV_WC_Payment_Gateway_My_Payment_Methods $instance The instance of the My Payment Methods class. 245 */ 246 public function autoship_display_apply_payment_method_to_all_scheduled_orders_square_btn( $list_item, $payment_token, $instance ) { 247 return autoship_display_apply_payment_method_to_all_scheduled_orders_skyverge_btn( $list_item, $payment_token, $instance, 'square_credit_card' ); 248 } 249 250 /** 251 * Delete payment method validation. 252 * 253 * @param bool $valid Current validation status. 254 * @param string $type The payment method type. 255 * @param WC_Payment_Token $token The payment token. 256 * @param object $method The QPilot payment method. 257 * @return bool Whether the deletion is valid. 258 */ 259 public function delete_payment_method( bool $valid, string $type, WC_Payment_Token $token, object $method ): bool { 260 $token_id = $token->get_token(); 261 $user_id = $token->get_user_id(); 262 263 return autoship_delete_non_wc_token_payment_method( $token_id, null, 'Square', $user_id ); 264 } 265 266 /** 267 * Add metadata for Square. 268 * 269 * @param array $payment_meta The payment metadata. 270 * @param WC_Order $order The order object. 271 * @return void 272 */ 273 public function add_adjusted_gateway_metadata( array $payment_meta, WC_Order $order ): void { 274 // Set the status for the transaction. 275 $payment = $payment_meta['payment']; 276 277 // Adjust Card Expiration. 278 $exp = substr( $payment['card_details']['card']['exp_year'], - 2 ); 279 $exp .= '-' . $payment['card_details']['card']['exp_month']; 280 281 // Format the date. 282 $date = autoship_get_datetime( $payment['created_at'] ); 283 284 $metadata = array( 285 '_wc_square_credit_card_square_order_id' => $payment['order_id'], 286 '_wc_square_credit_card_square_location_id' => $payment['location_id'], 287 '_wc_square_credit_card_card_type' => strtolower( $payment['card_details']['card']['card_brand'] ), 288 '_wc_square_credit_card_card_expiry_date' => $exp, 289 '_wc_square_credit_card_charge_captured' => 'yes', 290 '_wc_square_credit_card_authorization_amount' => $payment['approved_money']['amount'], 291 '_wc_square_credit_card_account_four' => $payment['card_details']['card']['last_4'], 292 '_wc_square_credit_card_customer_id' => $payment['customer_id'], 293 '_wc_square_credit_card_trans_date' => $date->format( 'Y-m-d H:i:s' ), 294 '_wc_square_credit_card_trans_id' => $payment['id'], 295 '_wc_square_credit_card_authorization_code' => $payment['id'], 296 '_wc_square_credit_card_square_version' => WC_SQUARE_PLUGIN_VERSION, 297 ); 298 299 $order->set_transaction_id( $payment['id'] ); 300 301 foreach ( $metadata as $key => $value ) { 302 $order->update_meta_data( $key, $value ); 303 } 304 305 $order->save(); 306 } 307 308 /** 309 * Static helper method for Square force save compatibility. 310 * 311 * @param bool $val The current value. 312 * @return bool 313 */ 314 public static function force_save_source( bool $val ): bool { 315 if ( autoship_cart_has_valid_autoship_items() ) { 316 return true; 317 } 318 return $val; 319 } 320 321 /** 322 * Static helper method for Square customer request filtering. 323 * 324 * @param array $request The Square customer request. 325 * @param WC_Order $order The WC Order object. 326 * @return array 327 */ 328 public static function filter_customer_request( array $request, WC_Order $order ): array { 329 if ( autoship_order_total_scheduled_items( $order ) > 0 ) { 330 // Flag as a recurring payment. 331 $request['note'] = 'Autoship recurring payment customer'; 332 } 333 return $request; 334 } 91 335 } -
autoship-cloud/trunk/app/Domain/PaymentIntegrations/StripePaymentIntegration.php
r3299545 r3462779 9 9 namespace Autoship\Domain\PaymentIntegrations; 10 10 11 use Autoship\Domain\PaymentIntegration; 11 use Autoship\Domain\AbstractPaymentGateway; 12 use Autoship\Services\Logging\Logger; 12 13 use Autoship\Domain\PaymentMethodType; 13 14 use Exception; 15 use QPilotPaymentData; 16 use WC_Order; 17 use WC_Payment_Token; 18 use WC_Stripe_API; 19 use WC_Payment_Token_CC; 20 use WC_Stripe_Helper; 14 21 15 22 /** … … 19 26 * @since 2.8.7 20 27 */ 21 class StripePaymentIntegration extends PaymentIntegration { 28 class StripePaymentIntegration extends AbstractPaymentGateway { 29 30 /** 31 * Initializing. 32 * 33 * @return void 34 */ 35 public function initialize(): void { 36 Logger::log( 'Stripe Payment Integration', 'Initializing Stripe payment integration.' ); 37 } 22 38 23 39 /** … … 29 45 'stripe', 30 46 'stripe_sepa', 47 'fkwcs_stripe', 48 'link', 31 49 ); 32 50 … … 50 68 $integration->set_method_name( $settings['title'] ?? '' ); 51 69 $integration->set_authorize_only( false ); 70 71 if ( 'fkwcs_stripe' === $gateway_id ) { 72 return self::build_funnelkit_integration( $integration ); 73 } 52 74 53 75 $environment = 'yes' === $settings['testmode'] ? 'test' : 'live'; … … 67 89 68 90 /** 91 * Build FunnelKit Stripe integration with specific configuration. 92 * 93 * @param StripePaymentIntegration $integration The integration instance. 94 * @return StripePaymentIntegration 95 */ 96 private static function build_funnelkit_integration( StripePaymentIntegration $integration ): StripePaymentIntegration { 97 $funnelkit_mode = get_option( 'fkwcs_mode', 'test' ); 98 $environment = 'test' === $funnelkit_mode ? 'test' : 'live'; 99 100 if ( 'test' === $environment ) { 101 $funnelkit_public_key = get_option( 'fkwcs_test_pub_key', '' ); 102 $funnelkit_secret_key = get_option( 'fkwcs_test_secret_key', '' ); 103 104 $integration->set_api_key_1( $funnelkit_public_key ?? '' ); 105 $integration->set_api_key_2( $funnelkit_secret_key ?? '' ); 106 $integration->set_test_mode( true ); 107 } else { 108 $funnelkit_public_key = get_option( 'fkwcs_pub_key', '' ); 109 $funnelkit_secret_key = get_option( 'fkwcs_secret_key', '' ); 110 111 $integration->set_api_key_1( $funnelkit_public_key ?? '' ); 112 $integration->set_api_key_2( $funnelkit_secret_key ?? '' ); 113 $integration->set_test_mode( false ); 114 } 115 116 return $integration; 117 } 118 119 /** 69 120 * Gets the value indicating if the payment integration is valid or not. 70 121 * … … 86 137 return true; 87 138 } 139 140 /** 141 * Get order payment data for QPilot. 142 * 143 * @param int $order_id The order ID. 144 * @param WC_Order $order The order object. 145 * 146 * @return ?QPilotPaymentData The payment data. 147 */ 148 public function get_order_payment_data( int $order_id, WC_Order $order ): ?QPilotPaymentData { 149 $payment_method = $order->get_payment_method(); 150 151 if ( 'fkwcs_stripe' === $payment_method ) { 152 return $this->get_fkwcs_order_payment_data( $order ); 153 } 154 155 // Stripe version >= 4.0.0. 156 $token_id = $order->get_meta( '_stripe_source_id' ); 157 158 // Stripe version < 4.0.0. 159 if ( empty( $token_id ) ) { 160 $token_id = $order->get_meta( '_stripe_card_id' ); 161 } 162 163 $customer_id = $order->get_meta( '_stripe_customer_id' ); 164 165 if ( ! empty( $token_id ) && ! empty( $customer_id ) ) { 166 167 $token = autoship_get_related_tokenized_id( $token_id ); 168 169 if ( ! empty( $token ) ) { 170 171 $payment_data = new QPilotPaymentData(); 172 $payment_data->description = $token->get_display_name(); 173 $payment_data->type = 'Stripe'; 174 $payment_data->gateway_payment_id = $token->get_token(); 175 $payment_data->gateway_customer_id = $customer_id; 176 177 if ( method_exists( $token, 'get_last4' ) && method_exists( $token, 'get_expiry_month' ) && method_exists( $token, 'get_expiry_year' ) ) { 178 $payment_data->last_four = $token->get_last4(); 179 $payment_data->expiration = $token->get_expiry_month() . substr( $token->get_expiry_year(), -2 ); 180 } 181 182 // Stripe Link. 183 if ( 'link' === $token->get_type() ) { 184 $payment_data->gateway_payment_type = 32; 185 } else { 186 $payment_data->gateway_payment_type = 7; 187 } 188 189 return $payment_data; 190 } else { 191 // Try to fetch payment data from Stripe API. 192 return $this->get_payment_method_data_by_id( $token_id, $customer_id ); 193 } 194 } 195 196 return null; 197 } 198 199 /** 200 * Get FunnelKit Stripe order payment data. 201 * 202 * @param WC_Order $order The order object. 203 * @return ?QPilotPaymentData The payment data. 204 */ 205 private function get_fkwcs_order_payment_data( WC_Order $order ): ?QPilotPaymentData { 206 $token_id = $order->get_meta( '_fkwcs_source_id' ); 207 $customer_id = $order->get_meta( '_fkwcs_customer_id' ); 208 209 if ( ! empty( $token_id ) && ! empty( $customer_id ) ) { 210 $token = autoship_get_related_tokenized_id( $token_id ); 211 212 if ( ! empty( $token ) ) { 213 $expiration = $token->get_expiry_month() . substr( $token->get_expiry_year(), -2 ); 214 $payment_data = new QPilotPaymentData(); 215 216 $payment_data->description = $token->get_display_name(); 217 $payment_data->type = 'Stripe'; 218 $payment_data->gateway_payment_id = $token->get_token(); 219 $payment_data->gateway_customer_id = $customer_id; 220 $payment_data->last_four = $token->get_last4(); 221 $payment_data->expiration = $expiration; 222 $payment_data->gateway_payment_type = 7; 223 224 return $payment_data; 225 } 226 } 227 228 return null; 229 } 230 231 /** 232 * Get payment method data by ID from Stripe API. 233 * 234 * @param string $payment_method_id The payment method ID. 235 * @param string $customer_id The Stripe customer ID. 236 * @return ?QPilotPaymentData The payment data. 237 */ 238 public function get_payment_method_data_by_id( string $payment_method_id, string $customer_id ): ?QPilotPaymentData { 239 if ( class_exists( 'WC_Stripe_API' ) ) { 240 $response = WC_Stripe_API::get_payment_method( $payment_method_id ); 241 if ( ! empty( $response->error ) || is_wp_error( $response ) ) { 242 return null; 243 } 244 if ( empty( $response->type ) || 'card' !== $response->type ) { 245 return null; 246 } 247 $exp_year = substr( $response->card->exp_year, - 2 ); 248 $expiration = $response->card->exp_month . $exp_year; 249 $description = sprintf( /* translators: 1: credit card type 2: last 4 digits 3: expiry month 4: expiry year */ __( '%1$s ending in %2$s (expires %3$s/%4$s)', 'woocommerce' ), wc_get_credit_card_type_label( $response->card->brand ), $response->card->last4, $response->card->exp_month, $exp_year ); 250 $payment_data = new QPilotPaymentData(); 251 $payment_data->description = $description; 252 $payment_data->type = 'Stripe'; 253 $payment_data->gateway_payment_id = $response->id; 254 $payment_data->gateway_customer_id = $customer_id; 255 $payment_data->last_four = $response->card->last4; 256 $payment_data->expiration = $expiration; 257 258 return $payment_data; 259 } 260 261 return null; 262 } 263 264 /** 265 * Add payment method data for QPilot. 266 * 267 * @param array $payment_method_data The payment method data. 268 * @param string $type The payment method type. 269 * @param WC_Payment_Token $token The payment token. 270 * @return array The modified payment method data. 271 */ 272 public function add_payment_method( array $payment_method_data, string $type, WC_Payment_Token $token ): array { 273 $user_id = $token->get_user_id(); 274 275 // FunnelKit Stripe payment gateway. 276 if ( 'fkwcs_stripe' === $token->get_gateway_id() ) { 277 $payment_method_data['gatewayCustomerId'] = get_user_option( '_fkwcs_customer_id', $user_id ); 278 } else { 279 // Stripe uses the customer id from user meta as Gateway Customer ID. 280 $payment_method_data['gatewayCustomerId'] = get_user_option( '_stripe_customer_id', $user_id ); 281 282 if ( 'stripe_sepa' === $token->get_gateway_id() ) { 283 $payment_method_data['gatewayPaymentType'] = 21; 284 } 285 } 286 287 return $payment_method_data; 288 } 289 290 /** 291 * Delete payment method validation. 292 * 293 * @param bool $valid Current validation status. 294 * @param string $type The payment method type. 295 * @param WC_Payment_Token $token The payment token. 296 * @param object $method The QPilot payment method. 297 * @return bool Whether the deletion is valid. 298 */ 299 public function delete_payment_method( bool $valid, string $type, WC_Payment_Token $token, object $method ): bool { 300 if ( 'Stripe' === $type ) { 301 $customer_id = get_user_option( '_stripe_customer_id', $token->get_user_id() ); 302 303 return ( $method->gatewayCustomerId === $customer_id && $method->gatewayPaymentId === $token->get_token() ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 304 } 305 306 return $valid; 307 } 308 309 /** 310 * Add refund metadata for Stripe. 311 * 312 * @param array $payment_meta The payment metadata. 313 * @param WC_Order $order The order object. 314 * @return void 315 */ 316 public function add_adjusted_gateway_metadata( array $payment_meta, WC_Order $order ): void { 317 $metadata = array(); 318 319 if ( isset( $payment_meta['CustomerId'] ) ) { 320 $metadata = array( 321 '_stripe_customer_id' => $payment_meta['CustomerId'], 322 '_stripe_source_id' => $payment_meta['Source']['Id'], 323 '_stripe_charge_captured' => 1 === $payment_meta['Captured'] ? 'yes' : 'no', 324 '_stripe_currency' => strtoupper( $payment_meta['Currency'] ), 325 ); 326 $order->set_transaction_id( $payment_meta['Id'] ); 327 } elseif ( isset( $payment_meta['charges'] ) && isset( $payment_meta['charges']['data'] ) ) { 328 $data = $payment_meta['charges']['data'][0]; 329 $metadata = array( 330 '_stripe_customer_id' => $data['customer'], 331 '_stripe_source_id' => $data['balance_transaction']['source'], 332 '_stripe_charge_captured' => 1 === $data['captured'] ? 'yes' : 'no', 333 '_stripe_currency' => strtoupper( $data['balance_transaction']['currency'] ), 334 ); 335 $order->set_transaction_id( $data['id'] ); 336 } 337 338 foreach ( $metadata as $key => $value ) { 339 $order->update_meta_data( $key, $value ); 340 } 341 342 $order->save(); 343 } 344 345 /** 346 * Add fee metadata for Stripe. 347 * 348 * @param array $payment_meta The payment metadata. 349 * @param WC_Order $order The order object. 350 * @return void 351 */ 352 public function add_adjusted_gateway_metadata_fees( array $payment_meta, WC_Order $order ): void { 353 if ( ! class_exists( 'WC_Stripe_Helper' ) ) { 354 return; 355 } 356 357 $fee_refund = null; 358 $net_refund = null; 359 360 if ( ! isset( $payment_meta['BalanceTransaction'] ) && isset( $payment_meta['charges'] ) ) { 361 if ( isset( $payment_meta['charges']['data'] ) && ! empty( $payment_meta['charges']['data'] ) ) { 362 $data = $payment_meta['charges']['data'][0]; 363 364 $fee_refund = isset( $data['balance_transaction']['fee'] ) ? $payment_meta['charges']['data'][0]['balance_transaction']['fee'] : 0; 365 $net_refund = isset( $data['balance_transaction']['net'] ) ? $payment_meta['charges']['data'][0]['balance_transaction']['net'] : 0; 366 367 // Use Stripes Helper Function to format currency. 368 if ( ! in_array( strtolower( $data['balance_transaction']['currency'] ), WC_Stripe_Helper::no_decimal_currencies(), true ) ) { 369 $fee_refund = number_format( $fee_refund / 100, 2, '.', '' ); 370 $net_refund = number_format( $net_refund / 100, 2, '.', '' ); 371 } 372 } 373 } elseif ( isset( $payment_meta['BalanceTransaction'] ) && ! empty( $payment_meta['BalanceTransaction'] ) ) { 374 // Fees and Net needs to both come from Stripe to be accurate as the returned 375 // values are in the local currency of the Stripe account, not from WC. 376 $fee_refund = isset( $payment_meta['BalanceTransaction']['Fee'] ) ? $payment_meta['BalanceTransaction']['Fee'] : 0; 377 $net_refund = isset( $payment_meta['BalanceTransaction']['Net'] ) ? $payment_meta['BalanceTransaction']['Net'] : 0; 378 379 // Use Stripes Helper Function to format currency. 380 if ( ! in_array( strtolower( $payment_meta['BalanceTransaction']['Currency'] ), WC_Stripe_Helper::no_decimal_currencies(), true ) ) { 381 $fee_refund = number_format( $fee_refund / 100, 2, '.', '' ); 382 $net_refund = number_format( $net_refund / 100, 2, '.', '' ); 383 } 384 } 385 386 if ( isset( $fee_refund ) && isset( $net_refund ) ) { 387 // Current data fee & net. 388 $fee_current = WC_Stripe_Helper::get_stripe_fee( $order ); 389 $net_current = WC_Stripe_Helper::get_stripe_net( $order ); 390 391 // Calculation. 392 $fee = (float) $fee_current + (float) $fee_refund; 393 $net = (float) $net_current + (float) $net_refund; 394 395 // Retrieve the current fees. 396 $current_fee = WC_Stripe_Helper::get_stripe_fee( $order ); 397 $current_net = WC_Stripe_Helper::get_stripe_net( $order ); 398 399 // if the fee or net doesn't exist update it. 400 if ( empty( $current_fee ) || empty( $current_net ) ) { 401 WC_Stripe_Helper::update_stripe_fee( $order, $fee ); 402 WC_Stripe_Helper::update_stripe_net( $order, $net ); 403 } 404 } 405 } 406 407 /** 408 * Static helper method for Stripe force save compatibility. 409 * 410 * @param bool $val The current value. 411 * @return bool 412 */ 413 public static function force_save_source( bool $val ): bool { 414 if ( autoship_cart_has_valid_autoship_items() ) { 415 return true; 416 } 417 return $val; 418 } 419 420 /** 421 * Static helper method for Stripe intent request filtering. 422 * 423 * @param array $request The Stripe intent request. 424 * @param WC_Order $order The WC Order object. 425 * @return array 426 */ 427 public static function filter_intent_request( array $request, WC_Order $order ): array { 428 if ( autoship_order_total_scheduled_items( $order ) > 0 ) { 429 // Setup card for both on and off-session payments. 430 $request['setup_future_usage'] = 'off_session'; 431 // Flag as a recurring payment. 432 $request['metadata']['payment_type'] = 'recurring'; 433 } 434 return $request; 435 } 436 437 /** 438 * Static helper method for Stripe Link mandate data. 439 * 440 * @param array $order_data The order data. 441 * @param int $order_id The order ID. 442 * @return array 443 */ 444 public static function add_link_mandate_data( array $order_data, int $order_id ): array { 445 if ( isset( $order_data['paymentMethod']['type'] ) && isset( $order_data['paymentMethod']['gatewayPaymentType'] ) ) { 446 if ( 'Stripe' === $order_data['paymentMethod']['type'] && 32 === $order_data['paymentMethod']['gatewayPaymentType'] ) { 447 $order = wc_get_order( $order_id ); 448 if ( $order ) { 449 $ip_address = $order->get_customer_ip_address(); 450 $user_agent = $order->get_customer_user_agent(); 451 452 $order_data['metadata']['stripe_mandate_data'] = array( 453 'customer_acceptance' => array( 454 'type' => 'online', 455 'online' => array( 456 'ip_address' => $ip_address, 457 'user_agent' => $user_agent, 458 ), 459 ), 460 ); 461 } 462 } 463 } 464 return $order_data; 465 } 466 467 /** 468 * Modifies the Payment Gateway ID for gateways treated like other gateways 469 * 470 * @param string $gateway_id The current Gateway ID. 471 * @param WC_Payment_Token_CC $token The payment Token being deleted. 472 * 473 * @return array The modified Payment Method Data to Send to QPilot 474 */ 475 public static function autoship_filter_deleted_payment_method_gateway_ids( $gateway_id, $token ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed 476 return 'stripe_sepa' === $gateway_id ? 'stripe' : $gateway_id; 477 } 88 478 } -
autoship-cloud/trunk/app/Services/QPilot/QPilotServiceClient.php
r3352156 r3462779 31 31 use Autoship\Services\QPilot\Implementations\CouponManagement; 32 32 use Autoship\Services\QPilot\Implementations\CustomerManagement; 33 use Autoship\Services\QPilot\Implementations\FeatureFlagManagement; 33 34 use Autoship\Services\QPilot\Implementations\IntegrationManagement; 34 35 use Autoship\Services\QPilot\Implementations\OrderManagement; … … 138 139 139 140 /** 141 * Feature flag management implementation. 142 * 143 * @var FeatureFlagManagement 144 */ 145 private FeatureFlagManagement $feature_flag_management; 146 147 /** 140 148 * Constructor. 141 149 * … … 146 154 147 155 // Initialize all implementation classes. 148 $this->access_management = new Implementations\AccessManagement( $this->api_client ); 149 $this->customer_management = new Implementations\CustomerManagement( $this->api_client ); 150 $this->product_management = new Implementations\ProductManagement( $this->api_client ); 151 $this->order_management = new Implementations\OrderManagement( $this->api_client ); 152 $this->payment_management = new Implementations\PaymentManagement( $this->api_client ); 153 $this->coupon_management = new Implementations\CouponManagement( $this->api_client ); 154 $this->integration_management = new Implementations\IntegrationManagement( $this->api_client ); 155 $this->site_management = new Implementations\SiteManagement( $this->api_client ); 156 $this->access_management = new Implementations\AccessManagement( $this->api_client ); 157 $this->customer_management = new Implementations\CustomerManagement( $this->api_client ); 158 $this->product_management = new Implementations\ProductManagement( $this->api_client ); 159 $this->order_management = new Implementations\OrderManagement( $this->api_client ); 160 $this->payment_management = new Implementations\PaymentManagement( $this->api_client ); 161 $this->coupon_management = new Implementations\CouponManagement( $this->api_client ); 162 $this->integration_management = new Implementations\IntegrationManagement( $this->api_client ); 163 $this->site_management = new Implementations\SiteManagement( $this->api_client ); 164 $this->feature_flag_management = new Implementations\FeatureFlagManagement( $this->api_client ); 156 165 } 157 166 … … 780 789 781 790 /** 791 * Get all globally enabled feature flags. 792 * 793 * @return array<string> List of enabled feature flag names. 794 */ 795 public function get_feature_flags(): array { 796 return $this->feature_flag_management->get_feature_flags(); 797 } 798 799 /** 800 * Get feature flags enabled for the current site. 801 * 802 * @return array<string> List of enabled feature flag names. 803 */ 804 public function get_site_feature_flags(): array { 805 return $this->feature_flag_management->get_site_feature_flags(); 806 } 807 808 /** 782 809 * Get the authentication token. 783 810 * -
autoship-cloud/trunk/app/Services/QPilot/QPilotServiceInterface.php
r3352156 r3462779 16 16 use Autoship\Services\QPilot\Interfaces\PaymentManagementInterface; 17 17 use Autoship\Services\QPilot\Interfaces\CouponManagementInterface; 18 use Autoship\Services\QPilot\Interfaces\FeatureFlagManagementInterface; 18 19 use Autoship\Services\QPilot\Interfaces\IntegrationManagementInterface; 19 20 use Autoship\Services\QPilot\Interfaces\SiteManagementInterface; … … 38 39 CouponManagementInterface, 39 40 IntegrationManagementInterface, 40 SiteManagementInterface { 41 SiteManagementInterface, 42 FeatureFlagManagementInterface { 41 43 /** 42 44 * Get the authentication token. -
autoship-cloud/trunk/autoship.php
r3453277 r3462779 8 8 * Plugin URI: https://autoship.cloud 9 9 * Description: Autoship Cloud for WooCommerce 10 * Version: 2.1 1.010 * Version: 2.12.0 11 11 * Author: Patterns In the Cloud LLC 12 12 * Author URI: https://qpilot.cloud … … 17 17 */ 18 18 19 define( 'Autoship_Version', '2.1 1.0' ); // phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ConstantNotUpperCase19 define( 'Autoship_Version', '2.12.0' ); // phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ConstantNotUpperCase 20 20 21 21 if ( ! defined( 'Autoship_Plugin_Dir' ) ) { -
autoship-cloud/trunk/languages/autoship.pot
r3453277 r3462779 3 3 msgid "" 4 4 msgstr "" 5 "Project-Id-Version: Autoship Cloud powered by QPilot 2.1 1.0\n"5 "Project-Id-Version: Autoship Cloud powered by QPilot 2.12.0\n" 6 6 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/autoship-cloud\n" 7 7 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" -
autoship-cloud/trunk/readme.txt
r3453277 r3462779 10 10 WC tested up to: 10.4.3 11 11 Requires PHP: 7.4 12 Stable tag: 2.1 1.012 Stable tag: 2.12.0 13 13 License: GPLv2 or later 14 14 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 291 291 292 292 == Changelog == 293 294 = 2.12.0 - 2026-02-16 = 295 296 - New! Payment gateway integrations are now managed through a centralized module with support for Stripe, PayPal and Authorize.NET. This provides a unified, modern architecture for handling payment method synchronization with QPilot. 297 298 - New! Added a payment compatibility layer that bridges the new modular payment system with existing WooCommerce payment hooks, ensuring a seamless transition with no disruption to existing store configurations. 299 300 - New! Payment gateways can now be remotely enabled or disabled via QPilot feature flags, giving merchants and support teams centralized control over which payment methods are active without requiring code changes. 293 301 294 302 = 2.11.0 - 2026-02-03 = -
autoship-cloud/trunk/src/payments.php
r3387754 r3462779 71 71 // - 5. Upsert The Method // autoship_update_payment_method() -- ** Same b. 72 72 73 use Autoship\Core\Plugin; 74 use Autoship\Modules\Payments\Services\PaymentMethodService; 73 75 use Autoship\Services\Logging\Logger; 74 76 … … 2355 2357 */ 2356 2358 function autoship_delete_payment_method( $method_id ) { 2357 // Get Autoship Default client.2358 $client = autoship_get_default_client();2359 2360 2359 try { 2361 // Try to delete payment method with method id. 2362 $client->delete_payment_method( $method_id ); 2363 2360 $container = Plugin::get_service_container(); 2361 $service = $container->get( PaymentMethodService::class ); 2362 2363 return $service->delete( $method_id ); 2364 2364 } catch ( Exception $e ) { 2365 $notice = autoship_expand_http_code( $e->getCode() ); 2366 autoship_log_entry( __( 'Autoship Payment Methods', 'autoship' ), sprintf( 'Error deleting QPilot Payment Method. Additional Details: %s - %s', $e->getCode(), $e->getMessage() ) ); 2367 2368 return new WP_Error( 'Deleting QPilot Payment Method Failed', __( $notice['desc'], 'autoship' ) ); // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText 2369 } 2370 2371 return true; 2365 // Fallback: service container unavailable, use legacy logic. 2366 $client = autoship_get_default_client(); 2367 2368 try { 2369 $client->delete_payment_method( $method_id ); 2370 } catch ( Exception $ex ) { 2371 $notice = autoship_expand_http_code( $ex->getCode() ); 2372 autoship_log_entry( __( 'Autoship Payment Methods', 'autoship' ), sprintf( 'Error deleting QPilot Payment Method. Additional Details: %s - %s', $ex->getCode(), $ex->getMessage() ) ); 2373 2374 return new WP_Error( 'Deleting QPilot Payment Method Failed', __( $notice['desc'], 'autoship' ) ); // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText 2375 } 2376 2377 return true; 2378 } 2372 2379 } 2373 2380 … … 2399 2406 */ 2400 2407 function autoship_add_payment_method( $payment_method_data ) { 2401 2402 $client = autoship_get_default_client();2403 2404 2408 try { 2405 $method = $client->upsert_payment_method( $payment_method_data ); 2409 $container = Plugin::get_service_container(); 2410 $service = $container->get( PaymentMethodService::class ); 2411 2412 return $service->upsert( $payment_method_data ); 2406 2413 } catch ( Exception $e ) { 2407 $notice = autoship_expand_http_code( $e->getCode() ); 2408 autoship_log_entry( __( 'Autoship Payment Methods', 'autoship' ), sprintf( 'Error creating QPilot Payment Method. Additional Details: %s - %s', $e->getCode(), $e->getMessage() ) ); 2409 2410 return new WP_Error( 'Creating QPilot Payment Method Failed', __( $notice['desc'], 'autoship' ) ); // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText 2411 } 2412 2413 return $method; 2414 // Fallback: service container unavailable, use legacy logic. 2415 $client = autoship_get_default_client(); 2416 2417 try { 2418 $method = $client->upsert_payment_method( $payment_method_data ); 2419 } catch ( Exception $ex ) { 2420 $notice = autoship_expand_http_code( $ex->getCode() ); 2421 autoship_log_entry( __( 'Autoship Payment Methods', 'autoship' ), sprintf( 'Error creating QPilot Payment Method. Additional Details: %s - %s', $ex->getCode(), $ex->getMessage() ) ); 2422 2423 return new WP_Error( 'Creating QPilot Payment Method Failed', __( $notice['desc'], 'autoship' ) ); // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText 2424 } 2425 2426 return $method; 2427 } 2414 2428 } 2415 2429 … … 2630 2644 */ 2631 2645 function autoship_add_tokenized_payment_method( $token_id ) { 2632 // Get the token. 2633 $token = WC_Payment_Tokens::get( $token_id ); 2634 2635 Logger::trace( 'Autoship', 'Adding Tokenized Payment Method', array( 'token_id' => $token_id ) ); 2636 2637 // Do not upsert payment methods at checkout. 2638 if ( apply_filters( 'autoship_add_tokenized_payment_method', false, $token ) ) { 2639 2640 Logger::trace( 'Autoship', 'Attempting to add payment method at checkout' ); 2641 2642 return; 2643 } 2644 2645 // Get the Type of Gateway ( standard tokenized or non-standard ). 2646 $gateway_type = autoship_get_payment_method_gateway_type( $token->get_gateway_id() ); 2647 2648 // Apply filters for non-standard gateways to tokenize the method data. 2649 $token = apply_filters( 'autoship_payment_method_tokenization', $token, $token_id, $gateway_type ); 2650 2651 // Allow users to override the gateway id. 2652 $gateway_id = apply_filters( 'autoship_add_tokenized_payment_method_gateway_id', $token->get_gateway_id(), $token_id, $token ); 2653 2654 // Get the current gateway id types. & Allow users to extend based on id & token. 2655 $gateway_id_types = apply_filters( 'autoship_add_tokenized_payment_method_extend_gateway_types', autoship_standard_gateway_id_types(), $gateway_id, $token ); 2656 2657 if ( ! array_key_exists( $gateway_id, $gateway_id_types ) ) { 2658 return false; 2659 } 2660 2661 /** 2662 * Add an action for Customers to call their own payment gateway add method. 2663 */ 2664 do_action( 'autoship_add_tokenized_payment_method_extend_gateway', $gateway_id, $gateway_id_types, $token ); 2665 2666 // Call the Autoship general add payment function. 2667 return autoship_add_general_payment_method( $token ); 2646 try { 2647 $container = Plugin::get_service_container(); 2648 $service = $container->get( PaymentMethodService::class ); 2649 2650 return $service->add_tokenized( $token_id ); 2651 } catch ( Exception $e ) { 2652 // Fallback: service container unavailable, use legacy logic. 2653 $token = WC_Payment_Tokens::get( $token_id ); 2654 2655 Logger::trace( 'Autoship', 'Adding Tokenized Payment Method', array( 'token_id' => $token_id ) ); 2656 2657 if ( apply_filters( 'autoship_add_tokenized_payment_method', false, $token ) ) { 2658 Logger::trace( 'Autoship', 'Attempting to add payment method at checkout' ); 2659 2660 return; 2661 } 2662 2663 $gateway_type = autoship_get_payment_method_gateway_type( $token->get_gateway_id() ); 2664 $token = apply_filters( 'autoship_payment_method_tokenization', $token, $token_id, $gateway_type ); 2665 $gateway_id = apply_filters( 'autoship_add_tokenized_payment_method_gateway_id', $token->get_gateway_id(), $token_id, $token ); 2666 $gateway_id_types = apply_filters( 'autoship_add_tokenized_payment_method_extend_gateway_types', autoship_standard_gateway_id_types(), $gateway_id, $token ); 2667 2668 if ( ! array_key_exists( $gateway_id, $gateway_id_types ) ) { 2669 return false; 2670 } 2671 2672 do_action( 'autoship_add_tokenized_payment_method_extend_gateway', $gateway_id, $gateway_id_types, $token ); 2673 2674 return autoship_add_general_payment_method( $token ); 2675 } 2668 2676 } 2669 2677 … … 2678 2686 */ 2679 2687 function autoship_delete_tokenized_payment_method( $token_id, $token ) { 2680 2681 // The id for the token being removed. 2682 $gateway_id = apply_filters( 'autoship_delete_tokenized_payment_method_gateway_id', $token->get_gateway_id(), $token ); 2683 2684 // Get the current gateway id types. & Allow users to extend based on id & token. 2685 $gateway_id_types = apply_filters( 'autoship_delete_tokenized_payment_method_extend_gateway_types', autoship_standard_gateway_id_types(), $gateway_id, $token ); 2686 2687 if ( ! array_key_exists( $gateway_id, $gateway_id_types ) ) { 2688 return false; 2689 } 2690 2691 // Add an action for Customers to call their own payment gateway deletion method. 2692 do_action( 'autoship_delete_tokenized_payment_method_extend_gateway', $gateway_id, $gateway_id_types, $token ); 2693 2694 // Call the Autoship general delete payment function. 2695 return autoship_delete_general_payment_method( $token_id, $token, $gateway_id_types[ $gateway_id ] ); 2688 try { 2689 $container = Plugin::get_service_container(); 2690 $service = $container->get( PaymentMethodService::class ); 2691 2692 return $service->delete_tokenized( $token_id, $token ); 2693 } catch ( Exception $e ) { 2694 // Fallback: service container unavailable, use legacy logic. 2695 $gateway_id = apply_filters( 'autoship_delete_tokenized_payment_method_gateway_id', $token->get_gateway_id(), $token ); 2696 $gateway_id_types = apply_filters( 'autoship_delete_tokenized_payment_method_extend_gateway_types', autoship_standard_gateway_id_types(), $gateway_id, $token ); 2697 2698 if ( ! array_key_exists( $gateway_id, $gateway_id_types ) ) { 2699 return false; 2700 } 2701 2702 do_action( 'autoship_delete_tokenized_payment_method_extend_gateway', $gateway_id, $gateway_id_types, $token ); 2703 2704 return autoship_delete_general_payment_method( $token_id, $token, $gateway_id_types[ $gateway_id ] ); 2705 } 2696 2706 } 2697 2707 … … 2707 2717 */ 2708 2718 function autoship_add_non_wc_token_payment_method( $response, $order, $autoship_method_type ) { 2709 2710 $token = $response->get_payment_token(); 2711 $autoship_method_id = $token->get_id(); 2712 2713 // Apply filters for non-standard gateways to tokenize the method data. 2714 $token = apply_filters( 'autoship_payment_method_tokenization', WC_Payment_Tokens::get( $autoship_method_id ), $autoship_method_id, $autoship_method_type ); 2715 if ( empty( $token ) ) { 2716 return $token; 2717 } 2718 2719 $type = autoship_get_valid_payment_method_type( $token->get_gateway_id() ); 2720 2721 // Get the payment method data. 2722 $autoship_method_data = autoship_add_general_payment_method( $token, true ); 2723 2724 return autoship_add_payment_method( $autoship_method_data ); 2719 try { 2720 $container = Plugin::get_service_container(); 2721 $service = $container->get( PaymentMethodService::class ); 2722 2723 return $service->add_from_gateway_response( $response, $order, $autoship_method_type ); 2724 } catch ( Exception $e ) { 2725 // Fallback: service container unavailable, use legacy logic. 2726 $token = $response->get_payment_token(); 2727 $autoship_method_id = $token->get_id(); 2728 2729 $token = apply_filters( 'autoship_payment_method_tokenization', WC_Payment_Tokens::get( $autoship_method_id ), $autoship_method_id, $autoship_method_type ); 2730 if ( empty( $token ) ) { 2731 return $token; 2732 } 2733 2734 $autoship_method_data = autoship_add_general_payment_method( $token, true ); 2735 2736 return autoship_add_payment_method( $autoship_method_data ); 2737 } 2725 2738 } 2726 2739 … … 2737 2750 */ 2738 2751 function autoship_delete_non_wc_token_payment_method( $gateway_payment_method_id, $gateway_customer_id, $type, $wc_customer_id = null ) { 2739 if ( empty( $wc_customer_id ) || ! isset( $wc_customer_id ) ) { 2740 $wc_customer_id = get_current_user_id(); 2741 } 2742 2743 // Check if the customer exists and if not create it. 2744 $customer = autoship_check_autoship_customer( $wc_customer_id, 'autoship_delete_non_wc_token_payment' ); 2745 2746 if ( ! $customer ) { 2747 return false; 2748 } 2749 2750 // Get this users payment methods from QPilot. 2751 $payment_methods = $customer->paymentMethods; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 2752 2753 $result = false; 2754 foreach ( $payment_methods as $method ) { 2755 2756 // Valid Check Since some gateways don't have a user id at deletion. 2757 $valid = ! empty( $gateway_customer_id ) ? ( $method->type === $type && $method->gatewayPaymentId === $gateway_customer_id && $method->gatewayPaymentId === $gateway_payment_method_id ) : ( $method->type === $type && $method->gatewayPaymentId === $gateway_payment_method_id ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 2758 2759 if ( $valid ) { 2760 // Delete the Payment Method. 2761 $result = autoship_delete_payment_method( $method->id ); 2762 break; 2763 } 2764 } 2765 2766 return $result; 2752 try { 2753 $container = Plugin::get_service_container(); 2754 $service = $container->get( PaymentMethodService::class ); 2755 2756 return $service->delete_non_wc_token( $gateway_payment_method_id, $gateway_customer_id, $type, $wc_customer_id ); 2757 } catch ( Exception $e ) { 2758 // Fallback: service container unavailable, use legacy logic. 2759 if ( empty( $wc_customer_id ) || ! isset( $wc_customer_id ) ) { 2760 $wc_customer_id = get_current_user_id(); 2761 } 2762 2763 $customer = autoship_check_autoship_customer( $wc_customer_id, 'autoship_delete_non_wc_token_payment' ); 2764 2765 if ( ! $customer ) { 2766 return false; 2767 } 2768 2769 $payment_methods = $customer->paymentMethods; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 2770 2771 $result = false; 2772 foreach ( $payment_methods as $method ) { 2773 $valid = ! empty( $gateway_customer_id ) ? ( $method->type === $type && $method->gatewayPaymentId === $gateway_customer_id && $method->gatewayPaymentId === $gateway_payment_method_id ) : ( $method->type === $type && $method->gatewayPaymentId === $gateway_payment_method_id ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 2774 2775 if ( $valid ) { 2776 $result = autoship_delete_payment_method( $method->id ); 2777 break; 2778 } 2779 } 2780 2781 return $result; 2782 } 2767 2783 } 2768 2784 … … 2777 2793 */ 2778 2794 function autoship_add_general_payment_method( $token, $return_or_added = false ) { 2779 2780 2795 if ( is_wp_error( $token ) || empty( $token ) || ! $token ) { 2781 2796 return; 2782 2797 } 2783 2798 2784 // Get the User associated with the token. 2785 $wc_customer_id = $token->get_user_id(); 2786 2787 // CHeck if the customer is already in Qpilot 2788 // This will upsert them if they aren't already there. 2789 $customer = autoship_check_autoship_customer( $wc_customer_id, 'autoship_add_general_payment' ); 2790 2791 // Don't process if not a Autoship. 2792 if ( ! $customer ) { 2793 return false; 2794 } 2795 2796 // Create the payment method and gather the info. 2797 $payment_method_id = $token->get_token(); 2798 2799 /** 2800 * Apply filters for non-standard gateways to tokenize the method data. 2801 */ 2802 $gateway = $token->get_gateway_id(); 2803 $description = apply_filters( 'autoship_add_general_payment_method_description', $token->get_display_name(), $token ); 2804 $type = autoship_get_valid_payment_method_type( $gateway ); 2805 $expiration = null; 2806 2807 // Catch Scenarios where the token class doesn't use expirations ( i.e. SEPA ). 2808 if ( is_callable( array( $token, 'get_expiry_month' ) ) && is_callable( array( $token, 'get_expiry_year' ) ) ) { 2809 $expiration = $token->get_expiry_month() . substr( $token->get_expiry_year(), -2 ); 2810 } 2811 2812 // Verify if the method exists within the token. 2813 $last_four_digits = null; 2814 if ( method_exists( $token, 'get_last4' ) && is_callable( array( $token, 'get_last4' ) ) && 'ppcp-gateway' !== $gateway ) { 2815 $last_four_digits = $token->get_last4(); 2816 } 2817 2818 $data = array( 2819 'type' => $type, 2820 'expiration' => $expiration, 2821 'lastFourDigits' => $last_four_digits, 2822 'gatewayCustomerId' => $wc_customer_id, 2823 'gatewayPaymentId' => $payment_method_id, 2824 'description' => $description, 2825 ); 2826 2827 // PayPal Payments adjustments. 2828 if ( 'PayPalV3' == $type ) { //phpcs:ignore 2829 if ( 'ppcp-credit-card-gateway' == $gateway ) { //phpcs:ignore 2830 $data['gatewayPaymentType'] = 26; 2831 } 2832 2833 if ( 'ppcp-gateway' == $gateway ) { //phpcs:ignore 2834 $data['gatewayPaymentType'] = 25; 2835 $data['description'] = 'PayPal Payments'; 2836 } 2837 2838 $gateway_customer_id = get_user_meta( $wc_customer_id, '_ppcp_target_customer_id', true ); 2839 if ( ! $gateway_customer_id ) { 2840 $gateway_customer_id = get_user_meta( $wc_customer_id, 'ppcp_customer_id', true ); 2841 } 2842 2843 if ( $gateway_customer_id ) { 2844 $data['gatewayCustomerId'] = $gateway_customer_id; 2845 } 2846 } 2847 2848 // Stripe Link Adjustments. 2849 if ( is_a( $token, 'WC_Payment_Token_Link' ) && 'Stripe' == $type && 'stripe' == $gateway ) { //phpcs:ignore 2850 $data['gatewayPaymentType'] = 32; 2851 } 2852 2853 $payment_method_data = autoship_get_general_payment_method_customer_data( $wc_customer_id, $data ); 2854 2855 // Apply the Payment method filter for customers to override. 2856 $payment_method_data = apply_filters( 'autoship_add_general_payment_method', $payment_method_data, $type, $token ); 2857 $payment_method_data = apply_filters( "autoship_add_{$type}_payment_method", $payment_method_data, $type, $token ); 2858 $payment_method_data = apply_filters( 'autoship_api_create_payment_method_data', $payment_method_data ); 2859 2860 if ( Logger::is_tracing_enabled() ) { 2861 $export_payment_data = var_export( $payment_method_data, true ); // phpcs:ignore 2862 2863 Logger::trace( 'Autoship Payment Methods', "Sending Payment Method Data to QPilot. Type: '{$type}' Gateway: '{$gateway}' Data: {$export_payment_data}." ); 2864 } 2865 2866 // Add the Method. 2867 return $return_or_added ? $payment_method_data : autoship_add_payment_method( $payment_method_data ); 2799 try { 2800 $container = Plugin::get_service_container(); 2801 $service = $container->get( PaymentMethodService::class ); 2802 2803 return $service->add_from_token( $token, $return_or_added ); 2804 } catch ( Exception $e ) { 2805 // Fallback: service container unavailable, use legacy logic. 2806 $wc_customer_id = $token->get_user_id(); 2807 2808 $customer = autoship_check_autoship_customer( $wc_customer_id, 'autoship_add_general_payment' ); 2809 2810 if ( ! $customer ) { 2811 return false; 2812 } 2813 2814 $payment_method_id = $token->get_token(); 2815 $gateway = $token->get_gateway_id(); 2816 $description = apply_filters( 'autoship_add_general_payment_method_description', $token->get_display_name(), $token ); 2817 $type = autoship_get_valid_payment_method_type( $gateway ); 2818 $expiration = null; 2819 2820 if ( is_callable( array( $token, 'get_expiry_month' ) ) && is_callable( array( $token, 'get_expiry_year' ) ) ) { 2821 $expiration = $token->get_expiry_month() . substr( $token->get_expiry_year(), -2 ); 2822 } 2823 2824 $last_four_digits = null; 2825 if ( method_exists( $token, 'get_last4' ) && is_callable( array( $token, 'get_last4' ) ) && 'ppcp-gateway' !== $gateway ) { 2826 $last_four_digits = $token->get_last4(); 2827 } 2828 2829 $data = array( 2830 'type' => $type, 2831 'expiration' => $expiration, 2832 'lastFourDigits' => $last_four_digits, 2833 'gatewayCustomerId' => $wc_customer_id, 2834 'gatewayPaymentId' => $payment_method_id, 2835 'description' => $description, 2836 ); 2837 2838 if ( 'PayPalV3' == $type ) { //phpcs:ignore 2839 if ( 'ppcp-credit-card-gateway' == $gateway ) { //phpcs:ignore 2840 $data['gatewayPaymentType'] = 26; 2841 } 2842 2843 if ( 'ppcp-gateway' == $gateway ) { //phpcs:ignore 2844 $data['gatewayPaymentType'] = 25; 2845 $data['description'] = 'PayPal Payments'; 2846 } 2847 2848 $gateway_customer_id = get_user_meta( $wc_customer_id, '_ppcp_target_customer_id', true ); 2849 if ( ! $gateway_customer_id ) { 2850 $gateway_customer_id = get_user_meta( $wc_customer_id, 'ppcp_customer_id', true ); 2851 } 2852 2853 if ( $gateway_customer_id ) { 2854 $data['gatewayCustomerId'] = $gateway_customer_id; 2855 } 2856 } 2857 2858 if ( is_a( $token, 'WC_Payment_Token_Link' ) && 'Stripe' == $type && 'stripe' == $gateway ) { //phpcs:ignore 2859 $data['gatewayPaymentType'] = 32; 2860 } 2861 2862 $payment_method_data = autoship_get_general_payment_method_customer_data( $wc_customer_id, $data ); 2863 2864 $payment_method_data = apply_filters( 'autoship_add_general_payment_method', $payment_method_data, $type, $token ); 2865 $payment_method_data = apply_filters( "autoship_add_{$type}_payment_method", $payment_method_data, $type, $token ); 2866 $payment_method_data = apply_filters( 'autoship_api_create_payment_method_data', $payment_method_data ); 2867 2868 if ( Logger::is_tracing_enabled() ) { 2869 $export_payment_data = var_export( $payment_method_data, true ); // phpcs:ignore 2870 2871 Logger::trace( 'Autoship Payment Methods', "Sending Payment Method Data to QPilot. Type: '{$type}' Gateway: '{$gateway}' Data: {$export_payment_data}." ); 2872 } 2873 2874 return $return_or_added ? $payment_method_data : autoship_add_payment_method( $payment_method_data ); 2875 } 2868 2876 } 2869 2877 … … 2878 2886 */ 2879 2887 function autoship_delete_general_payment_method( $token_id, $token, $type = '' ) { 2880 2881 // Get the WC Customer from the Token. 2882 $wc_customer_id = $token->get_user_id(); 2883 2884 // Get the Autoship Customer ID. 2885 $customer = autoship_check_autoship_customer( $wc_customer_id, 'autoship_delete_general_payment' ); 2886 2887 // If not autoship bypass. 2888 if ( ! $customer || empty( $type ) ) { 2889 return false; 2890 } 2891 2892 // Get the method id from the token. 2893 $payment_method_id = $token->get_token(); 2894 2895 // Get the customer's payment methods from QPilot. 2896 $payment_methods = $customer->paymentMethods; // phpcs:ignore 2897 2898 // Check if there are any payment methods. 2899 if ( empty( $payment_methods ) ) { 2900 return true; 2901 } 2902 2903 $result = false; 2904 2905 // Iterate through the payment methods and delete the one that matches this type. 2906 foreach ( $payment_methods as $method ) { 2907 2908 // If the token being deleted matches a token in QPilot Delete it. 2909 $valid = ( $method->type === $type && $method->gatewayCustomerId === $wc_customer_id && $method->gatewayPaymentId === $payment_method_id ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 2910 2911 // Added a filter to allow for custom matches between QPilot and Autoship. 2912 // Takes the current matching boolean, the supplied QPilot Method Type, The current Token and the QPilot Payment Method object. 2913 $valid = apply_filters( 'autoship_delete_general_payment_method_qpilot_match', $valid, $type, $token, $method ); 2914 $valid = apply_filters( "autoship_delete_{$type}_payment_method_qpilot_match", $valid, $type, $token, $method ); 2915 2916 if ( $valid ) { 2917 2918 // Delete the Payment Method. 2919 $result = autoship_delete_payment_method( $method->id ); 2920 break; 2921 } 2922 } 2923 2924 return $result; 2888 try { 2889 $container = Plugin::get_service_container(); 2890 $service = $container->get( PaymentMethodService::class ); 2891 2892 return $service->delete_for_token( $token_id, $token, $type ); 2893 } catch ( Exception $e ) { 2894 // Fallback: service container unavailable, use legacy logic. 2895 $wc_customer_id = $token->get_user_id(); 2896 2897 $customer = autoship_check_autoship_customer( $wc_customer_id, 'autoship_delete_general_payment' ); 2898 2899 if ( ! $customer || empty( $type ) ) { 2900 return false; 2901 } 2902 2903 $payment_method_id = $token->get_token(); 2904 $payment_methods = $customer->paymentMethods; // phpcs:ignore 2905 2906 if ( empty( $payment_methods ) ) { 2907 return true; 2908 } 2909 2910 $result = false; 2911 2912 foreach ( $payment_methods as $method ) { 2913 $valid = ( $method->type === $type && $method->gatewayCustomerId === $wc_customer_id && $method->gatewayPaymentId === $payment_method_id ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase 2914 2915 $valid = apply_filters( 'autoship_delete_general_payment_method_qpilot_match', $valid, $type, $token, $method ); 2916 $valid = apply_filters( "autoship_delete_{$type}_payment_method_qpilot_match", $valid, $type, $token, $method ); 2917 2918 if ( $valid ) { 2919 $result = autoship_delete_payment_method( $method->id ); 2920 break; 2921 } 2922 } 2923 2924 return $result; 2925 } 2925 2926 } 2926 2927 -
autoship-cloud/trunk/vendor/autoload.php
r3362678 r3462779 15 15 } 16 16 } 17 throw new RuntimeException($err); 17 trigger_error( 18 $err, 19 E_USER_ERROR 20 ); 18 21 } 19 22 -
autoship-cloud/trunk/vendor/composer/InstalledVersions.php
r3362678 r3462779 27 27 class InstalledVersions 28 28 { 29 /**30 * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to31 * @internal32 */33 private static $selfDir = null;34 35 29 /** 36 30 * @var mixed[]|null … … 330 324 331 325 /** 332 * @return string333 */334 private static function getSelfDir()335 {336 if (self::$selfDir === null) {337 self::$selfDir = strtr(__DIR__, '\\', '/');338 }339 340 return self::$selfDir;341 }342 343 /**344 326 * @return array[] 345 327 * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> … … 355 337 356 338 if (self::$canGetVendors) { 357 $selfDir = s elf::getSelfDir();339 $selfDir = strtr(__DIR__, '\\', '/'); 358 340 foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { 359 341 $vendorDir = strtr($vendorDir, '\\', '/'); -
autoship-cloud/trunk/vendor/composer/autoload_classmap.php
r3453277 r3462779 39 39 'Autoship\\Core\\SettingsInterface' => $baseDir . '/app/Core/SettingsInterface.php', 40 40 'Autoship\\Core\\SitesManagerInterface' => $baseDir . '/app/Core/SitesManagerInterface.php', 41 'Autoship\\Domain\\AbstractPaymentGateway' => $baseDir . '/app/Domain/AbstractPaymentGateway.php', 41 42 'Autoship\\Domain\\Nextime\\DeliveryDate' => $baseDir . '/app/Domain/Nextime/DeliveryDate.php', 42 43 'Autoship\\Domain\\Nextime\\NextimeShippingCalculator' => $baseDir . '/app/Domain/Nextime/NextimeShippingCalculator.php', … … 71 72 'Autoship\\Modules\\Nextime\\NextimeModule' => $baseDir . '/app/Modules/Nextime/NextimeModule.php', 72 73 'Autoship\\Modules\\Nextime\\NextimeService' => $baseDir . '/app/Modules/Nextime/NextimeService.php', 74 'Autoship\\Modules\\Payments\\Compatibility\\AbstractPaymentCompatibility' => $baseDir . '/app/Modules/Payments/Compatibility/AbstractPaymentCompatibility.php', 75 'Autoship\\Modules\\Payments\\Compatibility\\AuthorizeNetPaymentCompatibility' => $baseDir . '/app/Modules/Payments/Compatibility/AuthorizeNetPaymentCompatibility.php', 76 'Autoship\\Modules\\Payments\\Compatibility\\PayPalPaymentCompatibility' => $baseDir . '/app/Modules/Payments/Compatibility/PayPalPaymentCompatibility.php', 77 'Autoship\\Modules\\Payments\\Compatibility\\PaymentsCompatibilityManager' => $baseDir . '/app/Modules/Payments/Compatibility/PaymentsCompatibilityManager.php', 78 'Autoship\\Modules\\Payments\\Compatibility\\SquarePaymentCompatibility' => $baseDir . '/app/Modules/Payments/Compatibility/SquarePaymentCompatibility.php', 79 'Autoship\\Modules\\Payments\\Compatibility\\StripePaymentCompatibility' => $baseDir . '/app/Modules/Payments/Compatibility/StripePaymentCompatibility.php', 80 'Autoship\\Modules\\Payments\\PaymentsModule' => $baseDir . '/app/Modules/Payments/PaymentsModule.php', 81 'Autoship\\Modules\\Payments\\Services\\PaymentGatewayRegistry' => $baseDir . '/app/Modules/Payments/Services/PaymentGatewayRegistry.php', 82 'Autoship\\Modules\\Payments\\Services\\PaymentGatewayService' => $baseDir . '/app/Modules/Payments/Services/PaymentGatewayService.php', 83 'Autoship\\Modules\\Payments\\Services\\PaymentMethodDataBuilder' => $baseDir . '/app/Modules/Payments/Services/PaymentMethodDataBuilder.php', 84 'Autoship\\Modules\\Payments\\Services\\PaymentMethodService' => $baseDir . '/app/Modules/Payments/Services/PaymentMethodService.php', 85 'Autoship\\Modules\\Payments\\Services\\PaymentsCompatibilityService' => $baseDir . '/app/Modules/Payments/Services/PaymentsCompatibilityService.php', 73 86 'Autoship\\Modules\\QuickLinks\\Controllers\\QuickLinkController' => $baseDir . '/app/Modules/QuickLinks/Controllers/QuickLinkController.php', 74 87 'Autoship\\Modules\\QuickLinks\\Controllers\\QuickLinksSettingsController' => $baseDir . '/app/Modules/QuickLinks/Controllers/QuickLinksSettingsController.php', … … 134 147 'Autoship\\Services\\QPilot\\Implementations\\CouponManagement' => $baseDir . '/app/Services/QPilot/Implementations/CouponManagement.php', 135 148 'Autoship\\Services\\QPilot\\Implementations\\CustomerManagement' => $baseDir . '/app/Services/QPilot/Implementations/CustomerManagement.php', 149 'Autoship\\Services\\QPilot\\Implementations\\FeatureFlagManagement' => $baseDir . '/app/Services/QPilot/Implementations/FeatureFlagManagement.php', 136 150 'Autoship\\Services\\QPilot\\Implementations\\IntegrationManagement' => $baseDir . '/app/Services/QPilot/Implementations/IntegrationManagement.php', 137 151 'Autoship\\Services\\QPilot\\Implementations\\OrderManagement' => $baseDir . '/app/Services/QPilot/Implementations/OrderManagement.php', … … 146 160 'Autoship\\Services\\QPilot\\Interfaces\\CouponManagementInterface' => $baseDir . '/app/Services/QPilot/Interfaces/CouponManagementInterface.php', 147 161 'Autoship\\Services\\QPilot\\Interfaces\\CustomerManagementInterface' => $baseDir . '/app/Services/QPilot/Interfaces/CustomerManagementInterface.php', 162 'Autoship\\Services\\QPilot\\Interfaces\\FeatureFlagManagementInterface' => $baseDir . '/app/Services/QPilot/Interfaces/FeatureFlagManagementInterface.php', 148 163 'Autoship\\Services\\QPilot\\Interfaces\\IntegrationManagementInterface' => $baseDir . '/app/Services/QPilot/Interfaces/IntegrationManagementInterface.php', 149 164 'Autoship\\Services\\QPilot\\Interfaces\\OrderManagementInterface' => $baseDir . '/app/Services/QPilot/Interfaces/OrderManagementInterface.php', -
autoship-cloud/trunk/vendor/composer/autoload_static.php
r3453277 r3462779 8 8 { 9 9 public static $prefixLengthsPsr4 = array ( 10 'A' => 10 'A' => 11 11 array ( 12 12 'Autoship\\' => 9, … … 15 15 16 16 public static $prefixDirsPsr4 = array ( 17 'Autoship\\' => 17 'Autoship\\' => 18 18 array ( 19 19 0 => __DIR__ . '/../..' . '/app', … … 54 54 'Autoship\\Core\\SettingsInterface' => __DIR__ . '/../..' . '/app/Core/SettingsInterface.php', 55 55 'Autoship\\Core\\SitesManagerInterface' => __DIR__ . '/../..' . '/app/Core/SitesManagerInterface.php', 56 'Autoship\\Domain\\AbstractPaymentGateway' => __DIR__ . '/../..' . '/app/Domain/AbstractPaymentGateway.php', 56 57 'Autoship\\Domain\\Nextime\\DeliveryDate' => __DIR__ . '/../..' . '/app/Domain/Nextime/DeliveryDate.php', 57 58 'Autoship\\Domain\\Nextime\\NextimeShippingCalculator' => __DIR__ . '/../..' . '/app/Domain/Nextime/NextimeShippingCalculator.php', … … 86 87 'Autoship\\Modules\\Nextime\\NextimeModule' => __DIR__ . '/../..' . '/app/Modules/Nextime/NextimeModule.php', 87 88 'Autoship\\Modules\\Nextime\\NextimeService' => __DIR__ . '/../..' . '/app/Modules/Nextime/NextimeService.php', 89 'Autoship\\Modules\\Payments\\Compatibility\\AbstractPaymentCompatibility' => __DIR__ . '/../..' . '/app/Modules/Payments/Compatibility/AbstractPaymentCompatibility.php', 90 'Autoship\\Modules\\Payments\\Compatibility\\AuthorizeNetPaymentCompatibility' => __DIR__ . '/../..' . '/app/Modules/Payments/Compatibility/AuthorizeNetPaymentCompatibility.php', 91 'Autoship\\Modules\\Payments\\Compatibility\\PayPalPaymentCompatibility' => __DIR__ . '/../..' . '/app/Modules/Payments/Compatibility/PayPalPaymentCompatibility.php', 92 'Autoship\\Modules\\Payments\\Compatibility\\PaymentsCompatibilityManager' => __DIR__ . '/../..' . '/app/Modules/Payments/Compatibility/PaymentsCompatibilityManager.php', 93 'Autoship\\Modules\\Payments\\Compatibility\\SquarePaymentCompatibility' => __DIR__ . '/../..' . '/app/Modules/Payments/Compatibility/SquarePaymentCompatibility.php', 94 'Autoship\\Modules\\Payments\\Compatibility\\StripePaymentCompatibility' => __DIR__ . '/../..' . '/app/Modules/Payments/Compatibility/StripePaymentCompatibility.php', 95 'Autoship\\Modules\\Payments\\PaymentsModule' => __DIR__ . '/../..' . '/app/Modules/Payments/PaymentsModule.php', 96 'Autoship\\Modules\\Payments\\Services\\PaymentGatewayRegistry' => __DIR__ . '/../..' . '/app/Modules/Payments/Services/PaymentGatewayRegistry.php', 97 'Autoship\\Modules\\Payments\\Services\\PaymentGatewayService' => __DIR__ . '/../..' . '/app/Modules/Payments/Services/PaymentGatewayService.php', 98 'Autoship\\Modules\\Payments\\Services\\PaymentMethodDataBuilder' => __DIR__ . '/../..' . '/app/Modules/Payments/Services/PaymentMethodDataBuilder.php', 99 'Autoship\\Modules\\Payments\\Services\\PaymentMethodService' => __DIR__ . '/../..' . '/app/Modules/Payments/Services/PaymentMethodService.php', 100 'Autoship\\Modules\\Payments\\Services\\PaymentsCompatibilityService' => __DIR__ . '/../..' . '/app/Modules/Payments/Services/PaymentsCompatibilityService.php', 88 101 'Autoship\\Modules\\QuickLinks\\Controllers\\QuickLinkController' => __DIR__ . '/../..' . '/app/Modules/QuickLinks/Controllers/QuickLinkController.php', 89 102 'Autoship\\Modules\\QuickLinks\\Controllers\\QuickLinksSettingsController' => __DIR__ . '/../..' . '/app/Modules/QuickLinks/Controllers/QuickLinksSettingsController.php', … … 149 162 'Autoship\\Services\\QPilot\\Implementations\\CouponManagement' => __DIR__ . '/../..' . '/app/Services/QPilot/Implementations/CouponManagement.php', 150 163 'Autoship\\Services\\QPilot\\Implementations\\CustomerManagement' => __DIR__ . '/../..' . '/app/Services/QPilot/Implementations/CustomerManagement.php', 164 'Autoship\\Services\\QPilot\\Implementations\\FeatureFlagManagement' => __DIR__ . '/../..' . '/app/Services/QPilot/Implementations/FeatureFlagManagement.php', 151 165 'Autoship\\Services\\QPilot\\Implementations\\IntegrationManagement' => __DIR__ . '/../..' . '/app/Services/QPilot/Implementations/IntegrationManagement.php', 152 166 'Autoship\\Services\\QPilot\\Implementations\\OrderManagement' => __DIR__ . '/../..' . '/app/Services/QPilot/Implementations/OrderManagement.php', … … 161 175 'Autoship\\Services\\QPilot\\Interfaces\\CouponManagementInterface' => __DIR__ . '/../..' . '/app/Services/QPilot/Interfaces/CouponManagementInterface.php', 162 176 'Autoship\\Services\\QPilot\\Interfaces\\CustomerManagementInterface' => __DIR__ . '/../..' . '/app/Services/QPilot/Interfaces/CustomerManagementInterface.php', 177 'Autoship\\Services\\QPilot\\Interfaces\\FeatureFlagManagementInterface' => __DIR__ . '/../..' . '/app/Services/QPilot/Interfaces/FeatureFlagManagementInterface.php', 163 178 'Autoship\\Services\\QPilot\\Interfaces\\IntegrationManagementInterface' => __DIR__ . '/../..' . '/app/Services/QPilot/Interfaces/IntegrationManagementInterface.php', 164 179 'Autoship\\Services\\QPilot\\Interfaces\\OrderManagementInterface' => __DIR__ . '/../..' . '/app/Services/QPilot/Interfaces/OrderManagementInterface.php', -
autoship-cloud/trunk/vendor/composer/platform_check.php
r3453277 r3462779 20 20 } 21 21 } 22 throw new \RuntimeException( 23 'Composer detected issues in your platform: ' . implode(' ', $issues) 22 trigger_error( 23 'Composer detected issues in your platform: ' . implode(' ', $issues), 24 E_USER_ERROR 24 25 ); 25 26 }
Note: See TracChangeset
for help on using the changeset viewer.