pypaystack2 3.2.0__tar.gz → 3.3.0__tar.gz

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.
Files changed (82) hide show
  1. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/PKG-INFO +1 -2
  2. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/pyproject.toml +2 -3
  3. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/_metadata.py +2 -2
  4. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/fees_calculation_mixin.py +21 -7
  5. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/main_clients.py +96 -0
  6. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/models/__init__.py +2 -0
  7. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/models/payload_models.py +19 -7
  8. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/models/response_models.py +3 -2
  9. pypaystack2-3.3.0/src/pypaystack2/sub_clients/async_clients/orders.py +191 -0
  10. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/payment_requests.py +6 -0
  11. pypaystack2-3.3.0/src/pypaystack2/sub_clients/async_clients/preauthorizations.py +318 -0
  12. pypaystack2-3.3.0/src/pypaystack2/sub_clients/async_clients/storefronts.py +399 -0
  13. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/virtual_terminals.py +1 -0
  14. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/dedicated_accounts.py +1 -1
  15. pypaystack2-3.3.0/src/pypaystack2/sub_clients/sync_clients/orders.py +191 -0
  16. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/payment_requests.py +6 -0
  17. pypaystack2-3.3.0/src/pypaystack2/sub_clients/sync_clients/preauthorizations.py +314 -0
  18. pypaystack2-3.3.0/src/pypaystack2/sub_clients/sync_clients/storefronts.py +395 -0
  19. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/virtual_terminals.py +1 -0
  20. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/README.md +0 -0
  21. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/__init__.py +0 -0
  22. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/base_clients.py +0 -0
  23. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/cli.py +0 -0
  24. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/enums.py +0 -0
  25. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/exceptions.py +0 -0
  26. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/py.typed +0 -0
  27. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/__init__.py +0 -0
  28. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/__init__.py +0 -0
  29. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/apple_pay.py +0 -0
  30. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/bulk_charges.py +0 -0
  31. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/charge.py +0 -0
  32. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/customers.py +0 -0
  33. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/dedicated_accounts.py +0 -0
  34. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/direct_debits.py +0 -0
  35. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/disputes.py +0 -0
  36. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/integration.py +0 -0
  37. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/miscellaneous.py +0 -0
  38. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/payment_pages.py +0 -0
  39. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/plans.py +0 -0
  40. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/products.py +0 -0
  41. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/refunds.py +0 -0
  42. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/settlements.py +0 -0
  43. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/splits.py +0 -0
  44. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/subaccounts.py +0 -0
  45. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/subscriptions.py +0 -0
  46. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/terminals.py +0 -0
  47. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/transactions.py +0 -0
  48. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/transfer_recipients.py +0 -0
  49. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/transfers.py +0 -0
  50. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/transfers_control.py +0 -0
  51. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/async_clients/verification.py +0 -0
  52. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/__init__.py +0 -0
  53. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/apple_pay.py +0 -0
  54. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/bulk_charges.py +0 -0
  55. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/charge.py +0 -0
  56. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/customers.py +0 -0
  57. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/direct_debits.py +0 -0
  58. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/disputes.py +0 -0
  59. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/integration.py +0 -0
  60. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/miscellaneous.py +0 -0
  61. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/payment_pages.py +0 -0
  62. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/plans.py +0 -0
  63. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/products.py +0 -0
  64. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/refunds.py +0 -0
  65. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/settlements.py +0 -0
  66. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/splits.py +0 -0
  67. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/subaccounts.py +0 -0
  68. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/subscriptions.py +0 -0
  69. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/terminals.py +0 -0
  70. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/transactions.py +0 -0
  71. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/transfer_recipients.py +0 -0
  72. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/transfers.py +0 -0
  73. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/transfers_control.py +0 -0
  74. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/sub_clients/sync_clients/verification.py +0 -0
  75. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/types.py +0 -0
  76. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/utils.py +0 -0
  77. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/webhook/__init__.py +0 -0
  78. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/webhook/cli.py +0 -0
  79. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/webhook/enums.py +0 -0
  80. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/webhook/logging_config.py +0 -0
  81. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/webhook/models.py +0 -0
  82. {pypaystack2-3.2.0 → pypaystack2-3.3.0}/src/pypaystack2/webhook/webhook_proxy_server.py +0 -0
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypaystack2
3
- Version: 3.2.0
3
+ Version: 3.3.0
4
4
  Summary: A developer-friendly client library for Paystack
5
5
  Keywords: paystack-python,pypaystack,paystack,paystackapi
6
6
  Author: Gbenga Adeyi
7
7
  Author-email: Gbenga Adeyi <adeyigbenga005@gmail.com>
8
8
  License-Expression: MIT
9
- Classifier: License :: OSI Approved :: MIT License
10
9
  Classifier: Programming Language :: Python
11
10
  Classifier: Programming Language :: Python :: 3
12
11
  Requires-Dist: httpx>=0.28.1
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pypaystack2"
3
- version = "3.2.0"
3
+ version = "3.3.0"
4
4
  description = "A developer-friendly client library for Paystack"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -9,7 +9,6 @@ authors = [
9
9
  ]
10
10
  keywords = ["paystack-python", "pypaystack", "paystack", "paystackapi"]
11
11
  classifiers = [
12
- "License :: OSI Approved :: MIT License",
13
12
  "Programming Language :: Python",
14
13
  "Programming Language :: Python :: 3",
15
14
  ]
@@ -32,7 +31,7 @@ webhook = [
32
31
  ]
33
32
 
34
33
  [build-system]
35
- requires = ["uv_build>=0.9.10,<0.10.0"]
34
+ requires = ["uv_build>=0.11.19,<0.12.0"]
36
35
  build-backend = "uv_build"
37
36
 
38
37
  [dependency-groups]
@@ -1,5 +1,5 @@
1
1
  __title__ = "pypaystack2"
2
- __version__ = "3.2.0"
2
+ __version__ = "3.3.0"
3
3
  __author__ = [{"name": "Gbenga Adeyi", "email": "adeyigbenga005@gmail.com"}]
4
4
  __license__ = "MIT"
5
- __copyright__ = "Copyright 2025."
5
+ __copyright__ = "Copyright 2026."
@@ -119,19 +119,33 @@ class FeesCalculationMixin:
119
119
  )
120
120
  options_model = options_validator_class.model_validate(options) # type: ignore
121
121
 
122
- if currency == Currency.NGN:
122
+ if currency == Currency.NGN and isinstance(
123
+ options_model, NigeriaServiceFeeOptions
124
+ ):
123
125
  return self._calculate_ngn_fee(amount, options_model)
124
- if currency == Currency.GHS:
126
+ if currency == Currency.GHS and isinstance(
127
+ options_model, GhanaServiceFeeOptions
128
+ ):
125
129
  return self._calculate_ghs_fee(amount, options_model)
126
- if currency == Currency.ZAR:
130
+ if currency == Currency.ZAR and isinstance(
131
+ options_model, SouthAfricaServiceFeeOptions
132
+ ):
127
133
  return self._calculate_zar_fee(amount, options_model)
128
- if currency == Currency.KES:
134
+ if currency == Currency.KES and isinstance(
135
+ options_model, KenyaServiceFeeOptions
136
+ ):
129
137
  return self._calculate_kes_fee(amount, options_model)
130
- if currency == Currency.XOF:
138
+ if currency == Currency.XOF and isinstance(
139
+ options_model, CoteDIvoreServiceFeeOptions
140
+ ):
131
141
  return self._calculate_xof_fee(amount, options_model)
132
- if currency == Currency.RWF:
142
+ if currency == Currency.RWF and isinstance(
143
+ options_model, RwandaServiceFeeOptions
144
+ ):
133
145
  return self._calculate_rwf_fee(amount, options_model)
134
- if currency == Currency.EGP:
146
+ if currency == Currency.EGP and isinstance(
147
+ options_model, EgyptServiceFeeOptions
148
+ ):
135
149
  return self._calculate_egp_fee(amount, options_model)
136
150
  raise ValueError(
137
151
  f"calculations not supported for the provided currency {currency}"
@@ -1,3 +1,15 @@
1
+ from pypaystack2.sub_clients.async_clients.storefronts import AsyncStorefrontClient
2
+ from pypaystack2.sub_clients.async_clients.orders import AsyncOrderClient
3
+ from pypaystack2.sub_clients.async_clients.preauthorizations import (
4
+ AsyncPreauthorizationClient,
5
+ )
6
+ from pypaystack2.sub_clients.sync_clients.preauthorizations import (
7
+ PreauthorizationClient,
8
+ )
9
+ from pypaystack2.sub_clients.sync_clients.orders import OrderClient
10
+ from pypaystack2.sub_clients.sync_clients.storefronts import StorefrontClient
11
+ from http import HTTPMethod
12
+ from pypaystack2.types import PaystackDataModel
1
13
  from pypaystack2.sub_clients.async_clients.direct_debits import AsyncDirectDebitClient
2
14
  from pypaystack2.sub_clients.sync_clients.direct_debits import DirectDebitClient
3
15
  from pypaystack2.sub_clients.async_clients.virtual_terminals import (
@@ -112,6 +124,12 @@ class PaystackClient(BaseAPIClient):
112
124
  Virtual Terminal API e.g. `VirtualTerminalClient.list`.
113
125
  direct_debits: A binding to `DirectDebitClient` providing methods for interacting with Paystack's
114
126
  Direct Debit API e.g. `DirectDebitClient.trigger_activation_charge`.
127
+ storefronts: A binding to `StorefrontClient` providing methods for interacting with Paystack's
128
+ Storefront API e.g. `StorefrontClient.create`.
129
+ orders: A binding to `OrderClient` providing methods for interacting with Paystack's
130
+ Order API e.g. `OrderClient.create`.
131
+ preauthorizations: A binding to `PreauthorizationClient` providing methods for interacting with Paystack's
132
+ Preauthorization API e.g. `PreauthorizationClient.initialize`.
115
133
  """
116
134
 
117
135
  def __init__(self, secret_key: str | None = None):
@@ -169,6 +187,41 @@ class PaystackClient(BaseAPIClient):
169
187
  )
170
188
  self.virtual_terminals = VirtualTerminalClient(secret_key=self._secret_key)
171
189
  self.direct_debits = DirectDebitClient(secret_key=self._secret_key)
190
+ self.storefronts = StorefrontClient(secret_key=self._secret_key)
191
+ self.orders = OrderClient(secret_key=self._secret_key)
192
+ self.preauthorizations = PreauthorizationClient(secret_key=self._secret_key)
193
+
194
+ def get_capitec_pay_transaction(
195
+ self,
196
+ reference: str,
197
+ alternate_model_class: type[PaystackDataModel] | None = None,
198
+ ):
199
+ """Check the status of a charge made with Capitec Pay.
200
+
201
+ Args:
202
+ reference: The transaction reference from the previously initiated charge request
203
+ alternate_model_class: A pydantic model class to use instead of the
204
+ default pydantic model used by the library to present the data in
205
+ the `Response.data`. The default behaviour of the library is to
206
+ set `Response.data` to `None` if it fails to serialize the data
207
+ returned from paystack with the model provided in the library.
208
+ Providing a pydantic model class via this parameter overrides
209
+ the library default model with the model class you provide.
210
+ This can come in handy when the models in the library do not
211
+ accurately represent the data returned, and you prefer working with the
212
+ data as a pydantic model instead of as a dict of the response returned
213
+ by paystack before it is serialized with pydantic models, The original
214
+ data can be accessed via `Response.raw`.
215
+
216
+ Returns:
217
+ A pydantic model containing the response gotten from paystack's server.
218
+ """
219
+ url = self._full_url(f"/capitec-pay/requery/{reference}")
220
+ return self._handle_request(
221
+ HTTPMethod.POST,
222
+ url,
223
+ response_data_model_class=alternate_model_class,
224
+ )
172
225
 
173
226
 
174
227
  class AsyncPaystackClient(BaseAsyncAPIClient):
@@ -228,6 +281,12 @@ class AsyncPaystackClient(BaseAsyncAPIClient):
228
281
  Virtual Terminal API e.g. `AsyncVirtualTerminalClient.list`.
229
282
  direct_debits: A binding to `AsyncDirectDebitClient` providing methods for interacting with Paystack's
230
283
  Direct Debit API e.g. `AsyncDirectDebitClient.trigger_activation_charge`.
284
+ storefronts: A binding to `AsyncStorefrontClient` providing methods for interacting with Paystack's
285
+ Storefront API e.g. `AsyncStorefrontClient.create`.
286
+ orders: A binding to `AsyncOrderClient` providing methods for interacting with Paystack's
287
+ Order API e.g. `AsyncOrderClient.create`.
288
+ preauthorizations: A binding to `AsyncPreauthorizationClient` providing methods for interacting with Paystack's
289
+ Preauthorization API e.g. `AsyncPreauthorizationClient.initialize`.
231
290
 
232
291
  """
233
292
 
@@ -262,3 +321,40 @@ class AsyncPaystackClient(BaseAsyncAPIClient):
262
321
  self.verification = AsyncVerificationClient(secret_key=self._secret_key)
263
322
  self.virtual_terminals = AsyncVirtualTerminalClient(secret_key=self._secret_key)
264
323
  self.direct_debits = AsyncDirectDebitClient(secret_key=self._secret_key)
324
+ self.storefronts = AsyncStorefrontClient(secret_key=self._secret_key)
325
+ self.orders = AsyncOrderClient(secret_key=self._secret_key)
326
+ self.preauthorizations = AsyncPreauthorizationClient(
327
+ secret_key=self._secret_key
328
+ )
329
+
330
+ async def get_capitec_pay_transaction(
331
+ self,
332
+ reference: str,
333
+ alternate_model_class: type[PaystackDataModel] | None = None,
334
+ ):
335
+ """Check the status of a charge made with Capitec Pay.
336
+
337
+ Args:
338
+ reference: The transaction reference from the previously initiated charge request
339
+ alternate_model_class: A pydantic model class to use instead of the
340
+ default pydantic model used by the library to present the data in
341
+ the `Response.data`. The default behaviour of the library is to
342
+ set `Response.data` to `None` if it fails to serialize the data
343
+ returned from paystack with the model provided in the library.
344
+ Providing a pydantic model class via this parameter overrides
345
+ the library default model with the model class you provide.
346
+ This can come in handy when the models in the library do not
347
+ accurately represent the data returned, and you prefer working with the
348
+ data as a pydantic model instead of as a dict of the response returned
349
+ by paystack before it is serialized with pydantic models, The original
350
+ data can be accessed via `Response.raw`.
351
+
352
+ Returns:
353
+ A pydantic model containing the response gotten from paystack's server.
354
+ """
355
+ url = self._full_url(f"/capitec-pay/requery/{reference}")
356
+ return await self._handle_request(
357
+ HTTPMethod.POST,
358
+ url,
359
+ response_data_model_class=alternate_model_class,
360
+ )
@@ -3,6 +3,7 @@ from pypaystack2.models.payload_models import (
3
3
  RefundAccount,
4
4
  BulkChargeInstruction,
5
5
  LineItem,
6
+ OrderLineItem,
6
7
  Tax,
7
8
  SplitAccount,
8
9
  Recipient,
@@ -90,6 +91,7 @@ __all__ = [
90
91
  # payload models
91
92
  "BulkChargeInstruction",
92
93
  "LineItem",
94
+ "OrderLineItem",
93
95
  "Tax",
94
96
  "SplitAccount",
95
97
  "Recipient",
@@ -1,12 +1,12 @@
1
1
  from typing import Any, Optional, Literal, Self
2
2
 
3
- from pydantic import BaseModel, model_validator
3
+ from pydantic import BaseModel, model_validator, Field
4
4
 
5
5
  from pypaystack2.enums import RecipientType, Currency
6
6
 
7
7
 
8
8
  class RefundAccount(BaseModel):
9
- """A dataclass for representing refund account
9
+ """A pydantic model for representing refund account
10
10
  details
11
11
 
12
12
  Attributes:
@@ -22,7 +22,7 @@ class RefundAccount(BaseModel):
22
22
 
23
23
 
24
24
  class BulkChargeInstruction(BaseModel):
25
- """A dataclass for bulk charge instruction.
25
+ """A pydantic model for bulk charge instruction.
26
26
 
27
27
  Attributes:
28
28
  authorization: The authorization code of the customer you want to charge.
@@ -36,7 +36,7 @@ class BulkChargeInstruction(BaseModel):
36
36
 
37
37
 
38
38
  class LineItem(BaseModel):
39
- """A dataclass for LineItem.
39
+ """A pydantic model for LineItem.
40
40
 
41
41
  Attributes:
42
42
  name: The name of the product.
@@ -49,8 +49,20 @@ class LineItem(BaseModel):
49
49
  quantity: int
50
50
 
51
51
 
52
+ class OrderLineItem(BaseModel):
53
+ """A pydantic model for representing a line item in an order
54
+
55
+ Attributes:
56
+ product: The ID of the product
57
+ quantity: The quantity of of the product
58
+ """
59
+
60
+ product: int
61
+ quantity: int = Field(1, ge=1)
62
+
63
+
52
64
  class Tax(BaseModel):
53
- """A dataclass for Tax.
65
+ """A pydantic model for Tax.
54
66
 
55
67
  Attributes:
56
68
  name: The name of the tax.
@@ -62,7 +74,7 @@ class Tax(BaseModel):
62
74
 
63
75
 
64
76
  class SplitAccount(BaseModel):
65
- """A dataclass for SplitAccount.
77
+ """A pydantic model for SplitAccount.
66
78
 
67
79
  Attributes:
68
80
  subaccount: The id of the sub account.
@@ -99,7 +111,7 @@ class Recipient(BaseModel):
99
111
 
100
112
 
101
113
  class TransferInstruction(BaseModel):
102
- """A dataclass for TransferInstruction.
114
+ """A pydantic model for TransferInstruction.
103
115
 
104
116
  Attributes:
105
117
  amount: The amount to be transferred.
@@ -352,7 +352,7 @@ class PaymentRequestNotification(BaseModel):
352
352
 
353
353
  class PaymentRequest(BaseModel):
354
354
  id: int
355
- integration: int | Integration
355
+ integration: int | Integration | None = None
356
356
  domain: Domain
357
357
  amount: int
358
358
  currency: Currency
@@ -368,7 +368,7 @@ class PaymentRequest(BaseModel):
368
368
  paid: bool
369
369
  paid_at: datetime | None = None
370
370
  metadata: dict[str, Any] | None = None
371
- notifications: list[PaymentRequestNotification]
371
+ notifications: list[PaymentRequestNotification] | str
372
372
  offline_reference: str
373
373
  customer: Customer | int
374
374
  created_at: datetime
@@ -751,6 +751,7 @@ class Refund(BaseModel):
751
751
  refund_channel: str | None = None
752
752
  session_id: Any | None = None
753
753
  collect_account_number: bool | None = None
754
+ created_at: datetime | None = None
754
755
 
755
756
 
756
757
  class CardBin(BaseModel):
@@ -0,0 +1,191 @@
1
+ from http import HTTPMethod
2
+ from pypaystack2.models import Response
3
+ from pypaystack2.types import PaystackDataModel
4
+ from pypaystack2.models.payload_models import OrderLineItem
5
+ from pypaystack2.base_clients import append_query_params, BaseAsyncAPIClient
6
+
7
+
8
+ class AsyncOrderClient(BaseAsyncAPIClient):
9
+ """Provides a wrapper for paystack Orders API
10
+
11
+ The Orders API allows you to create and manage orders for your products.
12
+ """
13
+
14
+ async def create(
15
+ self,
16
+ customer: int | str,
17
+ line_items: list[OrderLineItem],
18
+ alternate_model_class: type[PaystackDataModel] | None = None,
19
+ ) -> Response[PaystackDataModel]:
20
+ """Create an order for selected items
21
+
22
+ Args:
23
+ customer: The customer code or ID whom the order belongs to
24
+ line_items: The items in the order, it is a list of pydantic model
25
+ `OrderLineItem` that contains the fields `product` which is the
26
+ id of the product and `quantity` which is the amount of that product
27
+ the customer ordered.
28
+ alternate_model_class: A pydantic model class to use instead of the
29
+ default pydantic model used by the library to present the data in
30
+ the `Response.data`. The default behaviour of the library is to
31
+ set `Response.data` to `None` if it fails to serialize the data
32
+ returned from paystack with the model provided in the library.
33
+ Providing a pydantic model class via this parameter overrides
34
+ the library default model with the model class you provide.
35
+ This can come in handy when the models in the library do not
36
+ accurately represent the data returned, and you prefer working with the
37
+ data as a pydantic model instead of as a dict of the response returned
38
+ by paystack before it is serialized with pydantic models, The original
39
+ data can be accessed via `Response.raw`.
40
+
41
+ Returns:
42
+ A pydantic model containing the response gotten from paystack's server.
43
+ """
44
+ _line_items = [item.model_dump(mode="json") for item in line_items]
45
+ payload = {
46
+ "customer": customer,
47
+ "line_items": _line_items,
48
+ }
49
+ url = self._full_url("/order")
50
+ return await self._handle_request( # type: ignore
51
+ HTTPMethod.POST,
52
+ url,
53
+ data=payload,
54
+ response_data_model_class=alternate_model_class,
55
+ )
56
+
57
+ async def get_orders(
58
+ self,
59
+ pagination: int = 50,
60
+ page: int = 1,
61
+ start_date: str | None = None,
62
+ end_date: str | None = None,
63
+ alternate_model_class: type[PaystackDataModel] | None = None,
64
+ ) -> Response[PaystackDataModel]:
65
+ """List the orders available on your integration
66
+
67
+ Args:
68
+ pagination: Specifies how many orders you want to retrieve call.
69
+ page: Specifies the page to retrieve from the pagination.
70
+ start_date: A timestamp at which to start listing orders e.g. `2016-09-24T00:00:05.000Z`, `2016-09-21`
71
+ end_date: A timestamp at which to stop listing orders e.g. `2016-09-24T00:00:05.000Z`, `2016-09-21`
72
+ alternate_model_class: A pydantic model class to use instead of the
73
+ default pydantic model used by the library to present the data in
74
+ the `Response.data`. The default behaviour of the library is to
75
+ set `Response.data` to `None` if it fails to serialize the data
76
+ returned from paystack with the model provided in the library.
77
+ Providing a pydantic model class via this parameter overrides
78
+ the library default model with the model class you provide.
79
+ This can come in handy when the models in the library do not
80
+ accurately represent the data returned, and you prefer working with the
81
+ data as a pydantic model instead of as a dict of the response returned
82
+ by paystack before it is serialized with pydantic models, The original
83
+ data can be accessed via `Response.raw`.
84
+
85
+ Returns:
86
+ A pydantic model containing the response gotten from paystack's server.
87
+ """
88
+ query_params = [("page", page), ("from", start_date), ("to", end_date)]
89
+ url = self._full_url(f"/order/?perPage={pagination}")
90
+ url = append_query_params(query_params, url)
91
+ return await self._handle_request( # type: ignore
92
+ HTTPMethod.GET,
93
+ url,
94
+ response_data_model_class=alternate_model_class,
95
+ )
96
+
97
+ async def get_order(
98
+ self,
99
+ id: int,
100
+ alternate_model_class: type[PaystackDataModel] | None = None,
101
+ ) -> Response[PaystackDataModel]:
102
+ """Fetch the details of an order on your integration
103
+
104
+ Args:
105
+ id: The ID of the order you want to retrieve.
106
+ alternate_model_class: A pydantic model class to use instead of the
107
+ default pydantic model used by the library to present the data in
108
+ the `Response.data`. The default behaviour of the library is to
109
+ set `Response.data` to `None` if it fails to serialize the data
110
+ returned from paystack with the model provided in the library.
111
+ Providing a pydantic model class via this parameter overrides
112
+ the library default model with the model class you provide.
113
+ This can come in handy when the models in the library do not
114
+ accurately represent the data returned, and you prefer working with the
115
+ data as a pydantic model instead of as a dict of the response returned
116
+ by paystack before it is serialized with pydantic models, The original
117
+ data can be accessed via `Response.raw`.
118
+
119
+ Returns:
120
+ A pydantic model containing the response gotten from paystack's server.
121
+ """
122
+ url = self._full_url(f"/order/{id}")
123
+ return await self._handle_request( # type: ignore
124
+ HTTPMethod.GET,
125
+ url,
126
+ response_data_model_class=alternate_model_class,
127
+ )
128
+
129
+ async def get_product_orders(
130
+ self,
131
+ id: int,
132
+ alternate_model_class: type[PaystackDataModel] | None = None,
133
+ ) -> Response[PaystackDataModel]:
134
+ """Fetch all orders for a particular product
135
+
136
+ Args:
137
+ id: The id of the product you want to retrieve associated orders for.
138
+ alternate_model_class: A pydantic model class to use instead of the
139
+ default pydantic model used by the library to present the data in
140
+ the `Response.data`. The default behaviour of the library is to
141
+ set `Response.data` to `None` if it fails to serialize the data
142
+ returned from paystack with the model provided in the library.
143
+ Providing a pydantic model class via this parameter overrides
144
+ the library default model with the model class you provide.
145
+ This can come in handy when the models in the library do not
146
+ accurately represent the data returned, and you prefer working with the
147
+ data as a pydantic model instead of as a dict of the response returned
148
+ by paystack before it is serialized with pydantic models, The original
149
+ data can be accessed via `Response.raw`.
150
+
151
+ Returns:
152
+ A pydantic model containing the response gotten from paystack's server.
153
+ """
154
+ url = self._full_url(f"/order/product/{id}")
155
+ return await self._handle_request( # type: ignore
156
+ HTTPMethod.GET,
157
+ url,
158
+ response_data_model_class=alternate_model_class,
159
+ )
160
+
161
+ async def validate(
162
+ self,
163
+ code: str,
164
+ alternate_model_class: type[PaystackDataModel] | None = None,
165
+ ) -> Response[PaystackDataModel]:
166
+ """Validate a pay for me order
167
+
168
+ Args:
169
+ code: The code for the order you want to validate.
170
+ alternate_model_class: A pydantic model class to use instead of the
171
+ default pydantic model used by the library to present the data in
172
+ the `Response.data`. The default behaviour of the library is to
173
+ set `Response.data` to `None` if it fails to serialize the data
174
+ returned from paystack with the model provided in the library.
175
+ Providing a pydantic model class via this parameter overrides
176
+ the library default model with the model class you provide.
177
+ This can come in handy when the models in the library do not
178
+ accurately represent the data returned, and you prefer working with the
179
+ data as a pydantic model instead of as a dict of the response returned
180
+ by paystack before it is serialized with pydantic models, The original
181
+ data can be accessed via `Response.raw`.
182
+
183
+ Returns:
184
+ A pydantic model containing the response gotten from paystack's server.
185
+ """
186
+ url = self._full_url(f"/order/{code}/validate")
187
+ return await self._handle_request( # type: ignore
188
+ HTTPMethod.GET,
189
+ url,
190
+ response_data_model_class=alternate_model_class,
191
+ )
@@ -34,6 +34,7 @@ class AsyncPaymentRequestClient(BaseAsyncAPIClient):
34
34
  has_invoice: bool | None = None,
35
35
  invoice_number: int | None = None,
36
36
  split_code: str | None = None,
37
+ metadata: dict[str, Any] | None = None,
37
38
  alternate_model_class: type[PaystackDataModel] | None = None,
38
39
  ) -> Response[PaymentRequest] | Response[PaystackDataModel]:
39
40
  """Create a payment request for a transaction on your integration
@@ -54,6 +55,7 @@ class AsyncPaymentRequestClient(BaseAsyncAPIClient):
54
55
  This field is to help override whatever value Paystack decides. Auto increment for
55
56
  subsequent invoices continue from this point.
56
57
  split_code: The split code of the transaction split. e.g. SPL_98WF13Eb3w
58
+ metadata: Additional informations to the request
57
59
  alternate_model_class: A pydantic model class to use instead of the
58
60
  default pydantic model used by the library to present the data in
59
61
  the `Response.data`. The default behaviour of the library is to
@@ -91,6 +93,7 @@ class AsyncPaymentRequestClient(BaseAsyncAPIClient):
91
93
  ("has_invoice", has_invoice),
92
94
  ("invoice_number", invoice_number),
93
95
  ("split_code", split_code),
96
+ ("metadata", metadata),
94
97
  ]
95
98
  payload = add_to_payload(optional_params, payload)
96
99
  return await self._handle_request( # type: ignore
@@ -336,6 +339,7 @@ class AsyncPaymentRequestClient(BaseAsyncAPIClient):
336
339
  draft: bool | None = None,
337
340
  invoice_number: int | None = None,
338
341
  split_code: str | None = None,
342
+ metadata: dict[str, Any] | None = None,
339
343
  alternate_model_class: type[PaystackDataModel] | None = None,
340
344
  ) -> Response[PaymentRequest] | Response[PaystackDataModel]:
341
345
  """Update a payment request details on your integration
@@ -356,6 +360,7 @@ class AsyncPaymentRequestClient(BaseAsyncAPIClient):
356
360
  This field is to help override whatever value Paystack decides. Auto increment for
357
361
  subsequent invoices continue from this point.
358
362
  split_code: The split code of the transaction split. e.g. SPL_98WF13Eb3w
363
+ metadata: Additional informations to the request
359
364
  alternate_model_class: A pydantic model class to use instead of the
360
365
  default pydantic model used by the library to present the data in
361
366
  the `Response.data`. The default behaviour of the library is to
@@ -395,6 +400,7 @@ class AsyncPaymentRequestClient(BaseAsyncAPIClient):
395
400
  ("draft", draft),
396
401
  ("invoice_number", invoice_number),
397
402
  ("split_code", split_code),
403
+ ("metadata", metadata),
398
404
  ]
399
405
  payload = add_to_payload(optional_params, payload)
400
406
  return await self._handle_request( # type: ignore