Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for adjustment type and VND currency #83

Merged
merged 2 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.2 - 2024-12-17

### 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.2",
"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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

items cannot be set to Undefined() by default without moving the argument, which would be a breaking change.

CreateAdjustment.full() and CreateAdjustment.partial() have been introduced to make it easier to create this operation, e.g.

CreateAdjustment.partial(
    Action.Refund,
    [CreateAdjustmentItem("txnitm_01h8bxryv3065dyh6103p3yg28", AdjustmentType.Partial, "100")],
    "error",
    "txn_01h8bxpvx398a7zbawb77y0kp5",
)
CreateAdjustment.full(
    Action.Refund,
    "error",
    "txn_01h8bxpvx398a7zbawb77y0kp5",
)

The constructor can still be used, but items must always be provided, e.g.

CreateAdjustment(
    Action.Refund,
    None,
    "error",
    "txn_01h8bxpvx398a7zbawb77y0kp5",
    AdjustmentActionType.Full,
)
CreateAdjustment(
    Action.Refund,
    Undefined(),
    "error",
    "txn_01h8bxpvx398a7zbawb77y0kp5",
    AdjustmentActionType.Full,
)

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.2",
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,7 @@
{
"action": "refund",
"type": "full",
"items": null,
"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
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 All @@ -15,6 +15,8 @@
)
from paddle_billing.Resources.Shared.Operations import Pager

from paddle_billing.Undefined import Undefined

from tests.Utils.ReadsFixture import ReadsFixtures


Expand Down Expand Up @@ -49,10 +51,77 @@ 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",
),
(
CreateAdjustment(
Action.Refund,
None,
"error",
"txn_01h8bxpvx398a7zbawb77y0kp5",
AdjustmentActionType.Full,
),
ReadsFixtures.read_raw_json_fixture("request/create_type_full_with_null_items"),
200,
ReadsFixtures.read_raw_json_fixture("response/minimal_entity"),
"/adjustments",
),
(
CreateAdjustment(
Action.Refund,
Undefined(),
"error",
"txn_01h8bxpvx398a7zbawb77y0kp5",
AdjustmentActionType.Full,
),
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",
"Create full adjustment with None items",
"Create full adjustment with Undefined items",
],
)
def test_create_adjustment_uses_expected_payload(
Expand Down
Loading
Loading