paddle-python-sdk 1.1.2__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
paddle_billing/Client.py CHANGED
@@ -20,6 +20,7 @@ from paddle_billing.Resources.Addresses.AddressesClient import AddressesClient
20
20
  from paddle_billing.Resources.Adjustments.AdjustmentsClient import AdjustmentsClient
21
21
  from paddle_billing.Resources.Businesses.BusinessesClient import BusinessesClient
22
22
  from paddle_billing.Resources.Customers.CustomersClient import CustomersClient
23
+ from paddle_billing.Resources.CustomerPortalSessions.CustomerPortalSessionsClient import CustomerPortalSessionsClient
23
24
  from paddle_billing.Resources.Discounts.DiscountsClient import DiscountsClient
24
25
  from paddle_billing.Resources.Events.EventsClient import EventsClient
25
26
  from paddle_billing.Resources.EventTypes.EventTypesClient import EventTypesClient
@@ -85,6 +86,7 @@ class Client:
85
86
  self.adjustments = AdjustmentsClient(self)
86
87
  self.businesses = BusinessesClient(self)
87
88
  self.customers = CustomersClient(self)
89
+ self.customer_portal_sessions = CustomerPortalSessionsClient(self)
88
90
  self.discounts = DiscountsClient(self)
89
91
  self.events = EventsClient(self)
90
92
  self.event_types = EventTypesClient(self)
@@ -202,7 +204,7 @@ class Client:
202
204
  "Authorization": f"Bearer {self.__api_key}",
203
205
  "Content-Type": "application/json",
204
206
  "Paddle-Version": str(self.use_api_version),
205
- "User-Agent": "PaddleSDK/python 1.1.2",
207
+ "User-Agent": "PaddleSDK/python 1.2.0",
206
208
  }
207
209
  )
208
210
 
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+ from datetime import datetime
4
+
5
+ from paddle_billing.Entities.Entity import Entity
6
+ from paddle_billing.Entities.CustomerPortalSessions import CustomerPortalSessionUrls
7
+
8
+
9
+ @dataclass
10
+ class CustomerPortalSession(Entity):
11
+ id: str
12
+ customer_id: str | None
13
+ urls: CustomerPortalSessionUrls
14
+ created_at: datetime
15
+
16
+ @staticmethod
17
+ def from_dict(data: dict) -> CustomerPortalSession:
18
+ return CustomerPortalSession(
19
+ id=data["id"],
20
+ customer_id=data.get("customer_id"),
21
+ urls=CustomerPortalSessionUrls.from_dict(data["urls"]),
22
+ created_at=datetime.fromisoformat(data["created_at"]),
23
+ )
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+
4
+
5
+ @dataclass
6
+ class CustomerPortalSessionGeneralUrl:
7
+ overview: str
8
+
9
+ @staticmethod
10
+ def from_dict(data: dict) -> CustomerPortalSessionGeneralUrl:
11
+ return CustomerPortalSessionGeneralUrl(
12
+ overview=data["overview"],
13
+ )
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+
4
+
5
+ @dataclass
6
+ class CustomerPortalSessionSubscriptionUrl:
7
+ id: str
8
+ cancel_subscription: str
9
+ update_subscription_payment_method: str
10
+
11
+ @staticmethod
12
+ def from_dict(data: dict) -> CustomerPortalSessionSubscriptionUrl:
13
+ return CustomerPortalSessionSubscriptionUrl(
14
+ id=data["id"],
15
+ cancel_subscription=data["cancel_subscription"],
16
+ update_subscription_payment_method=data["update_subscription_payment_method"],
17
+ )
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+
4
+ from paddle_billing.Entities.CustomerPortalSessions.CustomerPortalSessionGeneralUrl import (
5
+ CustomerPortalSessionGeneralUrl,
6
+ )
7
+ from paddle_billing.Entities.CustomerPortalSessions.CustomerPortalSessionSubscriptionUrl import (
8
+ CustomerPortalSessionSubscriptionUrl,
9
+ )
10
+
11
+
12
+ @dataclass
13
+ class CustomerPortalSessionUrls:
14
+ general: CustomerPortalSessionGeneralUrl
15
+ subscriptions: list[CustomerPortalSessionSubscriptionUrl]
16
+
17
+ @staticmethod
18
+ def from_dict(data: dict) -> CustomerPortalSessionUrls:
19
+ return CustomerPortalSessionUrls(
20
+ general=CustomerPortalSessionGeneralUrl.from_dict(data["general"]),
21
+ subscriptions=[
22
+ CustomerPortalSessionSubscriptionUrl.from_dict(item) for item in data.get("subscriptions", [])
23
+ ],
24
+ )
@@ -0,0 +1,7 @@
1
+ from paddle_billing.Entities.CustomerPortalSessions.CustomerPortalSessionUrls import CustomerPortalSessionUrls
2
+ from paddle_billing.Entities.CustomerPortalSessions.CustomerPortalSessionGeneralUrl import (
3
+ CustomerPortalSessionGeneralUrl,
4
+ )
5
+ from paddle_billing.Entities.CustomerPortalSessions.CustomerPortalSessionSubscriptionUrl import (
6
+ CustomerPortalSessionSubscriptionUrl,
7
+ )
@@ -0,0 +1,24 @@
1
+ from paddle_billing.ResponseParser import ResponseParser
2
+
3
+ from paddle_billing.Entities.CustomerPortalSession import CustomerPortalSession
4
+
5
+ from paddle_billing.Resources.CustomerPortalSessions.Operations import (
6
+ CreateCustomerPortalSession,
7
+ )
8
+
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from paddle_billing.Client import Client
13
+
14
+
15
+ class CustomerPortalSessionsClient:
16
+ def __init__(self, client: "Client"):
17
+ self.client = client
18
+ self.response = None
19
+
20
+ def create(self, customer_id: str, operation: CreateCustomerPortalSession) -> CustomerPortalSession:
21
+ self.response = self.client.post_raw(f"/customers/{customer_id}/portal-sessions", operation)
22
+ parser = ResponseParser(self.response)
23
+
24
+ return CustomerPortalSession.from_dict(parser.get_data())
@@ -0,0 +1,8 @@
1
+ from dataclasses import dataclass
2
+
3
+ from paddle_billing.Operation import Operation
4
+
5
+
6
+ @dataclass
7
+ class CreateCustomerPortalSession(Operation):
8
+ subscription_ids: list[str] = (None,)
@@ -0,0 +1,3 @@
1
+ from paddle_billing.Resources.CustomerPortalSessions.Operations.CreateCustomerPortalSession import (
2
+ CreateCustomerPortalSession,
3
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: paddle-python-sdk
3
- Version: 1.1.2
3
+ Version: 1.2.0
4
4
  Summary: Paddle's Python SDK for Paddle Billing
5
5
  Home-page: https://developer.paddle.com/api-reference/overview
6
6
  Author: Paddle and contributors
@@ -16,16 +16,16 @@ Classifier: Programming Language :: Python :: 3.13
16
16
  Requires-Python: >=3.11
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: requests >=2.31
20
- Requires-Dist: urllib3 >=1.26.18
19
+ Requires-Dist: requests>=2.31
20
+ Requires-Dist: urllib3>=1.26.18
21
21
  Provides-Extra: dev
22
- Requires-Dist: pytest <8.4.0,>=7.4.4 ; extra == 'dev'
23
- Requires-Dist: pytest-cov ~=4.1.0 ; extra == 'dev'
24
- Requires-Dist: requests-mock ~=1.11.0 ; extra == 'dev'
25
- Requires-Dist: setuptools >=69.0.3 ; extra == 'dev'
26
- Requires-Dist: pre-commit >=3.8.0 ; extra == 'dev'
27
- Requires-Dist: black >=24.8.0 ; extra == 'dev'
28
- Requires-Dist: flake8 >=7.1.1 ; extra == 'dev'
22
+ Requires-Dist: pytest<8.4.0,>=7.4.4; extra == "dev"
23
+ Requires-Dist: pytest-cov~=4.1.0; extra == "dev"
24
+ Requires-Dist: requests-mock~=1.11.0; extra == "dev"
25
+ Requires-Dist: setuptools>=69.0.3; extra == "dev"
26
+ Requires-Dist: pre-commit>=3.8.0; extra == "dev"
27
+ Requires-Dist: black>=24.8.0; extra == "dev"
28
+ Requires-Dist: flake8>=7.1.1; extra == "dev"
29
29
 
30
30
  [![Build Status](https://img.shields.io/github/actions/workflow/status/PaddleHQ/paddle-python-sdk/publish_to_pypi.yml)](https://github.com/PaddleHQ/paddle-python-sdk/actions/?query=branch%3Amain)
31
31
  [![PyPI](https://img.shields.io/pypi/v/paddle-python-sdk.svg)](https://pypi.python.org/pypi/paddle-python-sdk)
@@ -4,7 +4,7 @@ examples/event_polling.py,sha256=580dg_8CFrSCA89Mr1ny4V1gtB3-hk-LfePTbI7DT5w,217
4
4
  examples/get_products.py,sha256=4V7ZG1SH6Oxojufbtzm_TMySw4cOBMQ99mgQK_hlwFQ,1875
5
5
  examples/logger.py,sha256=AxmQmMrsM0ZqMIUnh6iARiczL4S4F9OqQcOu-67owNg,1042
6
6
  examples/webhook_verification.py,sha256=qkNscNdNZUAgxEIk83tCiljN2VmfePZ_k8zTliKz2QY,1205
7
- paddle_billing/Client.py,sha256=bf6vfthuEdA_-1pATS7qmxGkmDwrYfaB1UJ-tEdgKJo,8594
7
+ paddle_billing/Client.py,sha256=YJAbjLy6YpKjoVk5KFU8qloYBJfuK8o3q9L80al-284,8787
8
8
  paddle_billing/EnumStringify.py,sha256=iDvKULZat3jx9A-_PhvoN6CbFGf2pyxrQeYZxqX9n8M,48
9
9
  paddle_billing/Environment.py,sha256=sY4nrJUwlTugsZKncieAnvfCojqCcKWi4X7rFzjFeSQ,417
10
10
  paddle_billing/FiltersNone.py,sha256=HxjE6RJb7sy6txphpZSrCTQZt1Ua0XpIz8NDLHC43zo,268
@@ -24,6 +24,7 @@ paddle_billing/Entities/Business.py,sha256=wlnAd_lC0Fuw7_BHKZGHt8q-aeLYO6MjO92EY
24
24
  paddle_billing/Entities/CreditBalance.py,sha256=aGCsfSf-qZl6kVTfHd41_1raiNuI29picji-bj7-lvg,673
25
25
  paddle_billing/Entities/Customer.py,sha256=3Ae2wmopq5CWL5FKiWGjXkEVcDVWLZHKCF4N3cjtFO4,1165
26
26
  paddle_billing/Entities/CustomerAuthToken.py,sha256=Zsm0NJDHRt9TYLTRXueW_m01piRA2QLRJ6SkfB_fLWo,493
27
+ paddle_billing/Entities/CustomerPortalSession.py,sha256=yDzD-QQuPyZTxQco4OkiH3EklPzq95iB6hZRn-0E5VM,720
27
28
  paddle_billing/Entities/DateTime.py,sha256=vJJRO6nASbJzESSk0LO6RxfroHnkvOBDfJKLswovbHE,1512
28
29
  paddle_billing/Entities/Discount.py,sha256=btcN1MSiKSDd-p5HMQikijDRIl2HGf-USd8pZ3CmGjE,1993
29
30
  paddle_billing/Entities/Entity.py,sha256=8zY_ehy4uqylrgY4Qo9yzsSPnpPa5PluzqytE9wcXrA,271
@@ -73,6 +74,10 @@ paddle_billing/Entities/Collections/TransactionCollection.py,sha256=gF1Kf9m5Gxc9
73
74
  paddle_billing/Entities/Collections/TransactionPreviewCollection.py,sha256=Rr8wgUgKItTqpRpJd12lJTH6Omgl0TSwdtvhpu23fKM,610
74
75
  paddle_billing/Entities/Collections/TransactionsDataCollection.py,sha256=cbOXZiwzK0zExvuep3W0abTTBuUuXA4gNuf2EyBR_p4,589
75
76
  paddle_billing/Entities/Collections/__init__.py,sha256=pxBG0tG74_DLxZ_hoA21X06u76fa2zMoRoLQEEPeRko,1980
77
+ paddle_billing/Entities/CustomerPortalSessions/CustomerPortalSessionGeneralUrl.py,sha256=aiGkjhzPtZHDMJvSxbubf5cvCxTIUkPPSZhzLm9AMuQ,321
78
+ paddle_billing/Entities/CustomerPortalSessions/CustomerPortalSessionSubscriptionUrl.py,sha256=FQLBqkLwbf47YmkHF1H_rsp-yU3FGLgEt_E5qInPK24,543
79
+ paddle_billing/Entities/CustomerPortalSessions/CustomerPortalSessionUrls.py,sha256=mDQgMnmJqjiS7PUboZYomV9OapZs6OHDgUtlyHUFuz4,862
80
+ paddle_billing/Entities/CustomerPortalSessions/__init__.py,sha256=DdA-g5zgW3A3ciOuMDebsQMhWkbbEv_fbAmLH4NOrio,385
76
81
  paddle_billing/Entities/Discounts/DiscountStatus.py,sha256=ss0Btu04U7NEXYgWxlnkUOWINjSXILu67LWEgLb1DaA,304
77
82
  paddle_billing/Entities/Discounts/DiscountType.py,sha256=7JQCM_dN2PGHSiA-jzBHTIRVMVTRFKdHAMKxDxpQgf0,270
78
83
  paddle_billing/Entities/Discounts/__init__.py,sha256=2zGGjrklZaaWj0iAwFRvTs_87yl8TOYy6R2RcH2kT_4,148
@@ -383,6 +388,10 @@ paddle_billing/Resources/Businesses/Operations/CreateBusiness.py,sha256=zDQ-V7El
383
388
  paddle_billing/Resources/Businesses/Operations/ListBusinesses.py,sha256=41XRKW61uAN9hepj2Nps0g2H5AtL7O2JqQUcyGhzt6M,1595
384
389
  paddle_billing/Resources/Businesses/Operations/UpdateBusiness.py,sha256=fzijE9x9ru58jOW5Rq-ZvV_LtFc7m6rksyJQiSNwyLA,562
385
390
  paddle_billing/Resources/Businesses/Operations/__init__.py,sha256=mctosPK-Kdb4n_AmdIqVFKeldZxcjw8e4k4iWWoRml0,267
391
+ paddle_billing/Resources/CustomerPortalSessions/CustomerPortalSessionsClient.py,sha256=GXW4jlb9d5nKxPS9D-azjC082g09e-DZQP6mg6lsu0s,804
392
+ paddle_billing/Resources/CustomerPortalSessions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
393
+ paddle_billing/Resources/CustomerPortalSessions/Operations/CreateCustomerPortalSession.py,sha256=2WAIHNVZ4vgr0kR7WTX9Z8VPwtxKLwD-VzGfwftj5gQ,183
394
+ paddle_billing/Resources/CustomerPortalSessions/Operations/__init__.py,sha256=2DBura-28E1UBZHCZ4kFkorjY-s8zADPrCLCVjo8KaU,136
386
395
  paddle_billing/Resources/Customers/CustomersClient.py,sha256=sYouOQZipuAG4ScusIepg7xM9B76BL2nF-21_WwLBDM,2691
387
396
  paddle_billing/Resources/Customers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
388
397
  paddle_billing/Resources/Customers/Operations/CreateCustomer.py,sha256=IxY4Df6S8f51VPM-CIrTQnPFjhoTh1l3BeBA7XseUNw,394
@@ -540,6 +549,8 @@ tests/Functional/Resources/Adjustments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
540
549
  tests/Functional/Resources/Adjustments/test_AdjustmentsClient.py,sha256=WJdb0EZ0xSf9O10R-gyfb78ltcUgJUxtRD_gyI3g1u0,14229
541
550
  tests/Functional/Resources/Businesses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
542
551
  tests/Functional/Resources/Businesses/test_BusinessesClient.py,sha256=uUAydFqmXq3snmu--gGVI5nNrpg6oySQM_Ulg9q-G1Q,12727
552
+ tests/Functional/Resources/CustomerPortalSessions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
553
+ tests/Functional/Resources/CustomerPortalSessions/test_CustomerPortalSessionsClient.py,sha256=Zb81Gqb8dcyhv2wmOtPPOWtaLW-eAGRAQiJRMGpzhV8,6625
543
554
  tests/Functional/Resources/Customers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
544
555
  tests/Functional/Resources/Customers/test_CustomersClient.py,sha256=tWDmre025VMQuUGcK6UE12Ulh7Ju_BeprKon2bM-OLk,14755
545
556
  tests/Functional/Resources/Discounts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -582,8 +593,8 @@ tests/Utils/ReadsFixture.py,sha256=M3Ot3xHXp_C7vwttna9deLPHBAO8ml2Jb4thhHOJJ38,1
582
593
  tests/Utils/TestClient.py,sha256=-wc7hJMuR6WC-ukw0c7I59b5-8hj_-nzq__-2M81elg,1453
583
594
  tests/Utils/TestLogger.py,sha256=pFO9x711buRmg-8DAqpzIJP_hr21JPty1_ZQRcwoGKk,554
584
595
  tests/Utils/__init__.py,sha256=JtqJNPKqbNZ9exlpXlF3yj_9cfylPGlvopjQYi7yYTA,37
585
- paddle_python_sdk-1.1.2.dist-info/LICENSE,sha256=e5Sn9mzCdpjnqCLxXpGHNKdYB6JlRSTLhN_CD4WSO6w,10770
586
- paddle_python_sdk-1.1.2.dist-info/METADATA,sha256=06dDCKvNoN0Bnzq2YtwPWhnxk7AN8a0KgH6oJ-VbLWs,7392
587
- paddle_python_sdk-1.1.2.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
588
- paddle_python_sdk-1.1.2.dist-info/top_level.txt,sha256=9a07VPng7o5wK8VAXkl6NC30xrNbW9zff_02jHyHi4c,30
589
- paddle_python_sdk-1.1.2.dist-info/RECORD,,
596
+ paddle_python_sdk-1.2.0.dist-info/LICENSE,sha256=e5Sn9mzCdpjnqCLxXpGHNKdYB6JlRSTLhN_CD4WSO6w,10770
597
+ paddle_python_sdk-1.2.0.dist-info/METADATA,sha256=3KF_YyYlVdyYiFWfe4_BcVDX-cEwYFsiUY2iIp9lswI,7376
598
+ paddle_python_sdk-1.2.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
599
+ paddle_python_sdk-1.2.0.dist-info/top_level.txt,sha256=9a07VPng7o5wK8VAXkl6NC30xrNbW9zff_02jHyHi4c,30
600
+ paddle_python_sdk-1.2.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.5.0)
2
+ Generator: setuptools (75.6.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,127 @@
1
+ from json import loads
2
+ from pytest import mark
3
+ from urllib.parse import unquote
4
+
5
+ from paddle_billing.Entities.CustomerPortalSession import CustomerPortalSession
6
+ from paddle_billing.Entities.CustomerPortalSessions import (
7
+ CustomerPortalSessionUrls,
8
+ CustomerPortalSessionGeneralUrl,
9
+ CustomerPortalSessionSubscriptionUrl,
10
+ )
11
+
12
+ from paddle_billing.Resources.CustomerPortalSessions.Operations import CreateCustomerPortalSession
13
+
14
+ from tests.Utils.ReadsFixture import ReadsFixtures
15
+
16
+
17
+ class TestAddressesClient:
18
+ @mark.parametrize(
19
+ "customer_id, operation, expected_request_body, expected_response_body, expected_path",
20
+ [
21
+ (
22
+ "ctm_01gysfvfy7vqhpzkq8rjmrq7an",
23
+ CreateCustomerPortalSession(["sub_01h04vsc0qhwtsbsxh3422wjs4"]),
24
+ ReadsFixtures.read_raw_json_fixture("request/create_single"),
25
+ ReadsFixtures.read_raw_json_fixture("response/full_entity_single"),
26
+ "/customers/ctm_01gysfvfy7vqhpzkq8rjmrq7an/portal-sessions",
27
+ ),
28
+ (
29
+ "ctm_01gysfvfy7vqhpzkq8rjmrq7an",
30
+ CreateCustomerPortalSession(["sub_01h04vsc0qhwtsbsxh3422wjs4", "sub_02h04vsc0qhwtsbsxh3422wjs4"]),
31
+ ReadsFixtures.read_raw_json_fixture("request/create_multiple"),
32
+ ReadsFixtures.read_raw_json_fixture("response/full_entity_multiple"),
33
+ "/customers/ctm_01gysfvfy7vqhpzkq8rjmrq7an/portal-sessions",
34
+ ),
35
+ ],
36
+ ids=[
37
+ "Create portal session with single subscription ID",
38
+ "Create portal session with multiple subscription IDs",
39
+ ],
40
+ )
41
+ def test_create_uses_expected_payload(
42
+ self,
43
+ test_client,
44
+ mock_requests,
45
+ customer_id,
46
+ operation,
47
+ expected_request_body,
48
+ expected_response_body,
49
+ expected_path,
50
+ ):
51
+ expected_url = f"{test_client.base_url}{expected_path}"
52
+ mock_requests.post(expected_url, status_code=201, text=expected_response_body)
53
+
54
+ response = test_client.client.customer_portal_sessions.create(customer_id, operation)
55
+ response_json = test_client.client.customer_portal_sessions.response.json()
56
+ request_json = test_client.client.payload
57
+ last_request = mock_requests.last_request
58
+
59
+ assert isinstance(response, CustomerPortalSession)
60
+ assert last_request is not None
61
+ assert last_request.method == "POST"
62
+ assert test_client.client.status_code == 201
63
+ assert (
64
+ unquote(last_request.url) == expected_url
65
+ ), "The URL does not match the expected URL, verify the query string is correct"
66
+ assert loads(request_json) == loads(
67
+ expected_request_body
68
+ ), "The request JSON doesn't match the expected fixture JSON"
69
+ assert response_json == loads(
70
+ str(expected_response_body)
71
+ ), "The response JSON doesn't match the expected fixture JSON"
72
+
73
+ def test_create_returns_expected_response(
74
+ self,
75
+ test_client,
76
+ mock_requests,
77
+ ):
78
+ customer_id = "ctm_01gysfvfy7vqhpzkq8rjmrq7an"
79
+ expected_path = "/customers/ctm_01gysfvfy7vqhpzkq8rjmrq7an/portal-sessions"
80
+ expected_response_body = ReadsFixtures.read_raw_json_fixture("response/full_entity_multiple")
81
+
82
+ expected_url = f"{test_client.base_url}{expected_path}"
83
+ mock_requests.post(expected_url, status_code=201, text=expected_response_body)
84
+
85
+ response = test_client.client.customer_portal_sessions.create(
86
+ customer_id,
87
+ CreateCustomerPortalSession(["sub_01h04vsc0qhwtsbsxh3422wjs4", "sub_02h04vsc0qhwtsbsxh3422wjs4"]),
88
+ )
89
+
90
+ assert isinstance(response, CustomerPortalSession)
91
+ assert response.id == "cpls_01h4ge9r64c22exjsx0fy8b48b"
92
+ assert response.customer_id == customer_id
93
+ assert response.created_at.isoformat() == "2024-10-25T06:53:58+00:00"
94
+
95
+ urls = response.urls
96
+ assert isinstance(urls, CustomerPortalSessionUrls)
97
+
98
+ general = urls.general
99
+ assert isinstance(general, CustomerPortalSessionGeneralUrl)
100
+ assert (
101
+ general.overview
102
+ == "https://customer-portal.paddle.com/cpl_01j7zbyqs3vah3aafp4jf62qaw?action=overview&token=pga_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjdG1fMDFncm5uNHp0YTVhMW1mMDJqanplN3kyeXMiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE3Mjc2NzkyMzh9._oO12IejzdKmyKTwb7BLjmiILkx4_cSyGjXraOBUI_g"
103
+ )
104
+
105
+ subscription1 = urls.subscriptions[0]
106
+ assert isinstance(subscription1, CustomerPortalSessionSubscriptionUrl)
107
+ assert subscription1.id == "sub_01h04vsc0qhwtsbsxh3422wjs4"
108
+ assert (
109
+ subscription1.cancel_subscription
110
+ == "https://customer-portal.paddle.com/cpl_01j7zbyqs3vah3aafp4jf62qaw?action=cancel_subscription&subscription_id=sub_01h04vsc0qhwtsbsxh3422wjs4&token=pga_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjdG1fMDFncm5uNHp0YTVhMW1mMDJqanplN3kyeXMiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE3Mjc2NzkyMzh9._oO12IejzdKmyKTwb7BLjmiILkx4_cSyGjXraOBUI_g"
111
+ )
112
+ assert (
113
+ subscription1.update_subscription_payment_method
114
+ == "https://customer-portal.paddle.com/cpl_01j7zbyqs3vah3aafp4jf62qaw?action=update_subscription_payment_method&subscription_id=sub_01h04vsc0qhwtsbsxh3422wjs4&token=pga_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjdG1fMDFncm5uNHp0YTVhMW1mMDJqanplN3kyeXMiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE3Mjc2NzkyMzh9._oO12IejzdKmyKTwb7BLjmiILkx4_cSyGjXraOBUI_g"
115
+ )
116
+
117
+ subscription2 = urls.subscriptions[1]
118
+ assert isinstance(subscription2, CustomerPortalSessionSubscriptionUrl)
119
+ assert subscription2.id == "sub_02h04vsc0qhwtsbsxh3422wjs4"
120
+ assert (
121
+ subscription2.cancel_subscription
122
+ == "https://customer-portal.paddle.com/cpl_01j7zbyqs3vah3aafp4jf62qaw?action=cancel_subscription&subscription_id=sub_02h04vsc0qhwtsbsxh3422wjs4&token=pga_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjdG1fMDFncm5uNHp0YTVhMW1mMDJqanplN3kyeXMiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE3Mjc2NzkyMzh9._oO12IejzdKmyKTwb7BLjmiILkx4_cSyGjXraOBUI_g"
123
+ )
124
+ assert (
125
+ subscription2.update_subscription_payment_method
126
+ == "https://customer-portal.paddle.com/cpl_01j7zbyqs3vah3aafp4jf62qaw?action=update_subscription_payment_method&subscription_id=sub_02h04vsc0qhwtsbsxh3422wjs4&token=pga_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjdG1fMDFncm5uNHp0YTVhMW1mMDJqanplN3kyeXMiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE3Mjc2NzkyMzh9._oO12IejzdKmyKTwb7BLjmiILkx4_cSyGjXraOBUI_g"
127
+ )