Skip to content

Commit

Permalink
Ignore new data coming from Adyen
Browse files Browse the repository at this point in the history
When we migrated our Adyen account to the new 'systems communications'
interface, we started getting new data, which caused 500s. As all of it
comes in the 'additionalData.KEY = value' format and we don't need it,
we just blanket ignore it for now.
  • Loading branch information
maiksprenger committed Sep 24, 2015
1 parent 0febc8d commit c7686d2
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 1 deletion.
4 changes: 4 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ See `adyen.settings_config.FromSettingsConfig` for an example.
Changes
=======

0.4.1 - unreleased
------------------
- ignore additional data sent by Adyen's new-style system communications

0.4.0 - released July 14th, 2015
--------------------------------

Expand Down
29 changes: 29 additions & 0 deletions adyen/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Constants:
SESSION_VALIDITY = 'sessionValidity'
SKIN_CODE = 'skinCode'
SHIP_BEFORE_DATE = 'shipBeforeDate'
ADDITIONAL_DATA = 'additionalData.'

SHOPPER_EMAIL = 'shopperEmail'
SHOPPER_LOCALE = 'shopperLocale'
Expand Down Expand Up @@ -313,6 +314,16 @@ def process(self):


class PaymentNotification(BaseResponse):
"""
Class used to process payment notifications (HTTPS POST from Adyen to Oscaro servers).
Payment notifications can have multiple fields. They fall into four categories:
- required: Must be included.
- optional: Can be included.
- additional data: Can be included. Format is 'additionalData.VALUE' and we don't need the
data at the moment, so it's ignored.
- unexpected: We loudly complain.
"""
REQUIRED_FIELDS = (
Constants.CURRENCY,
Constants.EVENT_CODE,
Expand All @@ -331,6 +342,24 @@ class PaymentNotification(BaseResponse):
Constants.ORIGINAL_REFERENCE,
)

def check_fields(self):
"""
Delete unneeded additional data before validating.
Adyen's payment notification can come with additional data.
It can mostly be turned on and off in the notifications settings,
but some bits always seem to be delivered with the new
"System communication" setup (instead of the old "notifications" tab
in the settings).
We currently don't need any of that data, so we just drop it
before validating the response.
:return:
"""
self.params = {
key: self.params[key] for key in self.params if Constants.ADDITIONAL_DATA not in key
}
super().check_fields()

def process(self):
payment_result = self.params.get(Constants.SUCCESS, None)
accepted = payment_result == Constants.TRUE
Expand Down
47 changes: 46 additions & 1 deletion tests/test_adyen.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

from freezegun import freeze_time

from adyen.gateway import MissingFieldException, InvalidTransactionException
from adyen.gateway import MissingFieldException, InvalidTransactionException, PaymentNotification, \
Constants, UnexpectedFieldException
from adyen.models import AdyenTransaction
from adyen.scaffold import Scaffold
from adyen.facade import Facade
Expand Down Expand Up @@ -440,3 +441,47 @@ def test_assert_duplicate_notifications(self):
# any more. But we still acknowledge it.
assert (False, True) == self.scaffold.assess_notification_relevance(self.request)


class MockClient:
secret_key = None


class PaymentNotificationTestCase(TestCase):

def create_mock_notification(self, required=True, optional=False, additional=False):
keys_to_set = []
if required:
keys_to_set += PaymentNotification.REQUIRED_FIELDS
if optional:
keys_to_set += PaymentNotification.OPTIONAL_FIELDS
if additional:
keys_to_set += [Constants.ADDITIONAL_DATA + 'foo']
params = {key: 'FOO' for key in keys_to_set}

return PaymentNotification(MockClient(), params)

def test_required_fields_are_required(self):
notification = self.create_mock_notification(
required=False, optional=True, additional=True)
with self.assertRaises(MissingFieldException):
notification.check_fields()

def test_unknown_fields_cause_exception(self):
notification = self.create_mock_notification(
required=True, optional=False, additional=False)
notification.params['UNKNOWN_FIELD'] = 'foo'

with self.assertRaises(UnexpectedFieldException):
notification.check_fields()

def test_optional_fields_are_optional(self):
notification = self.create_mock_notification(
required=True, optional=False, additional=False)

notification.check_fields()

def test_additional_fields_are_ignored(self):
notification = self.create_mock_notification(
required=True, optional=False, additional=True)

notification.check_fields()

0 comments on commit c7686d2

Please sign in to comment.