Skip to content

Commit

Permalink
feat: Add support for adjustment type and VND currency
Browse files Browse the repository at this point in the history
  • Loading branch information
davidgrayston-paddle committed Dec 17, 2024
1 parent d4e881a commit b62008b
Show file tree
Hide file tree
Showing 19 changed files with 190 additions and 5 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

Check our main [developer changelog](https://developer.paddle.com/?utm_source=dx&utm_medium=paddle-python-sdk) for information about changes to the Paddle Billing platform, the Paddle API, and other developer tools.

## 1.3.0 - 2024-12-17

### Added

- Support for adjustment type, see [related changelog](https://developer.paddle.com/changelog/2024/refund-credit-full-total?utm_source=dx&utm_medium=paddle-python-sdk)
- Added Vietnamese Dong (`VND`) as a supported currency for payments [related changelog](https://developer.paddle.com/changelog/2024/vietnamese-dong-vnd-supported-currency?utm_source=dx&utm_medium=paddle-python-sdk)

## 1.2.1 - 2024-12-04

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion paddle_billing/Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def build_request_session(self) -> Session:
"Authorization": f"Bearer {self.__api_key}",
"Content-Type": "application/json",
"Paddle-Version": str(self.use_api_version),
"User-Agent": "PaddleSDK/python 1.2.1",
"User-Agent": "PaddleSDK/python 1.3.0",
}
)

Expand Down
3 changes: 3 additions & 0 deletions paddle_billing/Entities/Adjustment.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from paddle_billing.Entities.Adjustments import AdjustmentItem, AdjustmentTaxRatesUsed
from paddle_billing.Entities.Shared import (
Action,
AdjustmentActionType,
AdjustmentStatus,
CurrencyCode,
PayoutTotalsAdjustment,
Expand All @@ -30,6 +31,7 @@ class Adjustment(Entity):
created_at: datetime
updated_at: datetime | None
tax_rates_used: list[AdjustmentTaxRatesUsed]
type: AdjustmentActionType

@staticmethod
def from_dict(data: dict) -> Adjustment:
Expand All @@ -51,4 +53,5 @@ def from_dict(data: dict) -> Adjustment:
),
updated_at=datetime.fromisoformat(data["updated_at"]) if data.get("updated_at") else None,
tax_rates_used=[AdjustmentTaxRatesUsed.from_dict(item) for item in data["tax_rates_used"]],
type=AdjustmentStatus(data["type"]),
)
6 changes: 6 additions & 0 deletions paddle_billing/Entities/Shared/AdjustmentActionType.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta


class AdjustmentActionType(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
Full: "AdjustmentActionType" = "full"
Partial: "AdjustmentActionType" = "partial"
1 change: 1 addition & 0 deletions paddle_billing/Entities/Shared/CurrencyCode.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ class CurrencyCode(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
TRY: "CurrencyCode" = "TRY"
TWD: "CurrencyCode" = "TWD"
UAH: "CurrencyCode" = "UAH"
VND: "CurrencyCode" = "VND"
ZAR: "CurrencyCode" = "ZAR"
1 change: 1 addition & 0 deletions paddle_billing/Entities/Shared/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from paddle_billing.Entities.Shared.Action import Action
from paddle_billing.Entities.Shared.AddressPreview import AddressPreview
from paddle_billing.Entities.Shared.AdjustmentActionType import AdjustmentActionType
from paddle_billing.Entities.Shared.AdjustmentItemTotals import AdjustmentItemTotals
from paddle_billing.Entities.Shared.AdjustmentStatus import AdjustmentStatus
from paddle_billing.Entities.Shared.AdjustmentTotals import AdjustmentTotals
Expand Down
3 changes: 3 additions & 0 deletions paddle_billing/Notifications/Entities/Adjustment.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from paddle_billing.Notifications.Entities.Entity import Entity
from paddle_billing.Notifications.Entities.Shared import (
Action,
AdjustmentActionType,
AdjustmentStatus,
CurrencyCode,
PayoutTotalsAdjustment,
Expand All @@ -30,6 +31,7 @@ class Adjustment(Entity):
created_at: datetime
updated_at: datetime | None
tax_rates_used: list[AdjustmentTaxRatesUsed] | None
type: AdjustmentActionType | None

@staticmethod
def from_dict(data: dict) -> Adjustment:
Expand All @@ -55,4 +57,5 @@ def from_dict(data: dict) -> Adjustment:
if data.get("tax_rates_used")
else None
),
type=AdjustmentActionType(data["type"]) if data.get("type") else None,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta


class AdjustmentActionType(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
Full: "AdjustmentActionType" = "full"
Partial: "AdjustmentActionType" = "partial"
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ class CurrencyCode(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
TRY: "CurrencyCode" = "TRY"
TWD: "CurrencyCode" = "TWD"
UAH: "CurrencyCode" = "UAH"
VND: "CurrencyCode" = "VND"
ZAR: "CurrencyCode" = "ZAR"
1 change: 1 addition & 0 deletions paddle_billing/Notifications/Entities/Shared/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from paddle_billing.Notifications.Entities.Shared.Action import Action
from paddle_billing.Notifications.Entities.Shared.AddressPreview import AddressPreview
from paddle_billing.Notifications.Entities.Shared.AdjustmentActionType import AdjustmentActionType
from paddle_billing.Notifications.Entities.Shared.AdjustmentItemTotals import AdjustmentItemTotals
from paddle_billing.Notifications.Entities.Shared.AdjustmentStatus import AdjustmentStatus
from paddle_billing.Notifications.Entities.Shared.AdjustmentTotals import AdjustmentTotals
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,58 @@
from dataclasses import dataclass

from paddle_billing.Undefined import Undefined

from paddle_billing.Operation import Operation

from paddle_billing.Entities.Shared import Action
from paddle_billing.Entities.Shared import Action, AdjustmentActionType

from paddle_billing.Resources.Adjustments.Operations import CreateAdjustmentItem

from paddle_billing.Exceptions.SdkExceptions.InvalidArgumentException import InvalidArgumentException


@dataclass
class CreateAdjustment(Operation):
action: Action
items: list[CreateAdjustmentItem]
items: list[CreateAdjustmentItem] | None | Undefined
reason: str
transaction_id: str
type: AdjustmentActionType | Undefined = Undefined()

def __post_init__(self):
if self.type != AdjustmentActionType.Full and (
self.items is None or isinstance(self.items, Undefined) or len(self.items) == 0
):
raise InvalidArgumentException.array_is_empty("items")

if self.type == AdjustmentActionType.Full and isinstance(self.items, list):
raise InvalidArgumentException("items are not allowed when the adjustment type is full")

@staticmethod
def full(
action: Action,
reason: str,
transaction_id: str,
) -> "CreateAdjustment":
return CreateAdjustment(
action=action,
reason=reason,
transaction_id=transaction_id,
items=Undefined(),
type=AdjustmentActionType.Full,
)

@staticmethod
def partial(
action: Action,
items: list[CreateAdjustmentItem],
reason: str,
transaction_id: str,
) -> "CreateAdjustment":
return CreateAdjustment(
action=action,
reason=reason,
transaction_id=transaction_id,
items=items,
type=AdjustmentActionType.Partial,
)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


setup(
version="1.2.1",
version="1.3.0",
author="Paddle and contributors",
author_email="[email protected]",
description="Paddle's Python SDK for Paddle Billing",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"action": "refund",
"type": "full",
"reason": "error",
"transaction_id": "txn_01h8bxpvx398a7zbawb77y0kp5"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"action": "refund",
"type": "partial",
"items": [
{
"item_id": "txnitm_01h8bxryv3065dyh6103p3yg28",
"type": "partial",
"amount": "100"
}
],
"reason": "error",
"transaction_id": "txn_01h8bxpvx398a7zbawb77y0kp5"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"data": {
"id": "adj_01h8c65c2ggq5nxswnnwv78e75",
"action": "refund",
"type": "partial",
"transaction_id": "txn_01h8bxpvx398a7zbawb77y0kp5",
"subscription_id": "sub_01h8bxswamxysj44zt5n48njwh",
"customer_id": "ctm_01h8441jn5pcwrfhwh78jqt8hk",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
{
"id": "adj_01h8c65c2ggq5nxswnnwv78e75",
"action": "refund",
"type": "partial",
"transaction_id": "txn_01h8bxpvx398a7zbawb77y0kp5",
"subscription_id": "sub_01h8bxswamxysj44zt5n48njwh",
"customer_id": "ctm_01h8441jn5pcwrfhwh78jqt8hk",
Expand Down Expand Up @@ -55,6 +56,7 @@
{
"id": "adj_01h8bxezh16gm6t8rx21dx271b",
"action": "credit",
"type": "partial",
"credit_applied_to_balance": true,
"transaction_id": "txn_01h8bx69629a16wwm9z8rjmak3",
"subscription_id": "sub_01h8bx8fmywym11t6swgzba704",
Expand Down Expand Up @@ -114,6 +116,7 @@
{
"id": "adj_01h7jgzjqt2s8sab70e03ptkhv",
"action": "credit",
"type": "partial",
"credit_applied_to_balance": true,
"transaction_id": "txn_01h7jgd9bkwjscj3ae15g5d3vs",
"subscription_id": "sub_01h7ht5z5wdg9pz18jx1fagp8k",
Expand Down Expand Up @@ -173,6 +176,7 @@
{
"id": "adj_01h7jf6ptkfsc93hzc20fgf8wy",
"action": "credit",
"type": "partial",
"credit_applied_to_balance": true,
"transaction_id": "txn_01h7je77vc1qmzxntem45ebb5q",
"subscription_id": "sub_01h7ht5z5wdg9pz18jx1fagp8k",
Expand Down Expand Up @@ -232,6 +236,7 @@
{
"id": "adj_01h468w41ttb2j2bh8av74gwt1",
"action": "credit",
"type": "partial",
"credit_applied_to_balance": true,
"transaction_id": "txn_01h468crc3b3fe98a5ft53recb",
"subscription_id": "sub_01h468kv3jhs5jk330gszncsgt",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"data": {
"id": "adj_01h8c65c2ggq5nxswnnwv78e75",
"action": "refund",
"type": "partial",
"transaction_id": "txn_01h8bxpvx398a7zbawb77y0kp5",
"subscription_id": "sub_01h8bxswamxysj44zt5n48njwh",
"customer_id": "ctm_01h8441jn5pcwrfhwh78jqt8hk",
Expand Down
41 changes: 40 additions & 1 deletion tests/Functional/Resources/Adjustments/test_AdjustmentsClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from paddle_billing.Entities.Adjustment import Adjustment, AdjustmentTaxRatesUsed
from paddle_billing.Entities.Collections import AdjustmentCollection
from paddle_billing.Entities.AdjustmentCreditNote import AdjustmentCreditNote
from paddle_billing.Entities.Shared import Action, AdjustmentStatus, AdjustmentType, Disposition
from paddle_billing.Entities.Shared import Action, AdjustmentActionType, AdjustmentStatus, AdjustmentType, Disposition

from paddle_billing.Resources.Adjustments.Operations import (
CreateAdjustment,
Expand Down Expand Up @@ -49,10 +49,49 @@ class TestAdjustmentsClient:
ReadsFixtures.read_raw_json_fixture("response/full_entity"),
"/adjustments",
),
(
CreateAdjustment(
Action.Refund,
[CreateAdjustmentItem("txnitm_01h8bxryv3065dyh6103p3yg28", AdjustmentType.Partial, "100")],
"error",
"txn_01h8bxpvx398a7zbawb77y0kp5",
AdjustmentActionType.Partial,
),
ReadsFixtures.read_raw_json_fixture("request/create_type_partial_with_items"),
200,
ReadsFixtures.read_raw_json_fixture("response/minimal_entity"),
"/adjustments",
),
(
CreateAdjustment.partial(
Action.Refund,
[CreateAdjustmentItem("txnitm_01h8bxryv3065dyh6103p3yg28", AdjustmentType.Partial, "100")],
"error",
"txn_01h8bxpvx398a7zbawb77y0kp5",
),
ReadsFixtures.read_raw_json_fixture("request/create_type_partial_with_items"),
200,
ReadsFixtures.read_raw_json_fixture("response/minimal_entity"),
"/adjustments",
),
(
CreateAdjustment.full(
Action.Refund,
"error",
"txn_01h8bxpvx398a7zbawb77y0kp5",
),
ReadsFixtures.read_raw_json_fixture("request/create_type_full_with_no_items"),
200,
ReadsFixtures.read_raw_json_fixture("response/minimal_entity"),
"/adjustments",
),
],
ids=[
"Create adjustment with basic data",
"Create adjustment with full data",
"Create adjustment with basic data with type",
"Create partial adjustment with items",
"Create full adjustment with no items",
],
)
def test_create_adjustment_uses_expected_payload(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from pytest import mark, raises

from paddle_billing.Undefined import Undefined
from paddle_billing.Entities.Shared import Action, AdjustmentActionType
from paddle_billing.Resources.Adjustments.Operations import CreateAdjustment
from paddle_billing.Exceptions.SdkExceptions.InvalidArgumentException import InvalidArgumentException


class TestCreateAdjustment:
@mark.parametrize(
"items",
[
(None),
(Undefined()),
],
ids=[
"Full type with None items",
"Full type with undefined items",
],
)
def test_does_not_raise_invalid_argument_exception_for_full_type_with_empty_items(
self,
items,
):
operation = CreateAdjustment(
Action.Refund, items, "error", "txn_01h8bxpvx398a7zbawb77y0kp5", AdjustmentActionType.Full
)

assert operation.items == items

@mark.parametrize(
"items, type, expected_message",
[
([], AdjustmentActionType.Full, "items are not allowed when the adjustment type is full"),
([], AdjustmentActionType.Partial, "'items' cannot be empty"),
([], Undefined(), "'items' cannot be empty"),
],
ids=[
"Full type with items",
"Partial type with empty items",
"Undefined type with empty items",
],
)
def test_raises_invalid_argument_exception(self, items, type, expected_message):
with raises(InvalidArgumentException) as exception_info:
CreateAdjustment(Action.Refund, items, "error", "txn_01h8bxpvx398a7zbawb77y0kp5", type)

assert str(exception_info.value) == expected_message

0 comments on commit b62008b

Please sign in to comment.