Skip to content

Commit 606f9fe

Browse files
author
Riyaz Panjwani
committed
Add Advanced Commerce objects
1 parent 250fd58 commit 606f9fe

53 files changed

Lines changed: 1648 additions & 8 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright (c) 2025 Apple Inc. Licensed under MIT License.
2+
3+
from abc import ABC, abstractmethod
4+
from typing import Optional
5+
from attr import define
6+
import attr
7+
from .AdvancedCommerceRequest import AdvancedCommerceRequest
8+
from .AdvancedCommerceRequestInfo import AdvancedCommerceRequestInfo
9+
10+
11+
@define
12+
class AbstractAdvancedCommerceInAppRequest(AdvancedCommerceRequest, ABC):
13+
"""
14+
Abstract base class for Advanced Commerce in-app requests.
15+
"""
16+
17+
operation: str = attr.field()
18+
version: str = attr.field()
19+
20+
def __init__(self, operation: str, version: str, requestInfo: AdvancedCommerceRequestInfo):
21+
super().__init__(requestInfo)
22+
self.operation = operation
23+
self.version = version
24+
25+
@abstractmethod
26+
def self(self):
27+
"""Return self for method chaining."""
28+
pass
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright (c) 2023 Apple Inc. Licensed under MIT License.
2+
3+
from abc import ABC, abstractmethod
4+
from typing import Dict, Any, Optional
5+
from attr import define
6+
import attr
7+
8+
9+
@define
10+
class AbstractAdvancedCommerceItem(ABC):
11+
"""
12+
Abstract base class for Advanced Commerce items.
13+
"""
14+
15+
sku: str = attr.field()
16+
description: str = attr.field()
17+
displayName: str = attr.field()
18+
unknownFields: Optional[Dict[str, Any]] = attr.field(default=None)
19+
20+
MAXIMUM_DESCRIPTION_LENGTH = 45
21+
MAXIMUM_DISPLAY_NAME_LENGTH = 30
22+
MAXIMUM_SKU_LENGTH = 128
23+
24+
@sku.validator
25+
def _validate_sku(self, attribute, value):
26+
if value is not None and len(value) > self.MAXIMUM_SKU_LENGTH:
27+
raise ValueError("sku length longer than maximum allowed")
28+
29+
@description.validator
30+
def _validate_description(self, attribute, value):
31+
if value is not None and len(value) > self.MAXIMUM_DESCRIPTION_LENGTH:
32+
raise ValueError("description length longer than maximum allowed")
33+
34+
@displayName.validator
35+
def _validate_display_name(self, attribute, value):
36+
if value is not None and len(value) > self.MAXIMUM_DISPLAY_NAME_LENGTH:
37+
raise ValueError("displayName length longer than maximum allowed")
38+
39+
@abstractmethod
40+
def self(self):
41+
"""Return self for method chaining."""
42+
pass
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) 2025 Apple Inc. Licensed under MIT License.
2+
3+
from typing import Optional
4+
from attr import define
5+
import attr
6+
7+
8+
@define
9+
class AbstractAdvancedCommerceResponse:
10+
"""
11+
Abstract base class for Advanced Commerce responses.
12+
"""
13+
14+
signedRenewalInfo: Optional[str] = attr.field(default=None)
15+
signedTransactionInfo: Optional[str] = attr.field(default=None)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright (c) 2025 Apple Inc. Licensed under MIT License.
2+
3+
from typing import Dict, Any, Optional
4+
5+
from attr import define
6+
import attr
7+
8+
@define
9+
class AdvancedCommerceDescriptors:
10+
"""
11+
The description and display name of the subscription to migrate to that you manage.
12+
"""
13+
14+
# Maximum field lengths from Java implementation
15+
MAXIMUM_DESCRIPTION_LENGTH = 45
16+
MAXIMUM_DISPLAY_NAME_LENGTH = 30
17+
18+
description: Optional[str] = attr.ib(default=None)
19+
display_name: Optional[str] = attr.ib(default=None)
20+
unknown_fields: Optional[Dict[str, Any]] = attr.ib(default=None)
21+
22+
def __attrs_post_init__(self):
23+
if self.description is not None:
24+
self.description = self._validate_description(self.description)
25+
if self.display_name is not None:
26+
self.display_name = self._validate_display_name(self.display_name)
27+
28+
def _validate_description(self, description: str) -> str:
29+
"""Validate description field."""
30+
if description is None:
31+
raise ValueError("Description cannot be None")
32+
if len(description) > self.MAXIMUM_DESCRIPTION_LENGTH:
33+
raise ValueError("Description length longer than maximum allowed")
34+
return description
35+
36+
def _validate_display_name(self, display_name: str) -> str:
37+
"""Validate display name field."""
38+
if display_name is None:
39+
raise ValueError("Display name cannot be None")
40+
if len(display_name) > self.MAXIMUM_DISPLAY_NAME_LENGTH:
41+
raise ValueError("Display name length longer than maximum allowed")
42+
return display_name
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright (c) 2025 Apple Inc. Licensed under MIT License.
2+
3+
from enum import Enum
4+
5+
from .LibraryUtility import AppStoreServerLibraryEnumMeta
6+
7+
class AdvancedCommerceEffective(str, Enum, metaclass=AppStoreServerLibraryEnumMeta):
8+
"""
9+
A string value that indicates when a requested change to an auto-renewable subscription goes into effect.
10+
11+
https://developer.apple.com/documentation/advancedcommerceapi/effective
12+
"""
13+
IMMEDIATELY = "IMMEDIATELY"
14+
NEXT_BILL_CYCLE = "NEXT_BILL_CYCLE"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright (c) 2025 Apple Inc. Licensed under MIT License.
2+
3+
from typing import Dict, Any, Optional
4+
5+
from attr import define
6+
import attr
7+
8+
from .LibraryUtility import AttrsRawValueAware, AppStoreServerLibraryEnumMeta
9+
from .AdvancedCommerceOfferPeriod import AdvancedCommerceOfferPeriod
10+
from .AdvancedCommerceOfferReason import AdvancedCommerceOfferReason
11+
12+
@define
13+
class AdvancedCommerceOffer(AttrsRawValueAware):
14+
"""
15+
A discount offer for an auto-renewable subscription.
16+
17+
https://developer.apple.com/documentation/advancedcommerceapi/offer
18+
"""
19+
20+
period: Optional[AdvancedCommerceOfferPeriod] = AdvancedCommerceOfferPeriod.create_main_attr("rawPeriod")
21+
raw_period: Optional[str] = AdvancedCommerceOfferPeriod.create_raw_attr("period")
22+
23+
period_count: Optional[int] = attr.ib(default=None)
24+
price: Optional[int] = attr.ib(default=None)
25+
26+
reason: Optional[AdvancedCommerceOfferReason] = AdvancedCommerceOfferReason.create_main_attr("rawReason")
27+
raw_reason: Optional[str] = AdvancedCommerceOfferReason.create_raw_attr("reason")
28+
29+
unknown_fields: Optional[Dict[str, Any]] = attr.ib(default=None)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright (c) 2025 Apple Inc. Licensed under MIT License.
2+
3+
from enum import Enum
4+
5+
from .LibraryUtility import AppStoreServerLibraryEnumMeta
6+
7+
class AdvancedCommerceOfferPeriod(str, Enum, metaclass=AppStoreServerLibraryEnumMeta):
8+
"""
9+
The period of the offer.
10+
11+
https://developer.apple.com/documentation/advancedcommerceapi/offer
12+
"""
13+
P3D = "P3D"
14+
P1W = "P1W"
15+
P2W = "P2W"
16+
P1M = "P1M"
17+
P2M = "P2M"
18+
P3M = "P3M"
19+
P6M = "P6M"
20+
P9M = "P9M"
21+
P1Y = "P1Y"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) 2025 Apple Inc. Licensed under MIT License.
2+
3+
from enum import Enum
4+
5+
from .LibraryUtility import AppStoreServerLibraryEnumMeta
6+
7+
class AdvancedCommerceOfferReason(str, Enum, metaclass=AppStoreServerLibraryEnumMeta):
8+
"""
9+
The reason for the offer.
10+
11+
https://developer.apple.com/documentation/advancedcommerceapi/offer
12+
"""
13+
ACQUISITION = "ACQUISITION"
14+
WIN_BACK = "WIN_BACK"
15+
RETENTION = "RETENTION"
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright (c) 2025 Apple Inc. Licensed under MIT License.
2+
3+
from typing import Optional
4+
5+
from attr import define
6+
import attr
7+
8+
from .AbstractAdvancedCommerceInAppRequest import AbstractAdvancedCommerceInAppRequest
9+
from .AdvancedCommerceOneTimeChargeItem import AdvancedCommerceOneTimeChargeItem
10+
from .AdvancedCommerceRequestInfo import AdvancedCommerceRequestInfo
11+
from .AdvancedCommerceValidationUtils import AdvancedCommerceValidationUtils
12+
13+
@define
14+
class AdvancedCommerceOneTimeChargeCreateRequest(AbstractAdvancedCommerceInAppRequest):
15+
"""
16+
The request data your app provides when a customer purchases a one-time-charge product.
17+
18+
https://developer.apple.com/documentation/advancedcommerceapi/onetimechargecreaterequest
19+
"""
20+
21+
OPERATION = "CREATE_ONE_TIME_CHARGE"
22+
VERSION = "1"
23+
24+
currency: str = attr.ib()
25+
item: AdvancedCommerceOneTimeChargeItem = attr.ib()
26+
tax_code: str = attr.ib()
27+
storefront: Optional[str] = attr.ib(default=None)
28+
29+
def __attrs_post_init__(self):
30+
super().__attrs_post_init__()
31+
# Set the operation and version from constants
32+
object.__setattr__(self, 'operation', self.OPERATION)
33+
object.__setattr__(self, 'version', self.VERSION)
34+
35+
# Validate fields
36+
self.currency = AdvancedCommerceValidationUtils.validate_currency(self.currency)
37+
self.tax_code = AdvancedCommerceValidationUtils.validate_tax_code(self.tax_code)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright (c) 2025 Apple Inc. Licensed under MIT License.
2+
3+
from typing import Optional
4+
5+
from attr import define
6+
import attr
7+
8+
from .AbstractAdvancedCommerceItem import AbstractAdvancedCommerceItem
9+
10+
@define
11+
class AdvancedCommerceOneTimeChargeItem(AbstractAdvancedCommerceItem):
12+
"""
13+
The details of a one-time charge product, including its display name, price, SKU, and metadata.
14+
15+
https://developer.apple.com/documentation/advancedcommerceapi/onetimechargeitem
16+
"""
17+
18+
price: Optional[int] = attr.ib(default=None)
19+
20+
def __attrs_post_init__(self):
21+
super().__attrs_post_init__()
22+
if self.price is not None:
23+
self.price = self._validate_price(self.price)
24+
25+
def _validate_price(self, price: int) -> int:
26+
"""
27+
Validate price field.
28+
29+
Args:
30+
price: The price to validate
31+
32+
Returns:
33+
The validated price
34+
35+
Raises:
36+
ValueError: If price is invalid
37+
"""
38+
if price is None:
39+
raise ValueError("Price cannot be None")
40+
if price < 0:
41+
raise ValueError("Price cannot be negative")
42+
return price

0 commit comments

Comments
 (0)