Commit ce9ec7b6 authored by Gabriel Monnerat's avatar Gabriel Monnerat

erp5_stripe: Use activity to store stripe session in ERP5

Creating Stripe Payment Session and HTTP Exchange in the same transaction can raise conflict errors and when it happens, we already created the session on the Stripe side.

With this, when this happens, we receive one useless webhook to inform that the session has expired.

Also, batch_mode was removed because we only use it in tests. The tests were updated to use like in production.

This change will probably avoid the issue below:

```
------
2023-03-01 13:03:33,503 INFO Tracking queuing message: activity=SQLDict, object_path=/erp5/stripe_payment_session_module/20230301-1B990F0, method_id=immediateReindexObject, args=(), kw={}, activity_kw={'group_id': '', 'serialization_tag': '/erp5/stripe_payment_session_module/20230301-1B990F0', 'alternate_method_id': 'alternateReindexObject', 'group_method_id': 'portal_catalog/catalogObjectList'}, user_name=...
------
2023-03-01 13:03:33,516 INFO Tracking queuing message: activity=SQLDict, object_path=/erp5/system_event_module/20230301-9DDE8DD8, method_id=immediateReindexObject, args=(), kw={}, activity_kw={'group_id': '', 'serialization_tag': '/erp5/system_event_module/20230301-9DDE8DD8', 'alternate_method_id': 'alternateReindexObject', 'group_method_id': 'portal_catalog/catalogObjectList'}, user_name=...
------
2023-03-01 13:03:33,549 INFO ZPublisher.Conflict ReadConflictError at ......_startStripePaymentSession: database read conflict error (oid 0x06be91ef, serial this txn started with 0x03eec0ca6bdaf611 2023-03-01 10:50:25.278590, serial currently committed 0x03eec0d78f096a55 2023-03-01 11:03:33.524245) (12 conflicts (0 unresolved) since startup at Tue Jan 17 03:21:57 2023)
------
2023-03-01 13:03:35,057 INFO Tracking queuing message: activity=SQLDict, object_path=/erp5/stripe_payment_session_module/20230301-1E233DB, method_id=immediateReindexObject, args=(), kw={}, activity_kw={'group_id': '', 'serialization_tag': '/erp5/stripe_payment_session_module/20230301-1E233DB', 'alternate_method_id': 'alternateReindexObject', 'group_method_id': 'portal_catalog/catalogObjectList'}, user_name=...
------
2023-03-01 13:03:35,066 INFO Tracking queuing message: activity=SQLDict, object_path=/erp5/system_event_module/20230301-5C3B7E3, method_id=immediateReindexObject, args=(), kw={}, activity_kw={'group_id': '', 'serialization_tag': '/erp5/system_event_module/20230301-5C3B7E3', 'alternate_method_id': 'alternateReindexObject', 'group_method_id': 'portal_catalog/catalogObjectList'}, user_name=...
```

See merge request nexedi/erp5!1747
parents 4d35cae9 ec4a3f9d
Pipeline #27001 failed with stage
...@@ -61,11 +61,9 @@ ...@@ -61,11 +61,9 @@
<value> <value>
<object> <object>
<klass> <klass>
<global name="_reconstructor" module="copy_reg"/> <global name="DateTime" module="DateTime.DateTime"/>
</klass> </klass>
<tuple> <tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/> <none/>
</tuple> </tuple>
<state> <state>
......
import json import json
portal = context.getPortalObject()
response = connector.createSession(data=data) response = connector.createSession(data=data)
assert "id" in response, response assert "id" in response, response
stripe_payment_session = portal.stripe_payment_session_module.newContent( context.activate().StripePaymentSessionModule_storeStripeSession(
portal_type="Stripe Payment Session",
reference=response["id"], reference=response["id"],
expiration_date=context.getTypeBasedMethod('getStripePaymentSessionExpirationDate')(), expiration_date=context.getTypeBasedMethod('getStripePaymentSessionExpirationDate')(),
resource=resource, resource=resource,
source_value=connector, source=connector.getRelativeUrl(),
causality=causality causality=causality,
)
http_exchange = portal.system_event_module.newContent(
portal_type="HTTP Exchange",
title="Create Session",
follow_up_value=stripe_payment_session,
source_value=context,
resource_value=portal.portal_categories.http_exchange_resource.stripe.create_session,
request=json.dumps(data, indent=2), request=json.dumps(data, indent=2),
response=json.dumps(response, indent=2) response=json.dumps(response, indent=2)
) )
http_exchange.confirm()
http_exchange.acknowledge()
stripe_payment_session.open()
if batch_mode:
return stripe_payment_session
return context.REQUEST.RESPONSE.redirect(response["url"]) return context.REQUEST.RESPONSE.redirect(response["url"])
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>connector, data, causality=None, resource=None, batch_mode=False</string> </value> <value> <string>connector, data, causality=None, resource=None</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
portal = context.getPortalObject()
stripe_payment_session = portal.stripe_payment_session_module.newContent(
portal_type="Stripe Payment Session",
reference=reference,
expiration_date=expiration_date,
resource=resource,
source_value=portal.restrictedTraverse(source),
causality=causality
)
http_exchange = portal.system_event_module.newContent(
portal_type="HTTP Exchange",
title="Create Session",
follow_up_value=stripe_payment_session,
resource_value=portal.portal_categories.http_exchange_resource.stripe.create_session,
)
http_exchange.confirm()
http_exchange.acknowledge()
stripe_payment_session.open()
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>reference, expiration_date, resource, source, causality, request, response</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>StripePaymentSessionModule_storeStripeSession</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -205,7 +205,8 @@ class TestStripePaymentSession(ERP5TypeTestCase): ...@@ -205,7 +205,8 @@ class TestStripePaymentSession(ERP5TypeTestCase):
return (200, {'content-type': 'application/json'}, json.dumps({ return (200, {'content-type': 'application/json'}, json.dumps({
"id": session_id, "id": session_id,
"status": status, "status": status,
"object": "checkout.session" "object": "checkout.session",
"url": "https://stripe.url"
})) }))
return _callback return _callback
...@@ -382,13 +383,16 @@ class TestStripePaymentSession(ERP5TypeTestCase): ...@@ -382,13 +383,16 @@ class TestStripePaymentSession(ERP5TypeTestCase):
self.session_url, self.session_url,
self._response_callback("abc123") self._response_callback("abc123")
) )
stripe_payment_session = module.StripePaymentSessionModule_createStripeSession( module.StripePaymentSessionModule_createStripeSession(
connector, connector,
self.data.copy(), self.data.copy(),
module.getRelativeUrl(), module.getRelativeUrl(),
batch_mode=True
) )
self.tic() self.tic()
stripe_payment_session = self.portal.portal_catalog.getResultValue(
portal_type="Stripe Payment Session",
reference="abc123"
)
self.assertEqual(connector, stripe_payment_session.getSourceValue()) self.assertEqual(connector, stripe_payment_session.getSourceValue())
self._document_to_delete_list.append(stripe_payment_session) self._document_to_delete_list.append(stripe_payment_session)
self.assertEqual( self.assertEqual(
...@@ -415,8 +419,13 @@ class TestStripePaymentSession(ERP5TypeTestCase): ...@@ -415,8 +419,13 @@ class TestStripePaymentSession(ERP5TypeTestCase):
self.session_url, self.session_url,
self._response_callback("abc321_expired") self._response_callback("abc321_expired")
) )
first_stripe_payment_session = module.StripePaymentSessionModule_createStripeSession( module.StripePaymentSessionModule_createStripeSession(
connector, data, module.getRelativeUrl(), batch_mode=True) connector, data, module.getRelativeUrl())
self.tic()
first_stripe_payment_session = self.portal.portal_catalog.getResultValue(
portal_type="Stripe Payment Session",
reference="abc321_expired"
)
first_stripe_payment_session.setExpirationDate(DateTime() - 1) first_stripe_payment_session.setExpirationDate(DateTime() - 1)
self.tic() self.tic()
...@@ -426,8 +435,13 @@ class TestStripePaymentSession(ERP5TypeTestCase): ...@@ -426,8 +435,13 @@ class TestStripePaymentSession(ERP5TypeTestCase):
self.session_url, self.session_url,
self._response_callback("abc321_completed") self._response_callback("abc321_completed")
) )
second_stripe_payment_session = module.StripePaymentSessionModule_createStripeSession( module.StripePaymentSessionModule_createStripeSession(
connector, data, module.getRelativeUrl(), batch_mode=True) connector, data, module.getRelativeUrl())
self.tic()
second_stripe_payment_session = self.portal.portal_catalog.getResultValue(
portal_type="Stripe Payment Session",
reference="abc321_completed"
)
second_stripe_payment_session.setExpirationDate(DateTime() - 1) second_stripe_payment_session.setExpirationDate(DateTime() - 1)
self.tic() self.tic()
...@@ -449,6 +463,7 @@ class TestStripePaymentSession(ERP5TypeTestCase): ...@@ -449,6 +463,7 @@ class TestStripePaymentSession(ERP5TypeTestCase):
"%s/ERP5Site_receiveStripeWebHook" % self.portal.getPath(), "%s/ERP5Site_receiveStripeWebHook" % self.portal.getPath(),
stdin=BytesIO(urllib.parse.urlencode({ stdin=BytesIO(urllib.parse.urlencode({
"BODY": json.dumps({ "BODY": json.dumps({
"url": "https://stripe.url",
"id": "evt_%s" % "abc321_expired", "id": "evt_%s" % "abc321_expired",
"object": "event", "object": "event",
"data": { "data": {
...@@ -490,7 +505,8 @@ class TestStripePaymentSession(ERP5TypeTestCase): ...@@ -490,7 +505,8 @@ class TestStripePaymentSession(ERP5TypeTestCase):
json={ json={
"id": "test_update_expiration_date", "id": "test_update_expiration_date",
"status": "open", "status": "open",
"object": "checkout.session" "object": "checkout.session",
"url": "https://stripe.url"
}, },
) )
rsps.add( rsps.add(
...@@ -499,12 +515,17 @@ class TestStripePaymentSession(ERP5TypeTestCase): ...@@ -499,12 +515,17 @@ class TestStripePaymentSession(ERP5TypeTestCase):
json={ json={
"id": "test_update_expiration_date", "id": "test_update_expiration_date",
"status": "open", "status": "open",
"object": "checkout.session" "object": "checkout.session",
}, },
) )
stripe_payment_session = module.StripePaymentSessionModule_createStripeSession( module.StripePaymentSessionModule_createStripeSession(
connector, data, module.getRelativeUrl(), batch_mode=True) connector, data, module.getRelativeUrl())
self.tic()
stripe_payment_session = self.portal.portal_catalog.getResultValue(
portal_type="Stripe Payment Session",
reference="test_update_expiration_date"
)
self.assertEqual("open", stripe_payment_session.getValidationState()) self.assertEqual("open", stripe_payment_session.getValidationState())
stripe_payment_session.setExpirationDate(DateTime() - 1) stripe_payment_session.setExpirationDate(DateTime() - 1)
self.tic() self.tic()
...@@ -531,10 +552,13 @@ class TestStripePaymentSession(ERP5TypeTestCase): ...@@ -531,10 +552,13 @@ class TestStripePaymentSession(ERP5TypeTestCase):
stripe_payment_session = module.StripePaymentSessionModule_createStripeSession( stripe_payment_session = module.StripePaymentSessionModule_createStripeSession(
connector, connector,
self.data.copy(), self.data.copy(),
module.getRelativeUrl(), module.getRelativeUrl()
batch_mode=True
) )
self.tic() self.tic()
stripe_payment_session = self.portal.portal_catalog.getResultValue(
portal_type="Stripe Payment Session",
reference=session_id
)
self._document_to_delete_list.append(stripe_payment_session) self._document_to_delete_list.append(stripe_payment_session)
first_http_exchange, = stripe_payment_session.getFollowUpRelatedValueList( first_http_exchange, = stripe_payment_session.getFollowUpRelatedValueList(
...@@ -550,7 +574,7 @@ class TestStripePaymentSession(ERP5TypeTestCase): ...@@ -550,7 +574,7 @@ class TestStripePaymentSession(ERP5TypeTestCase):
self.assertRaises( self.assertRaises(
requests.HTTPError, requests.HTTPError,
stripe_payment_session.StripePaymentSession_retrieveSession, stripe_payment_session.StripePaymentSession_retrieveSession,
connector, batch_mode=1 connector
) )
self.tic() self.tic()
...@@ -565,13 +589,15 @@ class TestStripePaymentSession(ERP5TypeTestCase): ...@@ -565,13 +589,15 @@ class TestStripePaymentSession(ERP5TypeTestCase):
self.session_url, self.session_url,
self._response_callback(session_id) self._response_callback(session_id)
) )
stripe_payment_session = module.StripePaymentSessionModule_createStripeSession( module.StripePaymentSessionModule_createStripeSession(
connector, connector,
self.data.copy(), self.data.copy(),
module.getRelativeUrl(), module.getRelativeUrl()
batch_mode=True
) )
self.tic() self.tic()
stripe_payment_session = self.portal.portal_catalog.getResultValue(
portal_type="Stripe Payment Session",
reference=session_id)
self._document_to_delete_list.append(stripe_payment_session) self._document_to_delete_list.append(stripe_payment_session)
with responses.RequestsMock() as rsps: with responses.RequestsMock() as rsps:
...@@ -603,9 +629,11 @@ class TestStripePaymentSession(ERP5TypeTestCase): ...@@ -603,9 +629,11 @@ class TestStripePaymentSession(ERP5TypeTestCase):
stripe_payment_session = module.StripePaymentSessionModule_createStripeSession( stripe_payment_session = module.StripePaymentSessionModule_createStripeSession(
connector, connector,
self.data.copy(), self.data.copy(),
batch_mode=True
) )
self.tic() self.tic()
stripe_payment_session = self.portal.portal_catalog.getResultValue(
portal_type="Stripe Payment Session",
reference=session_id)
self._document_to_delete_list.append(stripe_payment_session) self._document_to_delete_list.append(stripe_payment_session)
first_http_exchange, = stripe_payment_session.getFollowUpRelatedValueList( first_http_exchange, = stripe_payment_session.getFollowUpRelatedValueList(
portal_type="HTTP Exchange") portal_type="HTTP Exchange")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment