From c4b440774d649c916c98df7fc17032b094341a03 Mon Sep 17 00:00:00 2001 From: Philippe L'ATTENTION Date: Tue, 31 Aug 2021 09:22:06 +0400 Subject: [PATCH] [IMP] InstallmentPlans api resource - Fix object name "intallment_plan" - Refactor mapper InstallmentPlan data to have APIResource object like Payment - Adding Schedule APIResource and initializer to map list to list of Schedule(s) - Add tests notifications treat - Fix tests to use new APIResource objects - Bump version --- payplug/__version__.py | 2 +- payplug/resources.py | 39 ++++++- .../test_init/test_dao_installment_plans.py | 3 +- payplug/test/test_notifications.py | 108 ++++++++++++++++++ .../test_resources/test_installment_plans.py | 81 +++++++------ 5 files changed, 194 insertions(+), 39 deletions(-) diff --git a/payplug/__version__.py b/payplug/__version__.py index cf0bccd..b795e2c 100644 --- a/payplug/__version__.py +++ b/payplug/__version__.py @@ -1,2 +1,2 @@ # -*- coding: utf-8 -*- -__version__ = '1.4.0' +__version__ = '1.4.1' diff --git a/payplug/resources.py b/payplug/resources.py index 050c39e..98842fc 100644 --- a/payplug/resources.py +++ b/payplug/resources.py @@ -397,7 +397,36 @@ class InstallmentPlan(APIResource, VerifiableAPIResource, ReconstituableAPIResou """ An InstallmentPlans Resource """ - object_type = 'intallment_plan' + object_type = 'installment_plan' + + @property + def _mapper(self): + """ + Maps payment attributes to their specific types. + + :see :func:`~APIResource._mapper` + """ + return { + 'hosted_payment': Payment.HostedPayment, + 'notification': Payment.Notification, + 'failure': Payment.Failure, + 'billing': Payment.Billing, + 'shipping': Payment.Shipping, + } + + def _initialize(self, **resource_attributes): + """ + Initialize a resource. + Default behavior is just to set all the attributes. You may want to override this. + + :param resource_attributes: The resource attributes + """ + + schedules = [] + for schedule in resource_attributes.get('schedule', []): + schedules.append(InstallmentPlan.Schedule(**schedule)) + resource_attributes["schedule"] = schedules + super(InstallmentPlan, self)._initialize(**resource_attributes) def get_consistent_resource(self): """ @@ -408,4 +437,10 @@ def get_consistent_resource(self): response, _ = http_client.get( routes.url(routes.INSTALLMENT_PLANS, resource_id=self.id) ) - return InstallmentPlan(**response) \ No newline at end of file + return InstallmentPlan(**response) + + class Schedule(APIResource): + """ + Schedule information + """ + pass diff --git a/payplug/test/test_init/test_dao_installment_plans.py b/payplug/test/test_init/test_dao_installment_plans.py index f38742b..7846d8c 100644 --- a/payplug/test/test_init/test_dao_installment_plans.py +++ b/payplug/test/test_init/test_dao_installment_plans.py @@ -22,7 +22,7 @@ def test_update(self): assert isinstance(installment_plan, resources.InstallmentPlan) assert installment_plan.id == 'installment_plan_id' - assert installment_plan.failure['code'] == 'aborted' + assert installment_plan.failure.code == 'aborted' def test_create(self): @@ -30,4 +30,3 @@ def test_create(self): assert isinstance(installment_plan, resources.InstallmentPlan) assert installment_plan.id == 'installment_plan_id' - \ No newline at end of file diff --git a/payplug/test/test_notifications.py b/payplug/test/test_notifications.py index 475e0c8..0227e3c 100644 --- a/payplug/test/test_notifications.py +++ b/payplug/test/test_notifications.py @@ -56,3 +56,111 @@ def test_treat_payment(self): def test_treat_binary_string(self): safe_payment = notifications.treat(b'{"id": "pay_test_unsafe", "object": "payment"}') assert safe_payment.id == 'pay_test' + + +@patch('payplug.config.secret_key', 'a_secret_key') +class TestTreatNotificationsInstallmentPlanSuccess(TestBase): + @classmethod + def setup_class(cls): + api_response = { + "hosted_payment": { + "cancel_url": "https://example.com/payment/payplug/cancel", + "return_url": "https://example.com/shop/payment/validate", + "payment_url": "https://secure.payplug.com/pay/test/59TXrYROSdmt0Y7W9Ubpg8" + }, + "customer": { + "phone_number": "None", + "city": "PARIS", + "first_name": "JOHN", + "last_name": "DOE", + "language": "fr", + "address1": "21 Elm Street", + "address2": "None", + "postcode": "75018", + "country": "France", + "email": "johndoe@example.com", + }, + "schedule": [ + {"date": "2021-08-04", "amount": 2600, "payment_ids": ["pay_59TXrYROSdmt0Y7W9Ubpg8"]}, + {"date": "2021-09-04", "amount": 2600, "payment_ids": []}, + {"date": "2021-10-04", "amount": 2600, "payment_ids": []}, + ], + "notification": {"url": "https://example.com/payment/payplug/ipn"}, + "created_at": 1628079236, + "object": "installment_plan", + "is_active": True, + "currency": "EUR", + "is_live": False, + "is_fully_paid": False, + "id": "inst_2aSCmLRZFtAA7arHJfGrE1", + "failure": "None", + "metadata": {"customer_id": "23", "acquirer_id": 5, "reference": "CMD0000123"}, + } + cls.patcher_get = patch.object(payplug.resources.HttpClient, 'get', return_value=(api_response, 200)) + cls.patcher_get.start() + + @classmethod + def teardown_class(cls): + cls.patcher_get.stop() + + def test_treat_installment_plan(self): + json_data = '''{ + "hosted_payment":{ + "cancel_url":"https://example.com/payment/payplug/cancel", + "return_url":"https://example.com/shop/payment/validate", + "payment_url":"https://secure.payplug.com/pay/test/59TXrYROSdmt0Y7W9Ubpg8" + }, + "customer":{ + "phone_number":"None", + "city":"PARIS", + "first_name":"JOHN", + "last_name":"DOE", + "language":"fr", + "address1":"21 Elm Street", + "address2":"None", + "postcode":"75018", + "country":"France", + "email":"johndoe@example.com" + }, + "schedule":[ + { + "date":"2021-08-04", + "amount":2600, + "payment_ids":[ + "pay_59TXrYROSdmt0Y7W9Ubpg8" + ] + }, + { + "date":"2021-09-04", + "amount":2600, + "payment_ids":[ + + ] + }, + { + "date":"2021-10-04", + "amount":2600, + "payment_ids":[ + + ] + } + ], + "notification":{ + "url":"https://example.com/payment/payplug/ipn" + }, + "created_at":1628079236, + "object":"installment_plan", + "is_active":true, + "currency":"EUR", + "is_live":false, + "is_fully_paid":false, + "id":"inst_2aSCmLRZFtAA7arHJfGrE1", + "failure":"None", + "metadata":{ + "customer_id":"23", + "acquirer_id":5, + "reference":"CMD0000123" + } + }''' + safe_installment_plan = notifications.treat(json_data) + assert safe_installment_plan.id == 'inst_2aSCmLRZFtAA7arHJfGrE1' diff --git a/payplug/test/test_resources/test_installment_plans.py b/payplug/test/test_resources/test_installment_plans.py index 38b9dfb..e13b080 100644 --- a/payplug/test/test_resources/test_installment_plans.py +++ b/payplug/test/test_resources/test_installment_plans.py @@ -1,4 +1,5 @@ -from payplug.resources import InstallmentPlan +# -*- coding: utf-8 -*- +from payplug.resources import InstallmentPlan, Payment from payplug.test import TestBase @@ -67,43 +68,55 @@ def test_initializer_installment_plans(self): }, {"date": "2019-03-24", "amount": 10000, "payment_ids": []}, ], - "failure": null, + "failure": { + "code": "a_failure_code", + "message": 'A weird failure message ®±' + }, "metadata": {"customer_id": 42}, } installment_plan_object = InstallmentPlan(**installment_plan_attributes) - + assert isinstance(installment_plan_object, InstallmentPlan) assert installment_plan_object.created_at == 1548326773 assert installment_plan_object.currency == "EUR" - assert installment_plan_object.billing == { - "title": "mr", - "first_name": "John", - "last_name": "Watson", - "email": "john.watson@example.net", - "mobile_phone_number": null, - "landline_phone_number": null, - "address1": "221B Baker Street", - "address2": null, - "postcode": "NW16XE", - "city": "London", - "state": null, - "country": "GB", - "language": "en", - } - assert installment_plan_object.shipping == { - "title": "mr", - "first_name": "John", - "last_name": "Watson", - "email": "john.watson@example.net", - "mobile_phone_number": null, - "landline_phone_number": null, - "address1": "221B Baker Street", - "address2": null, - "postcode": "NW16XE", - "city": "London", - "state": null, - "country": "GB", - "language": "en", - "delivery_type": "BILLING", - } + assert installment_plan_object.is_fully_paid == False + + assert type(installment_plan_object.billing) == Payment.Billing + assert installment_plan_object.billing.title == 'mr' + assert installment_plan_object.billing.first_name == "John" + assert installment_plan_object.billing.last_name == "Watson" + assert installment_plan_object.billing.email == "john.watson@example.net" + assert installment_plan_object.billing.address1 == '221B Baker Street' + assert installment_plan_object.billing.postcode == 'NW16XE' + assert installment_plan_object.billing.city == 'London' + assert installment_plan_object.billing.country == 'GB' + assert installment_plan_object.billing.language == 'en' + + assert type(installment_plan_object.shipping) == Payment.Shipping + assert installment_plan_object.shipping.title == 'mr' + assert installment_plan_object.shipping.first_name == "John" + assert installment_plan_object.shipping.last_name == "Watson" + assert installment_plan_object.shipping.email == "john.watson@example.net" + assert installment_plan_object.shipping.address1 == '221B Baker Street' + assert installment_plan_object.shipping.postcode == 'NW16XE' + assert installment_plan_object.shipping.city == 'London' + assert installment_plan_object.shipping.country == 'GB' + assert installment_plan_object.shipping.language == 'en' + assert installment_plan_object.shipping.delivery_type == 'BILLING' + + assert type(installment_plan_object.hosted_payment) == Payment.HostedPayment + assert installment_plan_object.hosted_payment.payment_url == "https://secure.payplug.com/pay/1FTGSRWYHla7eDkfTo2Usd" + assert installment_plan_object.hosted_payment.return_url == "https://example.net/success?id=42" + assert installment_plan_object.hosted_payment.cancel_url == "https://example.net/cancel?id=42" + + + assert installment_plan_object.notification.url == "https://example.net/notifications?id=42" + assert type(installment_plan_object.schedule) == list + for schedule in installment_plan_object.schedule: + assert type(schedule) == InstallmentPlan.Schedule + assert type(schedule.date) == str + assert type(schedule.amount) == int + assert type(schedule.payment_ids) == list + for payment_id in schedule.payment_ids: + assert type(payment_id) == str \ No newline at end of file