mirror of
https://github.com/zulip/zulip.git
synced 2025-11-10 08:56:10 +00:00
integrations/stripe: Fix bug in charge.succeeded.
There are (at least) two types of objects that could be sent with a charge.succeeded event, a Charge (e.g. for credit cards) or a Payment (if they pay by ACH). We were handling the first but not the second. This commit also updates the fixture for the existing charge.succeeded event to the latest API version.
This commit is contained in:
@@ -1,76 +0,0 @@
|
|||||||
{
|
|
||||||
"created": 1326853478,
|
|
||||||
"livemode": false,
|
|
||||||
"id": "evt_00000000000000",
|
|
||||||
"type": "charge.succeeded",
|
|
||||||
"object": "event",
|
|
||||||
"request": null,
|
|
||||||
"pending_webhooks": 1,
|
|
||||||
"api_version": "2016-07-06",
|
|
||||||
"data": {
|
|
||||||
"object": {
|
|
||||||
"id": "ch_00000000000000",
|
|
||||||
"object": "charge",
|
|
||||||
"amount": 100,
|
|
||||||
"amount_refunded": 0,
|
|
||||||
"application": null,
|
|
||||||
"application_fee": null,
|
|
||||||
"balance_transaction": "txn_00000000000000",
|
|
||||||
"captured": true,
|
|
||||||
"created": 1480671988,
|
|
||||||
"currency": "aud",
|
|
||||||
"customer": null,
|
|
||||||
"description": "My First Test Charge (created for API docs)",
|
|
||||||
"destination": null,
|
|
||||||
"dispute": null,
|
|
||||||
"failure_code": null,
|
|
||||||
"failure_message": null,
|
|
||||||
"fraud_details": {},
|
|
||||||
"invoice": null,
|
|
||||||
"livemode": false,
|
|
||||||
"metadata": {},
|
|
||||||
"order": null,
|
|
||||||
"outcome": null,
|
|
||||||
"paid": true,
|
|
||||||
"receipt_email": null,
|
|
||||||
"receipt_number": null,
|
|
||||||
"refunded": false,
|
|
||||||
"refunds": {
|
|
||||||
"object": "list",
|
|
||||||
"data": [],
|
|
||||||
"has_more": false,
|
|
||||||
"total_count": 0,
|
|
||||||
"url": "/v1/charges/ch_19MDceCV4wXizEw45TBCADlp/refunds"
|
|
||||||
},
|
|
||||||
"review": null,
|
|
||||||
"shipping": null,
|
|
||||||
"source": {
|
|
||||||
"id": "card_00000000000000",
|
|
||||||
"object": "card",
|
|
||||||
"address_city": null,
|
|
||||||
"address_country": null,
|
|
||||||
"address_line1": null,
|
|
||||||
"address_line1_check": null,
|
|
||||||
"address_line2": null,
|
|
||||||
"address_state": null,
|
|
||||||
"address_zip": null,
|
|
||||||
"address_zip_check": null,
|
|
||||||
"brand": "Visa",
|
|
||||||
"country": "US",
|
|
||||||
"customer": null,
|
|
||||||
"cvc_check": null,
|
|
||||||
"dynamic_last4": null,
|
|
||||||
"exp_month": 8,
|
|
||||||
"exp_year": 2017,
|
|
||||||
"funding": "credit",
|
|
||||||
"last4": "4242",
|
|
||||||
"metadata": {},
|
|
||||||
"name": null,
|
|
||||||
"tokenization_method": null
|
|
||||||
},
|
|
||||||
"source_transfer": null,
|
|
||||||
"statement_descriptor": null,
|
|
||||||
"status": "succeeded"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
89
zerver/webhooks/stripe/fixtures/charge_succeeded__card.json
Normal file
89
zerver/webhooks/stripe/fixtures/charge_succeeded__card.json
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
{
|
||||||
|
"id": "evt_1DbqCuDEQaroqDjsojJSNhmh",
|
||||||
|
"pending_webhooks": 1,
|
||||||
|
"data": {
|
||||||
|
"object": {
|
||||||
|
"id": "ch_000000000000000000000000",
|
||||||
|
"object": "charge",
|
||||||
|
"amount": 100,
|
||||||
|
"amount_refunded": 0,
|
||||||
|
"application": null,
|
||||||
|
"application_fee": null,
|
||||||
|
"balance_transaction": "txn_000000000000000000000000",
|
||||||
|
"captured": true,
|
||||||
|
"created": 1542991183,
|
||||||
|
"currency": "aud",
|
||||||
|
"customer": "cus_00000000000000",
|
||||||
|
"description": null,
|
||||||
|
"destination": null,
|
||||||
|
"dispute": null,
|
||||||
|
"failure_code": null,
|
||||||
|
"failure_message": null,
|
||||||
|
"fraud_details": {
|
||||||
|
},
|
||||||
|
"invoice": "in_000000000000000000000000",
|
||||||
|
"livemode": true,
|
||||||
|
"metadata": {
|
||||||
|
},
|
||||||
|
"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": null,
|
||||||
|
"receipt_email": "user@example.com",
|
||||||
|
"receipt_number": "0000-0000",
|
||||||
|
"refunded": false,
|
||||||
|
"refunds": {
|
||||||
|
"object": "list",
|
||||||
|
"data": [
|
||||||
|
],
|
||||||
|
"has_more": false,
|
||||||
|
"total_count": 0,
|
||||||
|
"url": "/v1/charges/ch_000000000000000000000000/refunds"
|
||||||
|
},
|
||||||
|
"review": null,
|
||||||
|
"shipping": null,
|
||||||
|
"source": {
|
||||||
|
"id": "card_000000000000000000000000",
|
||||||
|
"object": "card",
|
||||||
|
"address_city": "city",
|
||||||
|
"address_country": "country",
|
||||||
|
"address_line1": "line1",
|
||||||
|
"address_line1_check": "unavailable",
|
||||||
|
"address_line2": null,
|
||||||
|
"address_state": "ST",
|
||||||
|
"address_zip": "00000",
|
||||||
|
"address_zip_check": "unavailable",
|
||||||
|
"brand": "Visa",
|
||||||
|
"country": "CO",
|
||||||
|
"customer": "cus_00000000000000",
|
||||||
|
"cvc_check": null,
|
||||||
|
"dynamic_last4": null,
|
||||||
|
"exp_month": 1,
|
||||||
|
"exp_year": 2023,
|
||||||
|
"fingerprint": "0000000000000000",
|
||||||
|
"funding": "credit",
|
||||||
|
"last4": "0000",
|
||||||
|
"metadata": {
|
||||||
|
},
|
||||||
|
"name": "name",
|
||||||
|
"tokenization_method": null
|
||||||
|
},
|
||||||
|
"source_transfer": null,
|
||||||
|
"statement_descriptor": "Zulip Cloud Standard",
|
||||||
|
"status": "succeeded",
|
||||||
|
"transfer_group": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "charge.succeeded",
|
||||||
|
"api_version": "2018-11-08",
|
||||||
|
"object": "event",
|
||||||
|
"livemode": true,
|
||||||
|
"created": 1543500572
|
||||||
|
}
|
||||||
117
zerver/webhooks/stripe/fixtures/charge_succeeded__invoice.json
Normal file
117
zerver/webhooks/stripe/fixtures/charge_succeeded__invoice.json
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
{
|
||||||
|
"id": "evt_1DbqCuDEQaroqDjsojJSNhmh",
|
||||||
|
"pending_webhooks": 1,
|
||||||
|
"data": {
|
||||||
|
"object": {
|
||||||
|
"failure_message": null,
|
||||||
|
"id": "py_000000000000000000000000",
|
||||||
|
"amount": 100,
|
||||||
|
"refunds": {
|
||||||
|
"total_count": 0,
|
||||||
|
"has_more": false,
|
||||||
|
"url": "\/v1\/charges\/py_000000000000000000000000\/refunds",
|
||||||
|
"object": "list",
|
||||||
|
"data": [
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"invoice": "in_000000000000000000000000",
|
||||||
|
"application": null,
|
||||||
|
"source": {
|
||||||
|
"id": "src_000000000000000000000000",
|
||||||
|
"type": "ach_credit_transfer",
|
||||||
|
"usage": "reusable",
|
||||||
|
"amount": null,
|
||||||
|
"flow": "receiver",
|
||||||
|
"customer": "cus_00000000000000",
|
||||||
|
"livemode": true,
|
||||||
|
"object": "source",
|
||||||
|
"owner": {
|
||||||
|
"address": null,
|
||||||
|
"verified_name": null,
|
||||||
|
"email": "username@example.com",
|
||||||
|
"verified_phone": null,
|
||||||
|
"phone": null,
|
||||||
|
"verified_email": null,
|
||||||
|
"verified_address": null,
|
||||||
|
"name": null
|
||||||
|
},
|
||||||
|
"statement_descriptor": null,
|
||||||
|
"metadata": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"client_secret": "secret",
|
||||||
|
"currency": "usd",
|
||||||
|
"receiver": {
|
||||||
|
"amount_received": 100,
|
||||||
|
"refund_attributes_status": "missing",
|
||||||
|
"amount_charged": 100,
|
||||||
|
"amount_returned": 0,
|
||||||
|
"refund_attributes_method": "email",
|
||||||
|
"address": "1234-1234"
|
||||||
|
},
|
||||||
|
"status": "pending",
|
||||||
|
"ach_credit_transfer": {
|
||||||
|
"refund_account_holder_name": null,
|
||||||
|
"bank_name": "WELLS FARGO BANK, N.A.",
|
||||||
|
"fingerprint": "1234",
|
||||||
|
"routing_number": "1234",
|
||||||
|
"swift_code": "WFBIUS6S",
|
||||||
|
"refund_account_holder_type": null,
|
||||||
|
"account_number": "1234",
|
||||||
|
"refund_account_number": null,
|
||||||
|
"refund_routing_number": null
|
||||||
|
},
|
||||||
|
"created": 1543500572
|
||||||
|
},
|
||||||
|
"refunded": false,
|
||||||
|
"statement_descriptor": null,
|
||||||
|
"metadata": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"transfer_group": null,
|
||||||
|
"amount_refunded": 0,
|
||||||
|
"currency": "usd",
|
||||||
|
"application_fee": null,
|
||||||
|
"source_transfer": null,
|
||||||
|
"object": "charge",
|
||||||
|
"receipt_email": "username@example.com",
|
||||||
|
"receipt_number": "1234-1234",
|
||||||
|
"captured": true,
|
||||||
|
"failure_code": null,
|
||||||
|
"description": null,
|
||||||
|
"payment_intent": null,
|
||||||
|
"paid": true,
|
||||||
|
"shipping": null,
|
||||||
|
"livemode": true,
|
||||||
|
"balance_transaction": "txn_000000000000000000000000",
|
||||||
|
"outcome": {
|
||||||
|
"type": "authorized",
|
||||||
|
"network_status": "approved_by_network",
|
||||||
|
"risk_level": "not_assessed",
|
||||||
|
"seller_message": "Payment complete.",
|
||||||
|
"reason": null
|
||||||
|
},
|
||||||
|
"dispute": null,
|
||||||
|
"on_behalf_of": null,
|
||||||
|
"status": "succeeded",
|
||||||
|
"fraud_details": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"order": null,
|
||||||
|
"review": null,
|
||||||
|
"customer": "cus_00000000000000",
|
||||||
|
"destination": null,
|
||||||
|
"created": 1543500571
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"id": null,
|
||||||
|
"idempotency_key": "in_000000000000000000000000"
|
||||||
|
},
|
||||||
|
"type": "charge.succeeded",
|
||||||
|
"api_version": "2018-11-08",
|
||||||
|
"object": "event",
|
||||||
|
"livemode": true,
|
||||||
|
"created": 1543500572
|
||||||
|
}
|
||||||
@@ -27,10 +27,18 @@ class StripeHookTests(WebhookTestCase):
|
|||||||
self.send_and_test_stream_message('charge_failed', expected_topic, expected_message,
|
self.send_and_test_stream_message('charge_failed', expected_topic, expected_message,
|
||||||
content_type="application/x-www-form-urlencoded")
|
content_type="application/x-www-form-urlencoded")
|
||||||
|
|
||||||
def test_charge_succeeded(self) -> None:
|
# Credit card charge
|
||||||
expected_topic = u"charges"
|
def test_charge_succeeded__card(self) -> None:
|
||||||
expected_message = u"[Charge](https://dashboard.stripe.com/charges/ch_00000000000000) for 1.00 AUD succeeded"
|
expected_topic = u"cus_00000000000000"
|
||||||
self.send_and_test_stream_message('charge_succeeded', expected_topic, expected_message,
|
expected_message = u"[Charge](https://dashboard.stripe.com/charges/ch_000000000000000000000000) for 1.00 AUD succeeded"
|
||||||
|
self.send_and_test_stream_message('charge_succeeded__card', expected_topic, expected_message,
|
||||||
|
content_type="application/x-www-form-urlencoded")
|
||||||
|
|
||||||
|
# ACH payment (really a 'payment', rather than a 'charge')
|
||||||
|
def test_charge_succeeded__invoice(self) -> None:
|
||||||
|
expected_topic = u"cus_00000000000000"
|
||||||
|
expected_message = u"[Payment](https://dashboard.stripe.com/payments/py_000000000000000000000000) for $1.00 succeeded"
|
||||||
|
self.send_and_test_stream_message('charge_succeeded__invoice', expected_topic, expected_message,
|
||||||
content_type="application/x-www-form-urlencoded")
|
content_type="application/x-www-form-urlencoded")
|
||||||
|
|
||||||
def test_customer_created(self) -> None:
|
def test_customer_created(self) -> None:
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ def api_stripe_webhook(request: HttpRequest, user_profile: UserProfile,
|
|||||||
return json_success()
|
return json_success()
|
||||||
if category == 'charge':
|
if category == 'charge':
|
||||||
if resource == 'charge':
|
if resource == 'charge':
|
||||||
if not topic:
|
if not topic: # only in legacy fixtures
|
||||||
topic = 'charges'
|
topic = 'charges'
|
||||||
body = "{resource} for {amount} {verbed}".format(
|
body = "{resource} for {amount} {verbed}".format(
|
||||||
resource=linkified_id(object_['id']),
|
resource=linkified_id(object_['id']),
|
||||||
@@ -208,6 +208,9 @@ def linkified_id(object_id: str, lower: bool=False) -> str:
|
|||||||
# I think usage records have URL prefixes like /subscription_items/si_id/usage_record_summaries
|
# I think usage records have URL prefixes like /subscription_items/si_id/usage_record_summaries
|
||||||
'mbur': ('Usage record', None),
|
'mbur': ('Usage record', None),
|
||||||
|
|
||||||
|
# Undocumented :|
|
||||||
|
'py': ('Payment', 'payments'),
|
||||||
|
|
||||||
# Connect, Fraud, Orders, etc not implemented
|
# Connect, Fraud, Orders, etc not implemented
|
||||||
} # type: Dict[str, Tuple[str, Optional[str]]]
|
} # type: Dict[str, Tuple[str, Optional[str]]]
|
||||||
name, url_prefix = names_and_urls[object_id.split('_')[0]]
|
name, url_prefix = names_and_urls[object_id.split('_')[0]]
|
||||||
|
|||||||
Reference in New Issue
Block a user