From 3c6c4b8e98e15d37534d1c28278892c0f8320111 Mon Sep 17 00:00:00 2001 From: Ivo Branco Date: Fri, 19 Apr 2024 12:51:01 +0100 Subject: [PATCH] fix: integrity error for DUC When receiving a payment paid from a DUC, there isn't any card masked pan, so we fall back to save only the payment type. fixes #15 --- paygate/processors.py | 6 ++++-- paygate/tests/test_views.py | 39 +++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/paygate/processors.py b/paygate/processors.py index dc0c6fd..cff8069 100644 --- a/paygate/processors.py +++ b/paygate/processors.py @@ -500,10 +500,12 @@ def handle_processor_response(self, response, basket=None): # Payment type (VISA, MASTERCARD, PAYPAL, MBWAY, REFMB, DUC, ...) # We use the `card_type` to save the payment type used. - card_type = paygate_transaction.get("PAYMENT_TYPE_CODE", "PayGate") + card_type = paygate_transaction.get("PAYMENT_TYPE_CODE") # Save only a mask of the card - card_number = paygate_transaction.get("CARD_MASKED_PAN", card_type) + card_number = paygate_transaction.get("CARD_MASKED_PAN") + if not card_number: + card_number = card_type hpr = HandledProcessorResponse( transaction_id=transaction_id, diff --git a/paygate/tests/test_views.py b/paygate/tests/test_views.py index 62e0fcc..50429df 100644 --- a/paygate/tests/test_views.py +++ b/paygate/tests/test_views.py @@ -366,3 +366,42 @@ def test_server_response_view_small_callback_data(self, mock__make_api_json_requ order = Order.objects.all().first() self.assertEqual(order.basket.id, basket.id) self.assertTrue(len(Order.objects.all()) == 1) + + @mock.patch.object(PayGate, "_make_api_json_request") + def test_callback_server_duc(self, mock__make_api_json_request): + """ + Test the server-to-server callback with a DUC payment. + """ + # create data for test + course = CourseFactory(id='a/b/c', name='Demo Course', partner=self.partner) + course.save() + product = course.create_or_update_seat('test-certificate-type', False, 20) + product.save() + basket = create_basket(site=self.site, owner=UserFactory(), empty=True) + basket.add_product(product) + basket.save() + + # mock the call to PayGate to double-check if it's being payed + mock__make_api_json_request.return_value = [{ + "MERCHANT_CODE": "NAU", + "STATUS_CODE": "C", + "PAYMENT_REF": basket.order_number, + "PAYMENT_AMOUNT": "20.00", + "TRANSACTION_ID": "123415432432432", + "CARD_MASKED_PAN": None, + "PAYMENT_TYPE_CODE": "DUC", + }] + + callback_server_data = { + 'payment_ref': basket.order_number, + } + response = self.client.post( + reverse("ecommerce_plugin_paygate:callback_server"), + data=json.dumps(callback_server_data), + content_type='application/json' + ) + self.assertContains(response, "Received server callback with success") + + order = Order.objects.all().first() + self.assertEqual(order.basket.id, basket.id) + self.assertTrue(len(Order.objects.all()) == 1)