After activating commerce_stripe in a production environment, I did a test order, and after that of course refunded the payment (via Drupal admin UI). After realizing that I've configured the wrong notification endpoint in Stripe - I took the README too literally and entered /payment/notify/stripe_payment_element, although my payment gateway config is just named "stripe" - I adjusted the configuration and tried to resend the failed API callbacks in Stripe admin UI.

First, I resent the previously failed payment_intent.succeeded notification - it now succeeded. Next, I tried to resend the "charge.refunded" as well, but ended in a 500 HTTP error in Drupal:

TypeError: reset(): Argument #1 ($array) must be of type array, null given in reset() (Zeile 445 in /web/modules/contrib/commerce_stripe/src/Plugin/Commerce/PaymentGateway/StripePaymentElement.php)

I took a look at the code, line 445 is:

$latest_refund = reset($object['refunds']['data']);

Whereas $object is set to this:

$object = $request_body['data']['object'];

Thank god, Stripe has a very detailed logging exposed in the admin interface, so we can look at the requests they are sending. According to this, the $object does not contain a key "refunds", nor "data". instead, it looks like this (starting from the outer "data" key, replaced some sensitive infos with "XXXXX"):

  "data": {
    "object": {
      "id": "XXXXX",
      "object": "charge",
      "amount": 21000,
      "amount_captured": 21000,
      "amount_refunded": 21000,
      "application": null,
      "application_fee": null,
      "application_fee_amount": null,
      "balance_transaction": "XXXXX",
      "billing_details": {
        "address": {
          "city": null,
          "country": "XXXXX",
          "line1": null,
          "line2": null,
          "postal_code": "XXXXX",
          "state": null
        },
        "email": null,
        "name": null,
        "phone": null
      },
      "calculated_statement_descriptor": "XXXXX",
      "captured": true,
      "created": 1702284253,
      "currency": "eur",
      "customer": null,
      "description": null,
      "destination": null,
      "dispute": null,
      "disputed": false,
      "failure_balance_transaction": null,
      "failure_code": null,
      "failure_message": null,
      "fraud_details": {
      },
      "invoice": null,
      "livemode": true,
      "metadata": {
        "order_id": "1",
        "store_id": "1"
      },
      "on_behalf_of": null,
      "order": null,
      "outcome": {
        "network_status": "approved_by_network",
        "reason": null,
        "risk_level": "normal",
        "seller_message": "Payment complete.",
        "type": "authorized"
      },
      "paid": true,
      "payment_intent": "XXXXX",
      "payment_method": "XXXXX",
      "payment_method_details": {
        "card": {
          "amount_authorized": 21000,
          "brand": "mastercard",
          "checks": {
            "address_line1_check": null,
            "address_postal_code_check": "unavailable",
            "cvc_check": "pass"
          },
          "country": "AT",
          "exp_month": 5,
          "exp_year": 2024,
          "extended_authorization": {
            "status": "disabled"
          },
          "fingerprint": "XXXXX",
          "funding": "credit",
          "incremental_authorization": {
            "status": "unavailable"
          },
          "installments": null,
          "last4": "XXXXX",
          "mandate": null,
          "multicapture": {
            "status": "unavailable"
          },
          "network": "mastercard",
          "network_token": {
            "used": false
          },
          "overcapture": {
            "maximum_amount_capturable": 21000,
            "status": "unavailable"
          },
          "three_d_secure": {
            "authentication_flow": "frictionless",
            "electronic_commerce_indicator": "02",
            "exemption_indicator": null,
            "result": "authenticated",
            "result_reason": null,
            "transaction_id": "XXXXX",
            "version": "2.2.0"
          },
          "wallet": null
        },
        "type": "card"
      },
      "receipt_email": null,
      "receipt_number": null,
      "receipt_url": "https://pay.stripe.com/receipts/payment/XXXXX",
      "refunded": true,
      "review": null,
      "shipping": {
        "address": {
          "city": "XXXXX",
          "country": "XXXXX",
          "line1": "XXXXX",
          "line2": "",
          "postal_code": "XXXXX",
          "state": null
        },
        "carrier": null,
        "name": "XXXXX",
        "phone": null,
        "tracking_number": null
      },
      "source": null,
      "source_transfer": null,
      "statement_descriptor": null,
      "statement_descriptor_suffix": null,
      "status": "succeeded",
      "transfer_data": null,
      "transfer_group": null
    },
    "previous_attributes": {
      "amount_refunded": 0,
      "receipt_url": "https://pay.stripe.com/receipts/payment/XXXXX",
      "refunded": false
    }
  },

I don't know, whether this happens because it's a subsequent trial of a failed notification, but this wouldn't make any sense imho

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

agoradesign created an issue. See original summary.

tomtech’s picture

Assigned: Unassigned » tomtech

Stripe payload depends on the version selected when you create your webhook.

Unfortunately, they only support your default (which is normally the "latest" version when you created your stripe account, or latest (if your default is not the latest.) No other versions. can be selected.

We have a change in the pipeline that will resolve this, regardless of the version configured in your webhook.

tomtech’s picture

Status: Active » Needs review

MR created that addresses this issue.

  • TomTech committed c73f11a1 on 8.x-1.x
    Issue #3407873 by TomTech, agoradesign: The charge.refunded webhook...
tomtech’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.