woocommerce / woocommerce-gateway-payfast

South African payment gateway supporting subscriptions, deposits & pre-orders
https://wordpress.org/plugins/woocommerce-payfast-gateway/
40 stars 15 forks source link

Renewal order ID is not submitted with renewal payments #152

Closed nicdwilson closed 8 months ago

nicdwilson commented 1 year ago

Describe the Bug

Renewal order IDs are not submitted with ad-hoc renewal payments. In turn, PayFast appears to return a random order id in the m_payment_id and custom_str3 from the customer's previous payments.

This means that when subscription prices are adjusted, subscription renewals may fail with the Amount mismatch result due to the incoming ITN order details not matching the actual order sent.

This is because custom_str3 is used to extract the ID of the order to check against.

08-01-2023 @ 11:51:33 - Check data against internal order
08-01-2023 @ 11:51:33 - Error occurred: Amount mismatch

To Reproduce

  1. Running WooCommerce Subscriptions and PayFast
  2. Purchase a subscription and run half a dozen renewals
  3. None of these will fail, but the logs will reveal that the incoming m_payment_id and custom_str3 values do not match the description value, which contains the actual order id of the order paid
  4. Change the value of the subscription
  5. Run a renewal
  6. See error

Log entry

08-01-2023 @ 11:51:33 - Verify data received
08-01-2023 @ 11:51:33 - Host = https://www.payfast.co.za/eng/query/validate
08-01-2023 @ 11:51:33 - Params = Array
(
    [m_payment_id] => 1436783
    [pf_payment_id] => 131231488
    [payment_status] => COMPLETE
    [item_name] => [redacted]
    [item_description] => {"renewal_order_id":1508897}
    [amount_gross] => 70.00
    [amount_fee] => -4.88
    [amount_net] => 65.12
    [custom_str1] => wc_order_im6qG0rXK6SUt
    [custom_str2] => [redacted]
    [custom_str3] => 1436783
    [custom_str4] => 
    [custom_str5] => 
    [custom_int1] => 
    [custom_int2] => 
    [custom_int3] => 
    [custom_int4] => 
    [custom_int5] => 
    [name_first] => [redacted]
    [name_last] => [redacted]
    [email_address] => [redacted]
    [merchant_id] => [redacted]
    [token] => [redacted]
    [billing_date] => 2023-08-01
)

08-01-2023 @ 11:51:33 - Response:
Array
(
    [VALID] => 
)

08-01-2023 @ 11:51:33 - Check data against internal order
08-01-2023 @ 11:51:33 - Error occurred: Amount mismatch

Expected Behavior

The m_payment_id and custom_str3 parameters should be passed with the ad hoc payment request.

Actual Behavior

The payment is validated against a random order.

Environment

System status ``` ` ### WordPress Environment ### WordPress address (URL): [redacted] WC Version: 8.0.1 REST API Version: ✔ 8.0.1 WC Blocks Version: ✔ 10.6.5 Action Scheduler Version: ✔ 3.6.1 Log Directory Writable: ✔ WP Version: 6.3 WP Multisite: – WP Memory Limit: 512 MB WP Debug Mode: – WP Cron: ✔ Language: en_US External object cache: ✔ ### Server Environment ### Server Info: nginx PHP Version: 8.1.22 PHP Post Max Size: 2 GB PHP Time Limit: 1200 PHP Max Input Vars: 6144 cURL Version: 8.0.1 OpenSSL/1.1.1n SUHOSIN Installed: – MySQL Version: 10.6.13-MariaDB-log Max Upload Size: 2 GB Default Timezone is UTC: ✔ fsockopen/cURL: ✔ SoapClient: ✔ DOMDocument: ✔ GZip: ✔ Multibyte String: ✔ Remote Post: ✔ Remote Get: ✔ ### Database ### WC Database Version: 8.0.1 WC Database Prefix: wp_ Total Database Size: 2.98MB Database Data Size: 1.31MB Database Index Size: 1.67MB wp_woocommerce_sessions: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_woocommerce_api_keys: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_woocommerce_attribute_taxonomies: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_woocommerce_downloadable_product_permissions: Data: 0.02MB + Index: 0.06MB + Engine InnoDB wp_woocommerce_order_items: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_woocommerce_order_itemmeta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_woocommerce_tax_rates: Data: 0.02MB + Index: 0.06MB + Engine InnoDB wp_woocommerce_tax_rate_locations: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_woocommerce_shipping_zones: Data: 0.02MB + Index: 0.00MB + Engine InnoDB wp_woocommerce_shipping_zone_locations: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_woocommerce_shipping_zone_methods: Data: 0.02MB + Index: 0.00MB + Engine InnoDB wp_woocommerce_payment_tokens: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_woocommerce_payment_tokenmeta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_woocommerce_log: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_actionscheduler_actions: Data: 0.02MB + Index: 0.11MB + Engine InnoDB wp_actionscheduler_claims: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_actionscheduler_groups: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_actionscheduler_logs: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_commentmeta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_comments: Data: 0.02MB + Index: 0.09MB + Engine InnoDB wp_links: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_options: Data: 0.16MB + Index: 0.03MB + Engine InnoDB wp_postmeta: Data: 0.06MB + Index: 0.03MB + Engine InnoDB wp_posts: Data: 0.05MB + Index: 0.06MB + Engine InnoDB wp_termmeta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_terms: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_term_relationships: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_term_taxonomy: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_usermeta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_users: Data: 0.02MB + Index: 0.05MB + Engine InnoDB wp_wc_admin_notes: Data: 0.06MB + Index: 0.00MB + Engine InnoDB wp_wc_admin_note_actions: Data: 0.08MB + Index: 0.02MB + Engine InnoDB wp_wc_category_lookup: Data: 0.02MB + Index: 0.00MB + Engine InnoDB wp_wc_customer_lookup: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_download_log: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_orders: Data: 0.02MB + Index: 0.11MB + Engine InnoDB wp_wc_orders_meta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_order_addresses: Data: 0.02MB + Index: 0.06MB + Engine InnoDB wp_wc_order_coupon_lookup: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_order_operational_data: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_order_product_lookup: Data: 0.02MB + Index: 0.06MB + Engine InnoDB wp_wc_order_stats: Data: 0.02MB + Index: 0.05MB + Engine InnoDB wp_wc_order_tax_lookup: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_product_attributes_lookup: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_wc_product_download_directories: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_wc_product_meta_lookup: Data: 0.02MB + Index: 0.09MB + Engine InnoDB wp_wc_rate_limits: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_wc_reserved_stock: Data: 0.02MB + Index: 0.00MB + Engine InnoDB wp_wc_tax_rate_classes: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_wc_webhooks: Data: 0.02MB + Index: 0.02MB + Engine InnoDB ### Post Type Counts ### attachment: 1 page: 7 post: 1 product: 1 shop_order: 8 shop_subscription: 1 wp_navigation: 1 wp_template: 2 ### Security ### Secure connection (HTTPS): ✔ Hide errors from visitors: ✔ ### Active Plugins (6) ### Akismet Anti-Spam: Spam Protection: by Automattic - Anti Spam Team – 5.2 Jetpack Protect: by Automattic - Jetpack Security team – 1.4.1 Jetpack: by Automattic – 12.5-a.7 WooCommerce Payfast Gateway: by WooCommerce – 1.5.7 WooCommerce Subscriptions: by WooCommerce – 5.4.0 WooCommerce: by Automattic – 8.0.1 ### Inactive Plugins (0) ### ### Dropin Plugins (2) ### advanced-cache.php: advanced-cache.php object-cache.php: Memcached ### Settings ### API Enabled: – Force SSL: – Currency: ZAR (R) Currency Position: left Thousand Separator: , Decimal Separator: . Number of Decimals: 2 Taxonomies: Product Types: external (external) grouped (grouped) simple (simple) subscription (subscription) variable (variable) variable subscription (variable-subscription) Taxonomies: Product Visibility: exclude-from-catalog (exclude-from-catalog) exclude-from-search (exclude-from-search) featured (featured) outofstock (outofstock) rated-1 (rated-1) rated-2 (rated-2) rated-3 (rated-3) rated-4 (rated-4) rated-5 (rated-5) Connected to WooCommerce.com: – Enforce Approved Product Download Directories: ✔ HPOS feature screen enabled: – HPOS feature enabled: – Order datastore: WC_Order_Data_Store_CPT HPOS data sync enabled: – ### WC Pages ### Shop base: #5 - /shop/ Cart: #6 - /cart/ Checkout: #7 - /checkout/ My account: #8 - /my-account/ Terms and conditions: ❌ Page not set ### Theme ### Name: Storefront Version: 4.5.2 Author URL: https://woocommerce.com/ Child Theme: ❌ – If you are modifying WooCommerce on a parent theme that you did not build personally we recommend using a child theme. See: How to create a child theme WooCommerce Support: ✔ ### Templates ### Overrides: – ### Subscriptions ### WCS_DEBUG: ✔ No Subscriptions Mode: ✔ Live Subscriptions Live URL: [redacted] Subscriptions-core Library Version: 6.2.0 Subscription Statuses: wc-active: 1 WooCommerce Account Connected: ❌ No Report Cache Enabled: ✔ Yes Cache Update Failures: ✔ 0 failure ### Store Setup ### Country / State: South Africa — Western Cape ### Subscriptions by Payment Gateway ### Payfast: wc-active: 1 ### Payment Gateway Support ### Payfast: products pre-orders subscriptions subscription_cancellation subscription_suspension subscription_reactivation subscription_amount_changes subscription_date_changes subscription_payment_method_change subscription_payment_method_change_customer ### Admin ### Enabled Features: activity-panels analytics product-block-editor coupons core-profiler customer-effort-score-tracks import-products-task experimental-fashion-sample-products shipping-smart-defaults shipping-setting-tour homescreen marketing mobile-app-banner navigation onboarding onboarding-tasks remote-inbox-notifications remote-free-extensions payment-gateway-suggestions shipping-label-banner subscriptions store-alerts transient-notices woo-mobile-welcome wc-pay-promotion wc-pay-welcome-page Disabled Features: minified-js new-product-management-experience product-variation-management settings async-product-editor-category-field Daily Cron: ✔ Next scheduled: 2023-08-15 05:09:00 +00:00 Options: ✔ Notes: 69 Onboarding: - ### Action Scheduler ### Complete: 30 Oldest: 2023-08-14 05:09:12 +0000 Newest: 2023-08-14 06:10:13 +0000 Failed: 3 Oldest: 2023-08-14 05:18:36 +0000 Newest: 2023-08-14 05:44:51 +0000 Pending: 4 Oldest: 2023-08-14 06:25:13 +0000 Newest: 2023-09-14 05:21:15 +0000 ### Status report information ### Generated at: 2023-08-14 06:23:04 +00:00 ` ```
iamdharmesh commented 8 months ago

Thanks for reporting this @nicdwilson. I followed the reproduce steps and I an not able to reproduce the issue. Changed subscription total multiple times and renewed subscription multiple times.

image

I attempted to check into the code and discovered that we already have a check to ignore the amount comparison if the order contains the subscription. Could we check with the reporter to determine if they are facing this issue with all subscriptions or only with one of the subscriptions, which may be due to some data deletion?

Thank you.

nicdwilson commented 8 months ago

@iamdharmesh This is quite an old report, and I can dig into it again if you like. The reporter was experiencing it on multiple cases, and I was able to reproduce the error, as in the logs above.

A second reporter made their own code changes to avoid the issue.

Does your [m_payment_id] match [custom_str3] in the submission? To me, this appeared to be the cause of the problem.

iamdharmesh commented 8 months ago

@nicdwilson, thank you very much for the quick response.

Does your [m_payment_id] match [custom_str3] in the submission? To me, this appeared to be the cause of the problem.

[m_payment_id] and [custom_str3] contain the parent order ID for me, which does not match the renewal order ID. According to the code, we retrieve the renewal order ID from the item_description field. The reason I am unable to reproduce this issue is because of the AND condition in the ITN handler ! $this->order_contains_subscription( $order_id ), which ignores the amount comparison if the payment is an order that contains the subscription.

It seems like I might be doing something wrong in my attempt to reproduce this issue. @ankitguptaindia, could you please help in reproducing this on your end?

Thank you

ankitguptaindia commented 8 months ago

@iamdharmesh

It seems like I might be doing something wrong in my attempt to reproduce this issue. @ankitguptaindia, could you please help in reproducing this on your end?

I followed the steps outlined in the description, and I achieved the expected result.

nicdwilson commented 8 months ago

Hi there Apologies for the delay, but it's been a while and I had to rebuild a site for testing. I am not able to reproduce, and the values returned remain in sync. Potentially, this was actually a problem on the PayFast side, since they did seem to be returning a random mismatched order number in [custom_str3] which is odd behaviour. If that was invalid, or was a valid number order number without a subscription, it would also have bypassed the check for a subscription in the order. I'm going to close this issue.

iamdharmesh commented 8 months ago

@nicdwilson, Thank you for checking further on this and sharing the root cause.