From ef89edbd23d20fa3e409679dc5d30f16d8f1870c Mon Sep 17 00:00:00 2001 From: Sam Willcocks Date: Sun, 11 Feb 2024 11:43:44 +0000 Subject: [PATCH] Fix test_purchase --- README.md | 4 + .../test_create_stripe_purchase.yaml | 464 ++++++++++++------ tests/test_purchase.py | 10 +- tests/webhook_fixtures/charge.refunded.json | 89 ++-- .../payment_intent.succeeded.json | 142 +----- 5 files changed, 394 insertions(+), 315 deletions(-) diff --git a/README.md b/README.md index 7e70e6ccf..4a6204b66 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,10 @@ Or, you can create an account and simultaneously make it an admin by using `./fl E-mail sending is disabled in development (but is printed out on the console). You can also log in directly by setting `BYPASS_LOGIN=True` in `config/development.cfg` and then using a URL of the form e.g. `/login/admin@test.invalid`. +### Testing payments + +The easiest way to test the payments flow (marginally less easy if you don't have a Stripe account) is to use Stripe test keys and pay by card with Stripe's test cards. To test incoming webhooks you can use a service like ngrok or tailscale funnel to expose your local dev instance to the web (temporarily!). + ### Database Migrations - `./flask db migrate -m 'Migration name'` to generate migration scripts when models have been updated. diff --git a/tests/cassettes/test_create_stripe_purchase.yaml b/tests/cassettes/test_create_stripe_purchase.yaml index 0db69b416..5b904ff22 100644 --- a/tests/cassettes/test_create_stripe_purchase.yaml +++ b/tests/cassettes/test_create_stripe_purchase.yaml @@ -1,82 +1,101 @@ interactions: - request: - body: amount=23000¤cy=GBP&statement_descriptor_suffix=EMF+2020+purchase&metadata[user_id]=1&metadata[payment_id]=1 + body: amount=23000¤cy=GBP&statement_descriptor_suffix=EMF+2025+purchase&metadata[user_id]=1&metadata[payment_id]=1 headers: Accept: - '*/*' Accept-Encoding: - - gzip, deflate + - gzip, deflate, br Connection: - keep-alive + Content-Length: + - '114' Content-Type: - application/x-www-form-urlencoded Idempotency-Key: - - 467112d0-3ed0-4d55-90f6-04599a2fdca5 + - 90582ef1-1afd-4010-97ed-ad91e3b01c5d + Stripe-Version: + - '2023-10-16' User-Agent: - - Stripe/v1 PythonBindings/2.38.0 + - Stripe/v1 PythonBindings/8.0.0 X-Stripe-Client-User-Agent: - - '{"bindings_version": "2.38.0", "lang": "python", "publisher": "stripe", "httplib": - "requests", "lang_version": "3.7.6", "platform": "Linux-4.19.76-linuxkit-x86_64-with-debian-10.2", - "uname": "Linux d9e02b76d0f1 4.19.76-linuxkit #1 SMP Thu Oct 17 19:31:58 UTC - 2019 x86_64 "}' + - '{"bindings_version": "8.0.0", "lang": "python", "publisher": "stripe", "httplib": + "requests", "lang_version": "3.11.7", "platform": "Linux-5.15.49-linuxkit-aarch64-with-glibc2.31", + "uname": "Linux 5cb7915c0fb8 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 + UTC 2022 aarch64 "}' + authorization: + - DUMMY method: POST uri: https://api.stripe.com/v1/payment_intents response: body: - string: "{\n \"id\": \"pi_1GUslpIcI91cWsdeheAuRsyg\",\n \"object\": \"payment_intent\"\ - ,\n \"allowed_source_types\": [\n \"card\"\n ],\n \"amount\": 23000,\n\ - \ \"amount_capturable\": 0,\n \"amount_received\": 0,\n \"application\"\ - : null,\n \"application_fee_amount\": null,\n \"canceled_at\": null,\n \ - \ \"cancellation_reason\": null,\n \"capture_method\": \"automatic\",\n \ - \ \"charges\": {\n \"object\": \"list\",\n \"data\": [\n\n ],\n \ - \ \"has_more\": false,\n \"total_count\": 0,\n \"url\": \"/v1/charges?payment_intent=pi_1GUslpIcI91cWsdeheAuRsyg\"\ - \n },\n \"client_secret\": \"pi_1GUslpIcI91cWsdeheAuRsyg_secret_jm7QnCtrTMjZKeYmqmmmlXZlj\"\ - ,\n \"confirmation_method\": \"automatic\",\n \"created\": 1586161027,\n\ - \ \"currency\": \"gbp\",\n \"customer\": null,\n \"description\": null,\n\ - \ \"invoice\": null,\n \"last_payment_error\": null,\n \"livemode\": false,\n\ - \ \"metadata\": {\n \"user_id\": \"1\",\n \"payment_id\": \"1\"\n \ - \ },\n \"next_action\": null,\n \"next_source_action\": null,\n \"on_behalf_of\"\ - : null,\n \"payment_method\": null,\n \"payment_method_options\": {\n \ - \ \"card\": {\n \"installments\": null,\n \"request_three_d_secure\"\ - : \"automatic\"\n }\n },\n \"payment_method_types\": [\n \"card\"\n\ - \ ],\n \"receipt_email\": null,\n \"review\": null,\n \"setup_future_usage\"\ - : null,\n \"shipping\": null,\n \"source\": null,\n \"statement_descriptor\"\ - : null,\n \"statement_descriptor_suffix\": \"EMF 2020 purchase\",\n \"status\"\ - : \"requires_source\",\n \"transfer_data\": null,\n \"transfer_group\":\ - \ null\n}\n" + string: "{\n \"id\": \"pi_3OiHFbHz0MWR65Xj0KidZr5i\",\n \"object\": \"payment_intent\",\n + \ \"amount\": 23000,\n \"amount_capturable\": 0,\n \"amount_details\": {\n + \ \"tip\": {}\n },\n \"amount_received\": 0,\n \"application\": null,\n + \ \"application_fee_amount\": null,\n \"automatic_payment_methods\": {\n + \ \"allow_redirects\": \"always\",\n \"enabled\": true\n },\n \"canceled_at\": + null,\n \"cancellation_reason\": null,\n \"capture_method\": \"automatic\",\n + \ \"client_secret\": \"pi_3OiHFbHz0MWR65Xj0KidZr5i_secret_Z9ikdFm8aaFuujx7VMlfTHP4M\",\n + \ \"confirmation_method\": \"automatic\",\n \"created\": 1707574191,\n \"currency\": + \"gbp\",\n \"customer\": null,\n \"description\": null,\n \"invoice\": + null,\n \"last_payment_error\": null,\n \"latest_charge\": null,\n \"livemode\": + false,\n \"metadata\": {\n \"payment_id\": \"1\",\n \"user_id\": \"1\"\n + \ },\n \"next_action\": null,\n \"on_behalf_of\": null,\n \"payment_method\": + null,\n \"payment_method_configuration_details\": null,\n \"payment_method_options\": + {\n \"card\": {\n \"installments\": null,\n \"mandate_options\": + null,\n \"network\": null,\n \"request_three_d_secure\": \"automatic\"\n + \ }\n },\n \"payment_method_types\": [\n \"card\"\n ],\n \"processing\": + null,\n \"receipt_email\": null,\n \"review\": null,\n \"setup_future_usage\": + null,\n \"shipping\": null,\n \"source\": null,\n \"statement_descriptor\": + null,\n \"statement_descriptor_suffix\": \"EMF 2025 purchase\",\n \"status\": + \"requires_payment_method\",\n \"transfer_data\": null,\n \"transfer_group\": + null\n}" headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Methods: + - GET,HEAD,PUT,PATCH,POST,DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required, + X-Stripe-Privileged-Session-Required + Access-Control-Max-Age: + - '300' + Cache-Control: + - no-cache, no-store Connection: - keep-alive + Content-Length: + - '1439' + Content-Security-Policy: + - report-uri https://q.stripe.com/csp-report?p=v1%2Fpayment_intents; block-all-mixed-content; + default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'; + img-src 'self'; script-src 'self' 'report-sample'; style-src 'self' Content-Type: - application/json Date: - - Mon, 06 Apr 2020 08:17:07 GMT + - Sat, 10 Feb 2024 14:09:52 GMT + Idempotency-Key: + - 90582ef1-1afd-4010-97ed-ad91e3b01c5d + Original-Request: + - req_reP2uzOE3Oy0vT + Request-Id: + - req_reP2uzOE3Oy0vT Server: - nginx Strict-Transport-Security: - - max-age=31556926; includeSubDomains; preload - access-control-allow-credentials: - - 'true' - access-control-allow-methods: - - GET, POST, HEAD, OPTIONS, DELETE - access-control-allow-origin: - - '*' - access-control-expose-headers: - - Request-Id, Stripe-Manage-Version, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required - access-control-max-age: - - '300' - cache-control: - - no-cache, no-store - idempotency-key: - - 467112d0-3ed0-4d55-90f6-04599a2fdca5 - original-request: - - req_MGgq5mNOSPFvrt - request-id: - - req_MGgq5mNOSPFvrt - stripe-should-retry: + - max-age=63072000; includeSubDomains; preload + Stripe-Should-Retry: - 'false' - stripe-version: - - '2016-07-06' + Stripe-Version: + - '2023-10-16' + Vary: + - Origin + X-Stripe-Non-Api-Overhead-Duration-Ms: + - '142.0' + X-Stripe-Routing-Context-Priority-Tier: + - api-testmode status: code: 200 message: OK @@ -86,155 +105,296 @@ interactions: Accept: - '*/*' Accept-Encoding: - - gzip, deflate + - gzip, deflate, br Connection: - keep-alive + Stripe-Version: + - '2023-10-16' User-Agent: - - Stripe/v1 PythonBindings/2.38.0 - X-Stripe-Client-Telemetry: - - '{"last_request_metrics": {"request_id": "req_MGgq5mNOSPFvrt", "request_duration_ms": - 305}}' + - Stripe/v1 PythonBindings/8.0.0 X-Stripe-Client-User-Agent: - - '{"bindings_version": "2.38.0", "lang": "python", "publisher": "stripe", "httplib": - "requests", "lang_version": "3.7.6", "platform": "Linux-4.19.76-linuxkit-x86_64-with-debian-10.2", - "uname": "Linux d9e02b76d0f1 4.19.76-linuxkit #1 SMP Thu Oct 17 19:31:58 UTC - 2019 x86_64 "}' + - '{"bindings_version": "8.0.0", "lang": "python", "publisher": "stripe", "httplib": + "requests", "lang_version": "3.11.7", "platform": "Linux-5.15.49-linuxkit-aarch64-with-glibc2.31", + "uname": "Linux 5cb7915c0fb8 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 + UTC 2022 aarch64 "}' + authorization: + - DUMMY method: GET - uri: https://api.stripe.com/v1/charges/ch_1GUslxIcI91cWsde5jePBfRQ + uri: https://api.stripe.com/v1/charges/ch_3OibCXHz0MWR65Xj09SoiLkW response: body: - string: "{\n \"id\": \"ch_1GUslxIcI91cWsde5jePBfRQ\",\n \"object\": \"charge\"\ - ,\n \"amount\": 23000,\n \"amount_refunded\": 0,\n \"application\": null,\n\ - \ \"application_fee\": null,\n \"application_fee_amount\": null,\n \"balance_transaction\"\ - : \"txn_1GUslxIcI91cWsdenOKhyR4i\",\n \"billing_details\": {\n \"address\"\ - : {\n \"city\": null,\n \"country\": null,\n \"line1\": null,\n\ - \ \"line2\": null,\n \"postal_code\": \"42424\",\n \"state\"\ - : null\n },\n \"email\": \"test@example.com\",\n \"name\": \"Test\"\ - ,\n \"phone\": null\n },\n \"calculated_statement_descriptor\": \"EMFCAMP*\ - \ EMF 2020 P\",\n \"captured\": true,\n \"created\": 1586171145,\n \"currency\"\ - : \"gbp\",\n \"customer\": null,\n \"description\": null,\n \"destination\"\ - : null,\n \"dispute\": null,\n \"disputed\": false,\n \"failure_code\"\ - : null,\n \"failure_message\": null,\n \"fraud_details\": {\n },\n \"\ - invoice\": null,\n \"livemode\": false,\n \"metadata\": {\n \"user_id\"\ - : \"1\",\n \"payment_id\": \"2\"\n },\n \"on_behalf_of\": null,\n \"\ - order\": null,\n \"outcome\": {\n \"network_status\": \"approved_by_network\"\ - ,\n \"reason\": null,\n \"risk_level\": \"normal\",\n \"risk_score\"\ - : 55,\n \"seller_message\": \"Payment complete.\",\n \"type\": \"authorized\"\ - \n },\n \"paid\": true,\n \"payment_intent\": \"pi_1GUslpIcI91cWsdeheAuRsyg\"\ - ,\n \"payment_method\": \"pm_1GUslxIcI91cWsdeBYozsFYU\",\n \"payment_method_details\"\ - : {\n \"card\": {\n \"brand\": \"visa\",\n \"checks\": {\n \ - \ \"address_line1_check\": null,\n \"address_postal_code_check\"\ - : \"pass\",\n \"cvc_check\": \"pass\"\n },\n \"country\"\ - : \"US\",\n \"exp_month\": 4,\n \"exp_year\": 2024,\n \"fingerprint\"\ - : \"VKnD4kq2Jm2zibNl\",\n \"funding\": \"credit\",\n \"installments\"\ - : null,\n \"last4\": \"4242\",\n \"network\": \"visa\",\n \"\ - three_d_secure\": null,\n \"wallet\": null\n },\n \"type\": \"\ - card\"\n },\n \"receipt_email\": null,\n \"receipt_number\": null,\n \"\ - receipt_url\": \"https://pay.stripe.com/receipts/acct_14i5G7IcI91cWsde/ch_1GUslxIcI91cWsde5jePBfRQ/rcpt_H2yjkWzJc46LbnTbSqH7RdXWbbaVDSU\"\ - ,\n \"refunded\": false,\n \"refunds\": {\n \"object\": \"list\",\n \ - \ \"data\": [\n\n ],\n \"has_more\": false,\n \"total_count\":\ - \ 0,\n \"url\": \"/v1/charges/ch_1GUslxIcI91cWsde5jePBfRQ/refunds\"\n \ - \ },\n \"review\": null,\n \"shipping\": null,\n \"source\": null,\n \"\ - source_transfer\": null,\n \"statement_descriptor\": null,\n \"statement_descriptor_suffix\"\ - : \"EMF 2020 purchase\",\n \"status\": \"succeeded\",\n \"transfer_data\"\ - : null,\n \"transfer_group\": null\n}\n" + string: "{\n \"id\": \"ch_3OibCXHz0MWR65Xj09SoiLkW\",\n \"object\": \"charge\",\n + \ \"amount\": 21000,\n \"amount_captured\": 21000,\n \"amount_refunded\": + 0,\n \"application\": null,\n \"application_fee\": null,\n \"application_fee_amount\": + null,\n \"balance_transaction\": \"txn_3OibCXHz0MWR65Xj0FGYSo9U\",\n \"billing_details\": + {\n \"address\": {\n \"city\": null,\n \"country\": null,\n \"line1\": + null,\n \"line2\": null,\n \"postal_code\": \"11111\",\n \"state\": + null\n },\n \"email\": \"test@example.com\",\n \"name\": \"Initial Admin + User\",\n \"phone\": null\n },\n \"calculated_statement_descriptor\": + \"STRIPE* EMF 2022 PURCH\",\n \"captured\": true,\n \"created\": 1707650896,\n + \ \"currency\": \"gbp\",\n \"customer\": null,\n \"description\": null,\n + \ \"destination\": null,\n \"dispute\": null,\n \"disputed\": false,\n \"failure_balance_transaction\": + null,\n \"failure_code\": null,\n \"failure_message\": null,\n \"fraud_details\": + {},\n \"invoice\": null,\n \"livemode\": false,\n \"metadata\": {\n \"payment_id\": + \"1\",\n \"user_id\": \"1\"\n },\n \"on_behalf_of\": null,\n \"order\": + null,\n \"outcome\": {\n \"network_status\": \"approved_by_network\",\n + \ \"reason\": null,\n \"risk_level\": \"normal\",\n \"risk_score\": + 47,\n \"seller_message\": \"Payment complete.\",\n \"type\": \"authorized\"\n + \ },\n \"paid\": true,\n \"payment_intent\": \"pi_3OibCXHz0MWR65Xj0sgHN7Ni\",\n + \ \"payment_method\": \"pm_1OibCmHz0MWR65XjLoAoi9pj\",\n \"payment_method_details\": + {\n \"card\": {\n \"amount_authorized\": 21000,\n \"brand\": + \"visa\",\n \"checks\": {\n \"address_line1_check\": null,\n \"address_postal_code_check\": + \"pass\",\n \"cvc_check\": \"pass\"\n },\n \"country\": \"US\",\n + \ \"exp_month\": 1,\n \"exp_year\": 2030,\n \"extended_authorization\": + {\n \"status\": \"disabled\"\n },\n \"fingerprint\": \"qyoEjYqy9x1BibQI\",\n + \ \"funding\": \"credit\",\n \"incremental_authorization\": {\n \"status\": + \"unavailable\"\n },\n \"installments\": null,\n \"last4\": + \"4242\",\n \"mandate\": null,\n \"multicapture\": {\n \"status\": + \"unavailable\"\n },\n \"network\": \"visa\",\n \"network_token\": + {\n \"used\": false\n },\n \"overcapture\": {\n \"maximum_amount_capturable\": + 21000,\n \"status\": \"unavailable\"\n },\n \"three_d_secure\": + null,\n \"wallet\": null\n },\n \"type\": \"card\"\n },\n \"radar_options\": + {},\n \"receipt_email\": null,\n \"receipt_number\": null,\n \"receipt_url\": + \"https://pay.stripe.com/receipts/payment/CAcaFwoVYWNjdF8xT2RocXVIejBNV1I2NVhqKIjgoq4GMgYedyoyka46LBahzyoz_mteiHuUGNdxRBku7tg6ApTa33nAeRp-PNF-XsrlCpM5MQnZwei3\",\n + \ \"refunded\": false,\n \"review\": null,\n \"shipping\": null,\n \"source\": + null,\n \"source_transfer\": null,\n \"statement_descriptor\": null,\n \"statement_descriptor_suffix\": + \"EMF 2022 purchase\",\n \"status\": \"succeeded\",\n \"transfer_data\": + null,\n \"transfer_group\": null\n}" headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Methods: + - GET,HEAD,PUT,PATCH,POST,DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required, + X-Stripe-Privileged-Session-Required + Access-Control-Max-Age: + - '300' + Cache-Control: + - no-cache, no-store Connection: - keep-alive + Content-Length: + - '2807' + Content-Security-Policy: + - report-uri https://q.stripe.com/csp-report?p=v1%2Fcharges%2F%3Acharge; block-all-mixed-content; + default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'; + img-src 'self'; script-src 'self' 'report-sample'; style-src 'self' Content-Type: - application/json Date: - - Tue, 07 Apr 2020 10:35:03 GMT + - Sun, 11 Feb 2024 11:31:20 GMT + Request-Id: + - req_VdpSuQFycMuN0D Server: - nginx Strict-Transport-Security: - - max-age=31556926; includeSubDomains; preload - access-control-allow-credentials: - - 'true' - access-control-allow-methods: - - GET, POST, HEAD, OPTIONS, DELETE - access-control-allow-origin: - - '*' - access-control-expose-headers: - - Request-Id, Stripe-Manage-Version, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required - access-control-max-age: - - '300' - cache-control: - - no-cache, no-store - request-id: - - req_PTgYlSPVyo8kBl - stripe-version: - - '2016-07-06' + - max-age=63072000; includeSubDomains; preload + Stripe-Version: + - '2023-10-16' + Vary: + - Origin + X-Stripe-Non-Api-Overhead-Duration-Ms: + - '79.99999999999999' + X-Stripe-Routing-Context-Priority-Tier: + - api-testmode status: code: 200 message: OK - request: - body: charge=ch_1GUslxIcI91cWsde5jePBfRQ&amount=21000&metadata[refund_request]=1 + body: charge=ch_3OibCXHz0MWR65Xj09SoiLkW&amount=21000&metadata[refund_request]=1 headers: Accept: - '*/*' Accept-Encoding: - - gzip, deflate + - gzip, deflate, br Connection: - keep-alive + Content-Length: + - '74' Content-Type: - application/x-www-form-urlencoded Idempotency-Key: - - 14d0d6b0-d636-49bb-998a-a3a517a392aa + - 37370c9d-b7ea-42d2-b8d0-b70e33e2e0d4 + Stripe-Version: + - '2023-10-16' User-Agent: - - Stripe/v1 PythonBindings/2.38.0 + - Stripe/v1 PythonBindings/8.0.0 X-Stripe-Client-Telemetry: - - '{"last_request_metrics": {"request_id": "req_PTgYlSPVyo8kBl", "request_duration_ms": - 453}}' + - '{"last_request_metrics": {"request_id": "req_VdpSuQFycMuN0D", "request_duration_ms": + 0}}' X-Stripe-Client-User-Agent: - - '{"bindings_version": "2.38.0", "lang": "python", "publisher": "stripe", "httplib": - "requests", "lang_version": "3.7.6", "platform": "Linux-4.19.76-linuxkit-x86_64-with-debian-10.2", - "uname": "Linux d9e02b76d0f1 4.19.76-linuxkit #1 SMP Thu Oct 17 19:31:58 UTC - 2019 x86_64 "}' + - '{"bindings_version": "8.0.0", "lang": "python", "publisher": "stripe", "httplib": + "requests", "lang_version": "3.11.7", "platform": "Linux-5.15.49-linuxkit-aarch64-with-glibc2.31", + "uname": "Linux 5cb7915c0fb8 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 + UTC 2022 aarch64 "}' + authorization: + - DUMMY method: POST uri: https://api.stripe.com/v1/refunds response: body: - string: "{\n \"id\": \"re_1GVEloIcI91cWsdemdIEKjOK\",\n \"object\": \"refund\"\ - ,\n \"amount\": 21000,\n \"balance_transaction\": \"txn_1GVEloIcI91cWsdeWsmUp4Fr\"\ - ,\n \"charge\": \"ch_1GUslxIcI91cWsde5jePBfRQ\",\n \"created\": 1586255704,\n\ - \ \"currency\": \"gbp\",\n \"metadata\": {\n \"refund_request\": \"1\"\ - \n },\n \"payment_intent\": \"pi_1GUslpIcI91cWsdeheAuRsyg\",\n \"reason\"\ - : null,\n \"receipt_number\": null,\n \"source_transfer_reversal\": null,\n\ - \ \"status\": \"succeeded\",\n \"transfer_reversal\": null\n}\n" + string: "{\n \"id\": \"re_3OibCXHz0MWR65Xj0KIi9Hq0\",\n \"object\": \"refund\",\n + \ \"amount\": 21000,\n \"balance_transaction\": \"txn_3OibCXHz0MWR65Xj0q14l4Pn\",\n + \ \"charge\": \"ch_3OibCXHz0MWR65Xj09SoiLkW\",\n \"created\": 1707651081,\n + \ \"currency\": \"gbp\",\n \"destination_details\": {\n \"card\": {\n + \ \"reference_status\": \"pending\",\n \"reference_type\": \"acquirer_reference_number\",\n + \ \"type\": \"refund\"\n },\n \"type\": \"card\"\n },\n \"metadata\": + {\n \"refund_request\": \"1\"\n },\n \"payment_intent\": \"pi_3OibCXHz0MWR65Xj0sgHN7Ni\",\n + \ \"reason\": null,\n \"receipt_number\": null,\n \"source_transfer_reversal\": + null,\n \"status\": \"succeeded\",\n \"transfer_reversal\": null\n}" headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Methods: + - GET,HEAD,PUT,PATCH,POST,DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required, + X-Stripe-Privileged-Session-Required + Access-Control-Max-Age: + - '300' + Cache-Control: + - no-cache, no-store Connection: - keep-alive + Content-Length: + - '645' + Content-Security-Policy: + - report-uri https://q.stripe.com/csp-report?p=v1%2Frefunds; block-all-mixed-content; + default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'; + img-src 'self'; script-src 'self' 'report-sample'; style-src 'self' Content-Type: - application/json Date: - - Tue, 07 Apr 2020 10:35:04 GMT + - Sun, 11 Feb 2024 11:31:21 GMT + Idempotency-Key: + - 37370c9d-b7ea-42d2-b8d0-b70e33e2e0d4 + Original-Request: + - req_fQu9FhEOR2ZON5 + Request-Id: + - req_fQu9FhEOR2ZON5 Server: - nginx Strict-Transport-Security: - - max-age=31556926; includeSubDomains; preload - access-control-allow-credentials: + - max-age=63072000; includeSubDomains; preload + Stripe-Should-Retry: + - 'false' + Stripe-Version: + - '2023-10-16' + Vary: + - Origin + X-Stripe-Non-Api-Overhead-Duration-Ms: + - '764.0' + X-Stripe-Routing-Context-Priority-Tier: + - api-testmode + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, br + Connection: + - keep-alive + Stripe-Version: + - '2023-10-16' + User-Agent: + - Stripe/v1 PythonBindings/8.0.0 + X-Stripe-Client-User-Agent: + - '{"bindings_version": "8.0.0", "lang": "python", "publisher": "stripe", "httplib": + "requests", "lang_version": "3.11.7", "platform": "Linux-5.15.49-linuxkit-aarch64-with-glibc2.31", + "uname": "Linux 5cb7915c0fb8 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 + UTC 2022 aarch64 "}' + authorization: + - DUMMY + method: GET + uri: https://api.stripe.com/v1/charges/ch_3OibCXHz0MWR65Xj09SoiLkW + response: + body: + string: "{\n \"id\": \"ch_3OibCXHz0MWR65Xj09SoiLkW\",\n \"object\": \"charge\",\n + \ \"amount\": 21000,\n \"amount_captured\": 21000,\n \"amount_refunded\": + 21000,\n \"application\": null,\n \"application_fee\": null,\n \"application_fee_amount\": + null,\n \"balance_transaction\": \"txn_3OibCXHz0MWR65Xj0FGYSo9U\",\n \"billing_details\": + {\n \"address\": {\n \"city\": null,\n \"country\": null,\n \"line1\": + null,\n \"line2\": null,\n \"postal_code\": \"11111\",\n \"state\": + null\n },\n \"email\": \"test@example.com\",\n \"name\": \"Initial Admin + User\",\n \"phone\": null\n },\n \"calculated_statement_descriptor\": + \"STRIPE* EMF 2022 PURCH\",\n \"captured\": true,\n \"created\": 1707650896,\n + \ \"currency\": \"gbp\",\n \"customer\": null,\n \"description\": null,\n + \ \"destination\": null,\n \"dispute\": null,\n \"disputed\": false,\n \"failure_balance_transaction\": + null,\n \"failure_code\": null,\n \"failure_message\": null,\n \"fraud_details\": + {},\n \"invoice\": null,\n \"livemode\": false,\n \"metadata\": {\n \"payment_id\": + \"1\",\n \"user_id\": \"1\"\n },\n \"on_behalf_of\": null,\n \"order\": + null,\n \"outcome\": {\n \"network_status\": \"approved_by_network\",\n + \ \"reason\": null,\n \"risk_level\": \"normal\",\n \"risk_score\": + 47,\n \"seller_message\": \"Payment complete.\",\n \"type\": \"authorized\"\n + \ },\n \"paid\": true,\n \"payment_intent\": \"pi_3OibCXHz0MWR65Xj0sgHN7Ni\",\n + \ \"payment_method\": \"pm_1OibCmHz0MWR65XjLoAoi9pj\",\n \"payment_method_details\": + {\n \"card\": {\n \"amount_authorized\": 21000,\n \"brand\": + \"visa\",\n \"checks\": {\n \"address_line1_check\": null,\n \"address_postal_code_check\": + \"pass\",\n \"cvc_check\": \"pass\"\n },\n \"country\": \"US\",\n + \ \"exp_month\": 1,\n \"exp_year\": 2030,\n \"extended_authorization\": + {\n \"status\": \"disabled\"\n },\n \"fingerprint\": \"qyoEjYqy9x1BibQI\",\n + \ \"funding\": \"credit\",\n \"incremental_authorization\": {\n \"status\": + \"unavailable\"\n },\n \"installments\": null,\n \"last4\": + \"4242\",\n \"mandate\": null,\n \"multicapture\": {\n \"status\": + \"unavailable\"\n },\n \"network\": \"visa\",\n \"network_token\": + {\n \"used\": false\n },\n \"overcapture\": {\n \"maximum_amount_capturable\": + 21000,\n \"status\": \"unavailable\"\n },\n \"three_d_secure\": + null,\n \"wallet\": null\n },\n \"type\": \"card\"\n },\n \"radar_options\": + {},\n \"receipt_email\": null,\n \"receipt_number\": null,\n \"receipt_url\": + \"https://pay.stripe.com/receipts/payment/CAcaFwoVYWNjdF8xT2RocXVIejBNV1I2NVhqKLbgoq4GMgawEAmvi6s6LBbS3hgKtCJtw4QOESWGae5cq9wU8F8Yv5Zf9dij-gcQ_bDQ_jpJAkZG_QbK\",\n + \ \"refunded\": true,\n \"review\": null,\n \"shipping\": null,\n \"source\": + null,\n \"source_transfer\": null,\n \"statement_descriptor\": null,\n \"statement_descriptor_suffix\": + \"EMF 2022 purchase\",\n \"status\": \"succeeded\",\n \"transfer_data\": + null,\n \"transfer_group\": null\n}" + headers: + Access-Control-Allow-Credentials: - 'true' - access-control-allow-methods: - - GET, POST, HEAD, OPTIONS, DELETE - access-control-allow-origin: + Access-Control-Allow-Methods: + - GET,HEAD,PUT,PATCH,POST,DELETE + Access-Control-Allow-Origin: - '*' - access-control-expose-headers: - - Request-Id, Stripe-Manage-Version, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required - access-control-max-age: + Access-Control-Expose-Headers: + - Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required, + X-Stripe-Privileged-Session-Required + Access-Control-Max-Age: - '300' - cache-control: + Cache-Control: - no-cache, no-store - idempotency-key: - - 14d0d6b0-d636-49bb-998a-a3a517a392aa - original-request: - - req_2wQMwa8QK6IquD - request-id: - - req_2wQMwa8QK6IquD - stripe-should-retry: - - 'false' - stripe-version: - - '2016-07-06' + Connection: + - keep-alive + Content-Length: + - '2810' + Content-Security-Policy: + - report-uri https://q.stripe.com/csp-report?p=v1%2Fcharges%2F%3Acharge; block-all-mixed-content; + default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'; + img-src 'self'; script-src 'self' 'report-sample'; style-src 'self' + Content-Type: + - application/json + Date: + - Sun, 11 Feb 2024 11:32:06 GMT + Request-Id: + - req_JtAfXPsoab9wa9 + Server: + - nginx + Strict-Transport-Security: + - max-age=63072000; includeSubDomains; preload + Stripe-Version: + - '2023-10-16' + Vary: + - Origin + X-Stripe-Non-Api-Overhead-Duration-Ms: + - '75.00000000000001' + X-Stripe-Routing-Context-Priority-Tier: + - api-testmode status: code: 200 message: OK diff --git a/tests/test_purchase.py b/tests/test_purchase.py index c974233b8..1d7726db3 100644 --- a/tests/test_purchase.py +++ b/tests/test_purchase.py @@ -28,6 +28,14 @@ def load_webhook_fixture(name): return stripe.Event.construct_from(json.load(f), None) +@pytest.fixture(scope="module") +def vcr_config(): + return { + # Replace the Authorization request header with "DUMMY" in cassettes + "filter_headers": [("authorization", "DUMMY")], + } + + # This test uses VCR to automatically store Stripe responses as test fixtures. # It also uses some webhook fixtures which we manually supply. # @@ -46,7 +54,7 @@ def test_create_stripe_purchase(user, app, monkeypatch): db.session.commit() # This matches the intent ID in stored fixtures - intent_id = "pi_1GUslpIcI91cWsdeheAuRsyg" + intent_id = "pi_3OiHFbHz0MWR65Xj0KidZr5i" with app.test_request_context("/tickets/pay"): login_user(user) diff --git a/tests/webhook_fixtures/charge.refunded.json b/tests/webhook_fixtures/charge.refunded.json index 360a11f53..8a0565f2f 100644 --- a/tests/webhook_fixtures/charge.refunded.json +++ b/tests/webhook_fixtures/charge.refunded.json @@ -1,42 +1,45 @@ { - "id": "ch_1GUslxIcI91cWsde5jePBfRQ", + "id": "ch_3OibCXHz0MWR65Xj09SoiLkW", "object": "charge", - "amount": 23000, - "amount_refunded": 21000, + "amount": 11500, + "amount_captured": 11500, + "amount_refunded": 11500, "application": null, "application_fee": null, "application_fee_amount": null, - "balance_transaction": "txn_1GUslxIcI91cWsdenOKhyR4i", + "balance_transaction": "txn_3Oe2zLHz0MWR65Xj1QWdzYX2", "billing_details": { "address": { "city": null, "country": null, "line1": null, "line2": null, - "postal_code": "42424", + "postal_code": "11111", "state": null }, "email": "test@example.com", "name": "Name", "phone": null }, - "calculated_statement_descriptor": "EMFCAMP EMF 2020 P", + "calculated_statement_descriptor": "STRIPE* EMF 2022 PURCH", "captured": true, - "created": 1586171145, + "created": 1706566070, "currency": "gbp", "customer": null, "description": null, "destination": null, "dispute": null, "disputed": false, + "failure_balance_transaction": null, "failure_code": null, "failure_message": null, - "fraud_details": {}, + "fraud_details": { + }, "invoice": null, "livemode": false, "metadata": { - "user_id": "1", - "payment_id": "2" + "payment_id": "3", + "user_id": "1" }, "on_behalf_of": null, "order": null, @@ -44,15 +47,16 @@ "network_status": "approved_by_network", "reason": null, "risk_level": "normal", - "risk_score": 55, + "risk_score": 29, "seller_message": "Payment complete.", "type": "authorized" }, "paid": true, - "payment_intent": "pi_1GUslpIcI91cWsdeheAuRsyg", - "payment_method": "pm_1GUslxIcI91cWsdeBYozsFYU", + "payment_intent": "pi_3OiHFbHz0MWR65Xj0KidZr5i", + "payment_method": "pm_1Oe2zaHz0MWR65Xj9ObFA4hd", "payment_method_details": { "card": { + "amount_authorized": 11500, "brand": "visa", "checks": { "address_line1_check": null, @@ -60,55 +64,48 @@ "cvc_check": "pass" }, "country": "US", - "exp_month": 4, - "exp_year": 2024, - "fingerprint": "VKnD4kq2Jm2zibNl", + "exp_month": 1, + "exp_year": 2029, + "extended_authorization": { + "status": "disabled" + }, + "fingerprint": "qyoEjYqy9x1BibQI", "funding": "credit", + "incremental_authorization": { + "status": "unavailable" + }, "installments": null, "last4": "4242", + "mandate": null, + "multicapture": { + "status": "unavailable" + }, "network": "visa", + "network_token": { + "used": false + }, + "overcapture": { + "maximum_amount_capturable": 11500, + "status": "unavailable" + }, "three_d_secure": null, "wallet": null }, "type": "card" }, + "radar_options": { + }, "receipt_email": null, "receipt_number": null, - "receipt_url": "https://pay.stripe.com/receipts/acct_14i5G7IcI91cWsde/ch_1GUslxIcI91cWsde5jePBfRQ/rcpt_H2yjkWzJc46LbnTbSqH7RdXWbbaVDSU", - "refunded": false, - "refunds": { - "object": "list", - "data": [ - { - "id": "re_1GVEloIcI91cWsdemdIEKjOK", - "object": "refund", - "amount": 21000, - "balance_transaction": "txn_1GVEloIcI91cWsdeWsmUp4Fr", - "charge": "ch_1GUslxIcI91cWsde5jePBfRQ", - "created": 1586255704, - "currency": "gbp", - "metadata": { - "refund_request": "1" - }, - "payment_intent": "pi_1GUslpIcI91cWsdeheAuRsyg", - "reason": null, - "receipt_number": null, - "source_transfer_reversal": null, - "status": "succeeded", - "transfer_reversal": null - } - ], - "has_more": false, - "total_count": 1, - "url": "/v1/charges/ch_1GUslxIcI91cWsde5jePBfRQ/refunds" - }, + "receipt_url": "https://pay.stripe.com/receipts/payment/CAcaFwoVYWNjdF8xT2RocXVIejBNV1I2NVhqKLnE4K0GMgYuOdb8Tz86LBZHtvpFa6UvmDVEvQaGSKdQfESb2Z3CArkrrX4DqeiYsXdDAocurT4krTtc", + "refunded": true, "review": null, "shipping": null, "source": null, "source_transfer": null, "statement_descriptor": null, - "statement_descriptor_suffix": "EMF 2020 purchase", + "statement_descriptor_suffix": "EMF 2022 purchase", "status": "succeeded", "transfer_data": null, "transfer_group": null -} +} \ No newline at end of file diff --git a/tests/webhook_fixtures/payment_intent.succeeded.json b/tests/webhook_fixtures/payment_intent.succeeded.json index 5717b0bf9..804e9b048 100644 --- a/tests/webhook_fixtures/payment_intent.succeeded.json +++ b/tests/webhook_fixtures/payment_intent.succeeded.json @@ -1,150 +1,60 @@ { - "id": "pi_1GUslpIcI91cWsdeheAuRsyg", + "id": "pi_3OiHFbHz0MWR65Xj0KidZr5i", "object": "payment_intent", - "allowed_source_types": ["card"], - "amount": 23000, + "amount": 11500, "amount_capturable": 0, - "amount_received": 23000, + "amount_details": { + "tip": { + } + }, + "amount_received": 11500, "application": null, "application_fee_amount": null, + "automatic_payment_methods": { + "allow_redirects": "always", + "enabled": true + }, "canceled_at": null, "cancellation_reason": null, "capture_method": "automatic", - "charges": { - "object": "list", - "data": [ - { - "id": "ch_1GUslxIcI91cWsde5jePBfRQ", - "object": "charge", - "amount": 23000, - "amount_refunded": 0, - "application": null, - "application_fee": null, - "application_fee_amount": null, - "balance_transaction": "txn_1GUslxIcI91cWsdenOKhyR4i", - "billing_details": { - "address": { - "city": null, - "country": null, - "line1": null, - "line2": null, - "postal_code": "42424", - "state": null - }, - "email": "russ@garrett.co.uk", - "name": "Russ", - "phone": null - }, - "calculated_statement_descriptor": "RUSS.GARRE* EMF 2020 P", - "captured": true, - "created": 1586171145, - "currency": "gbp", - "customer": null, - "description": null, - "destination": null, - "dispute": null, - "disputed": false, - "failure_code": null, - "failure_message": null, - "fraud_details": {}, - "invoice": null, - "livemode": false, - "metadata": { - "user_id": "1", - "payment_id": "2" - }, - "on_behalf_of": null, - "order": null, - "outcome": { - "network_status": "approved_by_network", - "reason": null, - "risk_level": "normal", - "risk_score": 55, - "seller_message": "Payment complete.", - "type": "authorized" - }, - "paid": true, - "payment_intent": "pi_1GUslpIcI91cWsdeheAuRsyg", - "payment_method": "pm_1GUslxIcI91cWsdeBYozsFYU", - "payment_method_details": { - "card": { - "brand": "visa", - "checks": { - "address_line1_check": null, - "address_postal_code_check": "pass", - "cvc_check": "pass" - }, - "country": "US", - "exp_month": 4, - "exp_year": 2024, - "fingerprint": "VKnD4kq2Jm2zibNl", - "funding": "credit", - "installments": null, - "last4": "4242", - "network": "visa", - "three_d_secure": null, - "wallet": null - }, - "type": "card" - }, - "receipt_email": null, - "receipt_number": null, - "receipt_url": "https://pay.stripe.com/receipts/acct_14i5G7IcI91cWsde/ch_1GUslxIcI91cWsde5jePBfRQ/rcpt_H2yjkWzJc46LbnTbSqH7RdXWbbaVDSU", - "refunded": false, - "refunds": { - "object": "list", - "data": [], - "has_more": false, - "total_count": 0, - "url": "/v1/charges/ch_1GUslxIcI91cWsde5jePBfRQ/refunds" - }, - "review": null, - "shipping": null, - "source": null, - "source_transfer": null, - "statement_descriptor": null, - "statement_descriptor_suffix": "EMF 2020 purchase", - "status": "succeeded", - "transfer_data": null, - "transfer_group": null - } - ], - "has_more": false, - "total_count": 1, - "url": "/v1/charges?payment_intent=pi_1GUslpIcI91cWsdeheAuRsyg" - }, - "client_secret": "pi_1GUslpIcI91cWsdeheAuRsyg_secret_jm7QnCtrTMjZKeYmqmmmlXZlj", + "client_secret": "pi_3OiHFbHz0MWR65Xj0KidZr5i_secret_IHdxJI6A145n42CiRybjuCm5o", "confirmation_method": "automatic", - "created": 1586171137, + "created": 1706566055, "currency": "gbp", "customer": null, "description": null, "invoice": null, "last_payment_error": null, + "latest_charge": "ch_3OibCXHz0MWR65Xj09SoiLkW", "livemode": false, "metadata": { - "user_id": "1", - "payment_id": "2" + "payment_id": "3", + "user_id": "1" }, "next_action": null, - "next_source_action": null, "on_behalf_of": null, - "payment_method": "pm_1GUslxIcI91cWsdeBYozsFYU", + "payment_method": "pm_1Oe2zaHz0MWR65Xj9ObFA4hd", + "payment_method_configuration_details": null, "payment_method_options": { "card": { "installments": null, + "mandate_options": null, + "network": null, "request_three_d_secure": "automatic" } }, - "payment_method_types": ["card"], + "payment_method_types": [ + "card" + ], + "processing": null, "receipt_email": null, "review": null, "setup_future_usage": null, "shipping": null, "source": null, "statement_descriptor": null, - "statement_descriptor_suffix": "EMF 2020 purchase", + "statement_descriptor_suffix": "EMF 2022 purchase", "status": "succeeded", "transfer_data": null, "transfer_group": null -} +} \ No newline at end of file