From cb8c015fe08930aad1d3064108b78e65684abb4f Mon Sep 17 00:00:00 2001 From: Corey Regan Date: Tue, 30 Jan 2024 19:36:28 -0800 Subject: [PATCH] test_NotificationsClient.py works --- paddle_billing_python_sdk/Client.py | 5 +- .../Entities/Business.py | 12 +- .../Entities/Customer.py | 4 +- .../Notifications/NotificationSubscription.py | 19 +- paddle_billing_python_sdk/Entities/Product.py | 8 +- .../Notifications/NotificationsClient.py | 8 +- .../Operations/ListNotifications.py | 6 +- .../Resources/Notifications/__init__.py | 0 .../_fixtures/response/full_entity.json | 47 ++ .../_fixtures/response/list_default.json | 459 ++++++++++++++++++ .../_fixtures/response/replay.json | 8 + .../Notifications/test_NotificationsClient.py | 203 ++++++++ .../Resources/Reports/test_ReportsClient.py | 16 +- 13 files changed, 754 insertions(+), 41 deletions(-) create mode 100644 tests/Functional/Resources/Notifications/__init__.py create mode 100644 tests/Functional/Resources/Notifications/_fixtures/response/full_entity.json create mode 100644 tests/Functional/Resources/Notifications/_fixtures/response/list_default.json create mode 100644 tests/Functional/Resources/Notifications/_fixtures/response/replay.json create mode 100644 tests/Functional/Resources/Notifications/test_NotificationsClient.py diff --git a/paddle_billing_python_sdk/Client.py b/paddle_billing_python_sdk/Client.py index 44a8f52..e1b63e6 100644 --- a/paddle_billing_python_sdk/Client.py +++ b/paddle_billing_python_sdk/Client.py @@ -3,16 +3,15 @@ from requests import Response, RequestException, Session from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry -from urllib.parse import unquote, urljoin, urlencode +from urllib.parse import unquote, urljoin, urlencode # unquote used for debug from uuid import uuid4 from paddle_billing_python_sdk.__VERSION__ import __VERSION__ -from paddle_billing_python_sdk.FiltersNone import FiltersNone from paddle_billing_python_sdk.FiltersUndefined import FiltersUndefined from paddle_billing_python_sdk.HasParameters import HasParameters from paddle_billing_python_sdk.Options import Options -# from paddle_billing_python_sdk.Logger.Formatter import CustomLogger +# from paddle_billing_python_sdk.Logger.Formatter import CustomLogger # TODO from paddle_billing_python_sdk.Logger.NullHandler import NullHandler from paddle_billing_python_sdk.Resources.Addresses.AddressesClient import AddressesClient diff --git a/paddle_billing_python_sdk/Entities/Business.py b/paddle_billing_python_sdk/Entities/Business.py index 970bf07..6bdd010 100644 --- a/paddle_billing_python_sdk/Entities/Business.py +++ b/paddle_billing_python_sdk/Entities/Business.py @@ -12,16 +12,16 @@ @dataclass class Business(Entity): - id: str - name: str + id: str + name: str company_number: str | None tax_identifier: str | None - status: Status - contacts: list[Contacts] + status: Status + contacts: list[Contacts] created_at: datetime updated_at: datetime - custom_data: CustomData | None - import_meta: ImportMeta | None + custom_data: CustomData | None = None + import_meta: ImportMeta | None = None @classmethod diff --git a/paddle_billing_python_sdk/Entities/Customer.py b/paddle_billing_python_sdk/Entities/Customer.py index 85eb85c..cd5ee1c 100644 --- a/paddle_billing_python_sdk/Entities/Customer.py +++ b/paddle_billing_python_sdk/Entities/Customer.py @@ -16,11 +16,11 @@ class Customer(Entity): email: str marketing_consent: bool status: Status - custom_data: CustomData | None locale: str created_at: datetime updated_at: datetime - import_meta: ImportMeta | None + custom_data: CustomData | None = None + import_meta: ImportMeta | None = None @classmethod diff --git a/paddle_billing_python_sdk/Entities/Notifications/NotificationSubscription.py b/paddle_billing_python_sdk/Entities/Notifications/NotificationSubscription.py index 3375d8c..9388528 100644 --- a/paddle_billing_python_sdk/Entities/Notifications/NotificationSubscription.py +++ b/paddle_billing_python_sdk/Entities/Notifications/NotificationSubscription.py @@ -8,7 +8,6 @@ from paddle_billing_python_sdk.Entities.Shared.CollectionMode import CollectionMode from paddle_billing_python_sdk.Entities.Shared.CurrencyCode import CurrencyCode from paddle_billing_python_sdk.Entities.Shared.CustomData import CustomData -from paddle_billing_python_sdk.Entities.Shared.ImportMeta import ImportMeta from paddle_billing_python_sdk.Entities.Shared.TimePeriod import TimePeriod from paddle_billing_python_sdk.Entities.Subscriptions.SubscriptionDiscount import SubscriptionDiscount @@ -28,19 +27,19 @@ class NotificationSubscription(Entity): currency_code: CurrencyCode created_at: datetime updated_at: datetime - started_at: datetime | None - first_billed_at: datetime | None - next_billed_at: datetime | None - paused_at: datetime | None - canceled_at: datetime | None - discount: SubscriptionDiscount | None collection_mode: CollectionMode - billing_details: BillingDetails | None current_billing_period: SubscriptionTimePeriod billing_cycle: TimePeriod - scheduled_change: SubscriptionScheduledChange | None items: list[SubscriptionItem] - custom_data: CustomData | None + started_at: datetime | None = None + first_billed_at: datetime | None = None + next_billed_at: datetime | None = None + paused_at: datetime | None = None + canceled_at: datetime | None = None + discount: SubscriptionDiscount | None = None + billing_details: BillingDetails | None = None + scheduled_change: SubscriptionScheduledChange | None = None + custom_data: CustomData | None = None @classmethod diff --git a/paddle_billing_python_sdk/Entities/Product.py b/paddle_billing_python_sdk/Entities/Product.py index 276483a..b20f32d 100644 --- a/paddle_billing_python_sdk/Entities/Product.py +++ b/paddle_billing_python_sdk/Entities/Product.py @@ -17,12 +17,12 @@ class Product(Entity): name: str status: Status tax_category: TaxCategory - created_at: datetime | None - custom_data: CustomData | None description: str | None image_url: str | None - import_meta: ImportMeta | None - type: CatalogType | None + created_at: datetime | None = None + custom_data: CustomData | None = None + import_meta: ImportMeta | None = None + type: CatalogType | None = None @classmethod diff --git a/paddle_billing_python_sdk/Resources/Notifications/NotificationsClient.py b/paddle_billing_python_sdk/Resources/Notifications/NotificationsClient.py index 4914de6..7c2f11c 100644 --- a/paddle_billing_python_sdk/Resources/Notifications/NotificationsClient.py +++ b/paddle_billing_python_sdk/Resources/Notifications/NotificationsClient.py @@ -32,15 +32,15 @@ def list(self, operation: ListNotifications = None) -> NotificationCollection: ) - def get(self, notification_setting_id: str) -> Notification: - self.response = self.client.get_raw(f"/notifications/{notification_setting_id}") + def get(self, notification_id: str) -> Notification: + self.response = self.client.get_raw(f"/notifications/{notification_id}") parser = ResponseParser(self.response) return Notification.from_dict(parser.get_data()) - def replay(self, notification_setting_id: str) -> str: - self.response = self.client.post_raw(f"/notifications/{notification_setting_id}") + def replay(self, notification_id: str) -> str: + self.response = self.client.post_raw(f"/notifications/{notification_id}") parser = ResponseParser(self.response) data = parser.get_data() diff --git a/paddle_billing_python_sdk/Resources/Notifications/Operations/ListNotifications.py b/paddle_billing_python_sdk/Resources/Notifications/Operations/ListNotifications.py index 8e62f12..ddb33b4 100644 --- a/paddle_billing_python_sdk/Resources/Notifications/Operations/ListNotifications.py +++ b/paddle_billing_python_sdk/Resources/Notifications/Operations/ListNotifications.py @@ -1,5 +1,3 @@ -from dataclasses import dataclass - from paddle_billing_python_sdk.EnumStringify import enum_stringify from paddle_billing_python_sdk.HasParameters import HasParameters @@ -23,8 +21,8 @@ def __init__( self.pager = pager self.search = search self.filter = filter - self.end = DateTime.from_datetime(end) - self.start = DateTime.from_datetime(start) + self.end = end # DateTime.from_datetime(end) + self.start = start # DateTime.from_datetime(start) self.notification_setting_id = notification_setting_id if notification_setting_id is not None else [] self.statuses = statuses if statuses is not None else [] diff --git a/tests/Functional/Resources/Notifications/__init__.py b/tests/Functional/Resources/Notifications/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/Functional/Resources/Notifications/_fixtures/response/full_entity.json b/tests/Functional/Resources/Notifications/_fixtures/response/full_entity.json new file mode 100644 index 0000000..751309c --- /dev/null +++ b/tests/Functional/Resources/Notifications/_fixtures/response/full_entity.json @@ -0,0 +1,47 @@ +{ + "data": { + "id": "ntf_01h8bzam1z32agrxjwhjgqk8w6", + "type": "business.updated", + "status": "failed", + "payload": { + "data": { + "id": "biz_01h84a7hr4pzhsajkm8tev89ev", + "name": "ChatApp Inc.", + "status": "active", + "contacts": [ + { + "name": "Parker Jones", + "email": "parker@example.com" + }, + { + "name": "Jo Riley", + "email": "jo@example.com" + }, + { + "name": "Jesse Garcia", + "email": "jo@example.com" + } + ], + "created_at": "2023-08-18T12:34:25.668Z", + "updated_at": "2023-08-21T11:57:47.03542Z", + "company_number": "555775291485", + "tax_identifier": null + }, + "event_id": "evt_01h8bzakzx3hm2fmen703n5q45", + "event_type": "business.updated", + "occurred_at": "2023-08-21T11:57:47.390028Z", + "notification_id": "ntf_01h8bzam1z32agrxjwhjgqk8w6" + }, + "occurred_at": "2023-08-21T11:57:47.390028Z", + "delivered_at": null, + "replayed_at": null, + "origin": "event", + "last_attempt_at": "2023-08-21T12:15:53.620185Z", + "retry_at": null, + "times_attempted": 10, + "notification_setting_id": "ntfset_01h126ps19rp06wn89v9797mab" + }, + "meta": { + "request_id": "d14081ea-0062-491e-9035-0010f2216046" + } +} diff --git a/tests/Functional/Resources/Notifications/_fixtures/response/list_default.json b/tests/Functional/Resources/Notifications/_fixtures/response/list_default.json new file mode 100644 index 0000000..04cfbc5 --- /dev/null +++ b/tests/Functional/Resources/Notifications/_fixtures/response/list_default.json @@ -0,0 +1,459 @@ +{ + "data": [ + { + "id": "ntf_01h8bzam1z32agrxjwhjgqk8w6", + "type": "business.updated", + "status": "failed", + "payload": { + "data": { + "id": "biz_01h84a7hr4pzhsajkm8tev89ev", + "name": "ChatApp Inc.", + "status": "active", + "contacts": [ + { + "name": "Parker Jones", + "email": "parker@example.com" + }, + { + "name": "Jo Riley", + "email": "jo@example.com" + }, + { + "name": "Jesse Garcia", + "email": "jo@example.com" + } + ], + "created_at": "2023-08-18T12:34:25.668Z", + "updated_at": "2023-08-21T11:57:47.03542Z", + "company_number": "555775291485", + "tax_identifier": null + }, + "event_id": "evt_01h8bzakzx3hm2fmen703n5q45", + "event_type": "business.updated", + "occurred_at": "2023-08-21T11:57:47.390028Z", + "notification_id": "ntf_01h8bzam1z32agrxjwhjgqk8w6" + }, + "occurred_at": "2023-08-21T11:57:47.390028Z", + "delivered_at": null, + "replayed_at": null, + "origin": "event", + "last_attempt_at": "2023-08-21T12:15:53.620185Z", + "retry_at": null, + "times_attempted": 10, + "notification_setting_id": "ntfset_01h126ps19rp06wn89v9797mab" + }, + { + "id": "ntf_01h8brhd934tvsvf8s5q7thd2r", + "type": "transaction.created", + "status": "delivered", + "payload": { + "data": { + "id": "txn_01h8brhckjd6qk4n7e4py2340t", + "items": [ + { + "price": { + "id": "pri_01gsz8x8sawmvhz1pv30nge1ke", + "status": "active", + "quantity": { + "maximum": 999, + "minimum": 10 + }, + "tax_mode": "account_setting", + "product_id": "pro_01gsz4t5hdjse780zja8vvr7jg", + "unit_price": { + "amount": "3000", + "currency_code": "USD" + }, + "description": "Monthly (per seat)", + "name": "Monthly (per seat)", + "trial_period": null, + "billing_cycle": { + "interval": "month", + "frequency": 1 + }, + "unit_price_overrides": [ + { + "unit_price": { + "amount": "5000", + "currency_code": "AUD" + }, + "country_codes": [ + "AU" + ] + } + ] + }, + "price_id": "pri_01gsz8x8sawmvhz1pv30nge1ke", + "quantity": 10, + "proration": null + }, + { + "price": { + "id": "pri_01h1vjfevh5etwq3rb416a23h2", + "status": "active", + "quantity": { + "maximum": 100, + "minimum": 1 + }, + "tax_mode": "account_setting", + "product_id": "pro_01h1vjes1y163xfj1rh1tkfb65", + "unit_price": { + "amount": "10000", + "currency_code": "USD" + }, + "description": "Monthly (recurring addon)", + "name": "Monthly (recurring addon)", + "trial_period": null, + "billing_cycle": { + "interval": "month", + "frequency": 1 + }, + "unit_price_overrides": [ + { + "unit_price": { + "amount": "20000", + "currency_code": "AUD" + }, + "country_codes": [ + "AU" + ] + } + ] + }, + "price_id": "pri_01h1vjfevh5etwq3rb416a23h2", + "quantity": 1, + "proration": null + }, + { + "price": { + "id": "pri_01gsz98e27ak2tyhexptwc58yk", + "status": "active", + "quantity": { + "maximum": 1, + "minimum": 1 + }, + "tax_mode": "account_setting", + "product_id": "pro_01gsz97mq9pa4fkyy0wqenepkz", + "unit_price": { + "amount": "19900", + "currency_code": "USD" + }, + "description": "One-time charge", + "name": "One-time charge", + "trial_period": null, + "billing_cycle": null, + "unit_price_overrides": [ + { + "unit_price": { + "amount": "40000", + "currency_code": "AUD" + }, + "country_codes": [ + "AU" + ] + } + ] + }, + "price_id": "pri_01gsz98e27ak2tyhexptwc58yk", + "quantity": 1, + "proration": null + } + ], + "origin": "web", + "status": "draft", + "details": { + "totals": { + "fee": null, + "tax": "11980", + "total": "71880", + "credit": "0", + "credit_to_balance": "0", + "balance": "71880", + "discount": "0", + "earnings": null, + "subtotal": "59900", + "grand_total": "71880", + "currency_code": "USD" + }, + "line_items": [ + { + "id": "txnitm_01h8brhcmxzjp7zy6zxa4rmb6w", + "totals": { + "tax": "6000", + "total": "36000", + "discount": "0", + "subtotal": "30000" + }, + "product": { + "id": "pro_01gsz4t5hdjse780zja8vvr7jg", + "name": "ChatApp Pro", + "status": "active", + "image_url": "https://paddle-sandbox.s3.amazonaws.com/user/10889/2nmP8MQSret0aWeDemRw_icon1.png", + "description": "Everything in basic, plus access to a suite of powerful tools and features designed to take your team's productivity to the next level.", + "tax_category": "standard" + }, + "price_id": "pri_01gsz8x8sawmvhz1pv30nge1ke", + "quantity": 10, + "tax_rate": "0.2", + "unit_totals": { + "tax": "600", + "total": "3600", + "discount": "0", + "subtotal": "3000" + } + }, + { + "id": "txnitm_01h8brhcmxzjp7zy6zxbxpks7d", + "totals": { + "tax": "2000", + "total": "12000", + "discount": "0", + "subtotal": "10000" + }, + "product": { + "id": "pro_01h1vjes1y163xfj1rh1tkfb65", + "name": "Voice rooms addon", + "status": "active", + "image_url": "https://paddle-sandbox.s3.amazonaws.com/user/10889/GcZzBjXRfiraensppgtQ_icon2.png", + "description": "Create voice rooms in your chats to work in real time alongside your colleagues. Includes unlimited voice rooms and recording backup for compliance.", + "tax_category": "standard" + }, + "price_id": "pri_01h1vjfevh5etwq3rb416a23h2", + "quantity": 1, + "tax_rate": "0.2", + "unit_totals": { + "tax": "2000", + "total": "12000", + "discount": "0", + "subtotal": "10000" + } + }, + { + "id": "txnitm_01h8brhcmxzjp7zy6zxdm1d0wt", + "totals": { + "tax": "3980", + "total": "23880", + "discount": "0", + "subtotal": "19900" + }, + "product": { + "id": "pro_01gsz97mq9pa4fkyy0wqenepkz", + "name": "Custom domains", + "status": "active", + "image_url": "https://paddle-sandbox.s3.amazonaws.com/user/10889/SW3OevDQ92dUHSkN5a2x_icon3.png", + "description": "Make ChatApp truly your own with custom domains! Custom domains reinforce your brand identity and make it easy for your team to access ChatApp.", + "tax_category": "standard" + }, + "price_id": "pri_01gsz98e27ak2tyhexptwc58yk", + "quantity": 1, + "tax_rate": "0.2", + "unit_totals": { + "tax": "3980", + "total": "23880", + "discount": "0", + "subtotal": "19900" + } + } + ], + "payout_totals": null, + "tax_rates_used": [ + { + "totals": { + "tax": "11980", + "total": "71880", + "discount": "0", + "subtotal": "59900" + }, + "tax_rate": "0.2" + } + ] + }, + "checkout": { + "url": "https://magnificent-entremet-7ae0c6.netlify.app/default/overlay?_ptxn=txn_01h8brhckjd6qk4n7e4py2340t" + }, + "payments": [], + "billed_at": null, + "address_id": null, + "created_at": "2023-08-21T09:59:09.237822398Z", + "invoice_id": null, + "updated_at": "2023-08-21T09:59:09.237822398Z", + "business_id": null, + "custom_data": null, + "customer_id": null, + "discount_id": null, + "currency_code": "USD", + "billing_period": null, + "invoice_number": null, + "billing_details": null, + "collection_mode": "automatic", + "subscription_id": null + }, + "event_id": "evt_01h8brhd6mj4frv1dg3cghcrs3", + "event_type": "transaction.created", + "occurred_at": "2023-08-21T09:59:09.781003Z", + "notification_id": "ntf_01h8brhd934tvsvf8s5q7thd2r" + }, + "occurred_at": "2023-08-21T09:59:09.781003Z", + "delivered_at": "2023-08-21T09:59:10.316373Z", + "replayed_at": null, + "origin": "event", + "last_attempt_at": "2023-08-21T09:59:09.902732Z", + "retry_at": null, + "times_attempted": 1, + "notification_setting_id": "ntfset_01h7zcdzf04a7wvyja9k9p1n3p" + }, + { + "id": "ntf_01h8bkrfe7w1vwf8xmytwn51e7", + "type": "product.updated", + "status": "failed", + "payload": { + "data": { + "id": "pro_01h7zcgmdc6tmwtjehp3sh7azf", + "name": "ChatApp for Schools", + "status": "archived", + "image_url": "https://paddle-sandbox.s3.amazonaws.com/user/10889/2nmP8MQSret0aWeDemRw_icon1.png", + "created_at": "2023-08-16T14:38:08.3Z", + "custom_data": { + "features": { + "crm": false, + "reports": true, + "data_retention": true + } + }, + "description": "Spend more time engaging with students with ChataApp Education. Includes features from our Pro plan, plus tools to help educators track student progress.", + "tax_category": "standard" + }, + "event_id": "evt_01h8bkrfbwtaram1w8m7qekytx", + "event_type": "product.updated", + "occurred_at": "2023-08-21T08:35:38.493036Z", + "notification_id": "ntf_01h8bkrfe7w1vwf8xmytwn51e7" + }, + "occurred_at": "2023-08-21T08:35:38.493036Z", + "delivered_at": null, + "replayed_at": null, + "origin": "event", + "last_attempt_at": "2023-08-21T08:53:50.759289Z", + "retry_at": null, + "times_attempted": 10, + "notification_setting_id": "ntfset_01gt21c5pdx9q1e4mh1xrsjjn6" + }, + { + "id": "ntf_01h84cka91b65gy90qhe2tw2q6", + "type": "subscription.trialing", + "status": "delivered", + "payload": { + "data": { + "id": "sub_01h84ck8sg4ebkpzqb9x2mtjjf", + "items": [ + { + "price": { + "id": "pri_01h84cdy3xatsp16afda2gekzy", + "tax_mode": "account_setting", + "product_id": "pro_01h84cd36f900f3wmpdfamgv8w", + "unit_price": { + "amount": "0", + "currency_code": "USD" + }, + "description": "Annual plan", + "trial_period": { + "interval": "day", + "frequency": 10 + }, + "billing_cycle": { + "interval": "year", + "frequency": 1 + } + }, + "status": "trialing", + "quantity": 1, + "recurring": true, + "created_at": "2023-08-18T13:15:46.864164Z", + "updated_at": "2023-08-18T13:15:46.864164Z", + "trial_dates": { + "ends_at": "2023-08-28T13:15:46.864158Z", + "starts_at": "2023-08-18T13:15:46.864158Z" + }, + "next_billed_at": "2023-08-28T13:15:46.864158Z", + "previously_billed_at": null + } + ], + "status": "trialing", + "paused_at": null, + "address_id": "add_01h84cjfy5411jpjes4hmafqry", + "created_at": "2023-08-18T13:15:46.864163Z", + "started_at": "2023-08-18T13:15:46.864158Z", + "updated_at": "2023-08-18T13:15:46.864163Z", + "business_id": null, + "canceled_at": null, + "custom_data": null, + "customer_id": "ctm_01h84cjfwmdph1k8kgsyjt3k7g", + "billing_cycle": { + "interval": "year", + "frequency": 1 + }, + "currency_code": "USD", + "next_billed_at": "2023-08-28T13:15:46.864158Z", + "billing_details": null, + "collection_mode": "automatic", + "first_billed_at": null, + "scheduled_change": null, + "current_billing_period": { + "ends_at": "2023-08-28T13:15:46.864158Z", + "starts_at": "2023-08-18T13:15:46.864158Z" + }, + "import_meta": null + }, + "event_id": "evt_01h84cka4p40e737vm1ajb2bc5", + "event_type": "subscription.trialing", + "occurred_at": "2023-08-18T13:15:48.246292Z", + "notification_id": "ntf_01h84cka91b65gy90qhe2tw2q6" + }, + "occurred_at": "2023-08-18T13:15:48.246292Z", + "delivered_at": "2023-08-18T13:15:49.043358Z", + "replayed_at": null, + "origin": "event", + "last_attempt_at": "2023-08-18T13:15:48.446347Z", + "retry_at": null, + "times_attempted": 1, + "notification_setting_id": "ntfset_01h7hssm6xememp4cx2h562hvq" + }, + { + "id": "ntf_01h8441jz6fr97hv7zemswj8cw", + "type": "customer.created", + "status": "delivered", + "payload": { + "data": { + "id": "ctm_01h8441jn5pcwrfhwh78jqt8hk", + "name": "Sam Miller", + "email": "sam@example.com", + "locale": "en", + "status": "active", + "created_at": "2023-08-18T10:46:18.533Z", + "updated_at": "2023-08-18T10:46:18.533Z", + "marketing_consent": false + }, + "event_id": "evt_01h8441jx8x1q971q9ksksqh82", + "event_type": "customer.created", + "occurred_at": "2023-08-18T10:46:18.792661Z", + "notification_id": "ntf_01h8441jz6fr97hv7zemswj8cw" + }, + "occurred_at": "2023-08-18T10:46:18.792661Z", + "delivered_at": "2023-08-18T10:46:19.396422Z", + "replayed_at": null, + "origin": "event", + "last_attempt_at": "2023-08-18T10:46:18.887423Z", + "retry_at": null, + "times_attempted": 1, + "notification_setting_id": "ntfset_01h7zcdzf04a7wvyja9k9p1n3p" + } + ], + "meta": { + "pagination": { + "per_page": 50, + "estimated_total": 5, + "next": "http://api.paddle.com/notifications?after=ntf_01h8441jz6fr97hv7zemswj8cw", + "has_more": false + }, + "request_id": "21279f36-3eee-4828-943b-e2a9a6df4fce" + } +} diff --git a/tests/Functional/Resources/Notifications/_fixtures/response/replay.json b/tests/Functional/Resources/Notifications/_fixtures/response/replay.json new file mode 100644 index 0000000..a6fc2b4 --- /dev/null +++ b/tests/Functional/Resources/Notifications/_fixtures/response/replay.json @@ -0,0 +1,8 @@ +{ + "data": { + "notification_id": "ntf_01h46h1s2zabpkdks7yt4vkgkc" + }, + "meta": { + "request_id": "cfe92cac-86a1-49fe-ac50-20620dcd024f" + } +} diff --git a/tests/Functional/Resources/Notifications/test_NotificationsClient.py b/tests/Functional/Resources/Notifications/test_NotificationsClient.py new file mode 100644 index 0000000..ff80d8f --- /dev/null +++ b/tests/Functional/Resources/Notifications/test_NotificationsClient.py @@ -0,0 +1,203 @@ +from json import loads +from pytest import mark +from urllib.parse import unquote + +from paddle_billing_python_sdk.Entities.DateTime import DateTime +from paddle_billing_python_sdk.Entities.Notification import Notification +from paddle_billing_python_sdk.Entities.Notifications.NotificationStatus import NotificationStatus + +from paddle_billing_python_sdk.Entities.Collections.NotificationCollection import NotificationCollection + +from paddle_billing_python_sdk.Resources.Notifications.Operations.ListNotifications import ListNotifications +from paddle_billing_python_sdk.Resources.Shared.Operations.List.Pager import Pager + +from tests.Utils.TestClient import mock_requests, test_client +from tests.Utils.ReadsFixture import ReadsFixtures + + +class TestNotificationsClient: + @mark.parametrize( + 'operation, expected_response_status, expected_response_body, expected_url', + [ + ( + ListNotifications(), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications', + ), ( + ListNotifications(Pager()), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications?order_by=id[asc]&per_page=50', + ), ( + ListNotifications(Pager(after='nft_01h83xenpcfjyhkqr4x214m02x')), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications?after=nft_01h83xenpcfjyhkqr4x214m02x&order_by=id[asc]&per_page=50', + ), ( + ListNotifications(notification_setting_id=['nftset_01h83xenpcfjyhkqr4x214m02']), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications?notification_setting_id=nftset_01h83xenpcfjyhkqr4x214m02', + ), ( + ListNotifications(notification_setting_id=[ + 'nftset_01h83xenpcfjyhkqr4x214m02', + 'nftset_01h8brhckjd6qk4n7e4py2340t', + ]), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications?notification_setting_id=nftset_01h83xenpcfjyhkqr4x214m02,nftset_01h8brhckjd6qk4n7e4py2340t', + ), ( + ListNotifications(statuses=[NotificationStatus.Delivered]), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications?status=delivered', + ), ( + ListNotifications(statuses=[NotificationStatus.Delivered, NotificationStatus.NotAttempted]), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications?status=delivered,not_attempted', + ), ( + ListNotifications(filter='txn_01h83xenpcfjyhkqr4x214m02'), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications?filter=txn_01h83xenpcfjyhkqr4x214m02', + ), ( + ListNotifications(search='transaction.created'), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications?search=transaction.created', + ), ( + ListNotifications(end=DateTime('2023-12-25T00:00:00.000Z')), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications?to=2023-12-25T00:00:00.000000Z', + ), ( + ListNotifications(start=DateTime('2023-12-24T00:00:00.000Z')), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications?from=2023-12-24T00:00:00.000000Z', + ), ( + ListNotifications( + start = DateTime('2023-12-24T00:00:00.000Z'), + end = DateTime('2023-12-25T00:00:00.000Z'), + ), + 200, + ReadsFixtures.read_raw_json_fixture('response/list_default'), + '/notifications?to=2023-12-25T00:00:00.000000Z&from=2023-12-24T00:00:00.000000Z', + ), + ], + ids=[ + "List transactions without pagination", + "List transactions with default pagination", + "List paginated transactions after specified transaction_id", + "List transactions filtered by notification_setting_id", + "List transactions filtered by multiple notification_setting_ids", + "List transactions filtered by status", + "List transactions filtered by multiple statuses", + "List transactions filtered by id", + "List transactions filtered by search string", + "List transactions filtered by to time", + "List transactions filtered by from time", + "List transactions filtered by to & from time", + ], + ) + def test_list_transactions_returns_expected_response( + self, + test_client, + mock_requests, + operation, + expected_response_status, + expected_response_body, + expected_url, + ): + expected_url = f"{test_client.base_url}{expected_url}" + mock_requests.get(expected_url, status_code=expected_response_status, text=expected_response_body) + + response = test_client.client.notifications.list(operation) + last_request = mock_requests.last_request + + assert isinstance(response, NotificationCollection) + assert last_request is not None + assert last_request.method == 'GET' + assert test_client.client.status_code == expected_response_status + assert unquote(last_request.url) == expected_url, \ + "The URL does not match the expected URL, verify the query string is correct" + + @mark.parametrize( + 'notification_id, expected_response_status, expected_response_body, expected_url', + [( + 'nft_01h8441jn5pcwrfhwh78jqt8hk', + 200, + ReadsFixtures.read_raw_json_fixture('response/full_entity'), + '/notifications/nft_01h8441jn5pcwrfhwh78jqt8hk', + )], + ids=["Get a notification by its id"], + ) + def test_get_notification_returns_expected_response( + self, + test_client, + mock_requests, + notification_id, + expected_response_status, + expected_response_body, + expected_url, + ): + expected_url = f"{test_client.base_url}{expected_url}" + mock_requests.get(expected_url, status_code=expected_response_status, text=expected_response_body) + + response = test_client.client.notifications.get(notification_id) + response_json = test_client.client.notifications.response.json() + last_request = mock_requests.last_request + + assert isinstance(response, Notification) + assert last_request is not None + assert last_request.method == 'GET' + assert test_client.client.status_code == expected_response_status + assert unquote(last_request.url) == expected_url, \ + "The URL does not match the expected URL, verify the query string is correct" + assert response_json == loads(str(expected_response_body)), \ + "The response JSON generated by ResponseParser() doesn't match the expected fixture JSON" + + + @mark.parametrize( + 'notification_id,' + 'expected_response_status,' + 'expected_response_body,' + 'expected_response_notification_id,' + 'expected_url', + [( + 'nft_01h8441jn5pcwrfhwh78jqt8hk', + 200, + ReadsFixtures.read_raw_json_fixture('response/replay'), + 'ntf_01h46h1s2zabpkdks7yt4vkgkc', + '/notifications/nft_01h8441jn5pcwrfhwh78jqt8hk', + )], + ids=["Replay a notification by its id"], + ) + def test_replacy_notification_returns_expected_response( + self, + test_client, + mock_requests, + notification_id, + expected_response_status, + expected_response_body, + expected_response_notification_id, + expected_url, + ): + expected_url = f"{test_client.base_url}{expected_url}" + mock_requests.post(expected_url, status_code=expected_response_status, text=expected_response_body) + + response = test_client.client.notifications.replay(notification_id) + response_json = test_client.client.notifications.response.json() + last_request = mock_requests.last_request + + assert last_request is not None + assert last_request.method == 'POST' + assert test_client.client.status_code == expected_response_status + assert unquote(last_request.url) == expected_url, \ + "The URL does not match the expected URL, verify the query string is correct" + assert response_json == loads(str(expected_response_body)), \ + "The response JSON generated by ResponseParser() doesn't match the expected fixture JSON" + assert response == expected_response_notification_id, \ + "The response notification_id doesn't match the expected fixture JSON notification_id" diff --git a/tests/Functional/Resources/Reports/test_ReportsClient.py b/tests/Functional/Resources/Reports/test_ReportsClient.py index f522606..c5f7d4b 100644 --- a/tests/Functional/Resources/Reports/test_ReportsClient.py +++ b/tests/Functional/Resources/Reports/test_ReportsClient.py @@ -134,10 +134,10 @@ def test_list_reports_returns_expected_response( @mark.parametrize( 'report_id, expected_response_status, expected_response_body, expected_url', [( - 'rep_01hhq4c3b03g3x2kpkj8aecjv6', - 200, - ReadsFixtures.read_raw_json_fixture('response/full_entity'), - '/reports/rep_01hhq4c3b03g3x2kpkj8aecjv6', + 'rep_01hhq4c3b03g3x2kpkj8aecjv6', + 200, + ReadsFixtures.read_raw_json_fixture('response/full_entity'), + '/reports/rep_01hhq4c3b03g3x2kpkj8aecjv6', )], ids=["Get a report by its id"], ) @@ -170,10 +170,10 @@ def test_get_report_returns_expected_response( @mark.parametrize( 'report_id, expected_response_status, expected_response_body, expected_url', [( - 'rep_01hhq4c3b03g3x2kpkj8aecjv6', - 200, - ReadsFixtures.read_raw_json_fixture('response/report_csv_entity'), - '/reports/rep_01hhq4c3b03g3x2kpkj8aecjv6/download-url', + 'rep_01hhq4c3b03g3x2kpkj8aecjv6', + 200, + ReadsFixtures.read_raw_json_fixture('response/report_csv_entity'), + '/reports/rep_01hhq4c3b03g3x2kpkj8aecjv6/download-url', )], ids=["Get a report csv by its id"], )