Browse Source

Add new store fields and separate types

pull/10109/head
dolfies 1 year ago
parent
commit
c507bc2524
  1. 15
      discord/enums.py
  2. 17
      discord/flags.py
  3. 24
      discord/http.py
  4. 74
      discord/store.py
  5. 19
      discord/subscriptions.py
  6. 6
      discord/types/entitlements.py
  7. 4
      discord/types/payments.py
  8. 69
      discord/types/store.py
  9. 3
      discord/types/subscriptions.py
  10. 6
      docs/api.rst

15
discord/enums.py

@ -107,6 +107,7 @@ __all__ = (
'ApplicationAssetType', 'ApplicationAssetType',
'SKUType', 'SKUType',
'SKUAccessLevel', 'SKUAccessLevel',
'SKUProductLine',
'SKUFeature', 'SKUFeature',
'SKUGenre', 'SKUGenre',
'OperatingSystem', 'OperatingSystem',
@ -1188,6 +1189,7 @@ class PaymentSourceType(Enum):
bancontact = 14 bancontact = 14
eps = 15 eps = 15
ideal = 16 ideal = 16
cash_app = 17
payment_request = 99 payment_request = 99
@ -1290,6 +1292,19 @@ class SKUAccessLevel(Enum, comparable=True):
return self.value return self.value
class SKUProductLine(Enum):
premium = 1
guild_premium = 2
iap = 3
guild_role = 4
guild_product = 5
application = 6
collectible = 7
def __int__(self) -> int:
return self.value
class SKUFeature(Enum): class SKUFeature(Enum):
single_player = 1 single_player = 1
online_multiplayer = 2 online_multiplayer = 2

17
discord/flags.py

@ -1591,6 +1591,23 @@ class SKUFlags(BaseFlags):
""":class:`bool`: Returns ``True`` if the SKU is a application subscription. These are subscriptions made to applications for premium perks bound to a user.""" """:class:`bool`: Returns ``True`` if the SKU is a application subscription. These are subscriptions made to applications for premium perks bound to a user."""
return 1 << 8 return 1 << 8
@flag_value
def creator_monetization(self):
""":class:`bool`: Returns ``True`` if the SKU is a creator monetization product (e.g. guild role subscription, guild product).
.. versionadded:: 2.1
"""
# For some reason this is only actually present on products...
return 1 << 9
@flag_value
def guild_product(self):
""":class:`bool`: Returns ``True`` if the SKU is a guild product. These are one-time purchases made by guilds for premium perks.
.. versionadded:: 2.1
"""
return 1 << 10
@fill_with_flags() @fill_with_flags()
class PaymentFlags(BaseFlags): class PaymentFlags(BaseFlags):

24
discord/http.py

@ -3090,7 +3090,7 @@ class HTTPClient:
payment_source_id: Optional[Snowflake] = None, payment_source_id: Optional[Snowflake] = None,
localize: bool = True, localize: bool = True,
with_bundled_skus: bool = True, with_bundled_skus: bool = True,
) -> Response[List[store.SKU]]: ) -> Response[List[store.PrivateSKU]]:
params = {} params = {}
if country_code: if country_code:
params['country_code'] = country_code params['country_code'] = country_code
@ -3105,7 +3105,7 @@ class HTTPClient:
Route('GET', '/applications/{app_id}/skus', app_id=app_id), params=params, super_properties_to_track=True Route('GET', '/applications/{app_id}/skus', app_id=app_id), params=params, super_properties_to_track=True
) )
def create_sku(self, payload: dict) -> Response[store.SKU]: def create_sku(self, payload: dict) -> Response[store.PrivateSKU]:
return self.request(Route('POST', '/store/skus'), json=payload, super_properties_to_track=True) return self.request(Route('POST', '/store/skus'), json=payload, super_properties_to_track=True)
def get_app_discoverability(self, app_id: Snowflake) -> Response[application.ApplicationDiscoverability]: def get_app_discoverability(self, app_id: Snowflake) -> Response[application.ApplicationDiscoverability]:
@ -3507,7 +3507,7 @@ class HTTPClient:
country_code: Optional[str] = None, country_code: Optional[str] = None,
payment_source_id: Optional[Snowflake] = None, payment_source_id: Optional[Snowflake] = None,
localize: bool = True, localize: bool = True,
) -> Response[store.StoreListing]: ) -> Response[store.PrivateStoreListing]:
params = {} params = {}
if country_code: if country_code:
params['country_code'] = country_code params['country_code'] = country_code
@ -3525,7 +3525,7 @@ class HTTPClient:
country_code: Optional[str] = None, country_code: Optional[str] = None,
payment_source_id: Optional[Snowflake] = None, payment_source_id: Optional[Snowflake] = None,
localize: bool = True, localize: bool = True,
) -> Response[store.StoreListing]: ) -> Response[store.PublicStoreListing]:
params = {} params = {}
if country_code: if country_code:
params['country_code'] = country_code params['country_code'] = country_code
@ -3543,7 +3543,7 @@ class HTTPClient:
country_code: Optional[str] = None, country_code: Optional[str] = None,
payment_source_id: Optional[int] = None, payment_source_id: Optional[int] = None,
localize: bool = True, localize: bool = True,
) -> Response[List[store.StoreListing]]: ) -> Response[List[store.PrivateStoreListing]]:
params = {} params = {}
if country_code: if country_code:
params['country_code'] = country_code params['country_code'] = country_code
@ -3603,7 +3603,7 @@ class HTTPClient:
country_code: Optional[str] = None, country_code: Optional[str] = None,
payment_source_id: Optional[int] = None, payment_source_id: Optional[int] = None,
localize: bool = True, localize: bool = True,
) -> Response[List[store.StoreListing]]: ) -> Response[List[store.PublicStoreListing]]:
params = {'application_id': app_id} params = {'application_id': app_id}
if country_code: if country_code:
params['country_code'] = country_code params['country_code'] = country_code
@ -3621,7 +3621,7 @@ class HTTPClient:
country_code: Optional[str] = None, country_code: Optional[str] = None,
payment_source_id: Optional[int] = None, payment_source_id: Optional[int] = None,
localize: bool = True, localize: bool = True,
) -> Response[store.StoreListing]: ) -> Response[store.PublicStoreListing]:
params = {} params = {}
if country_code: if country_code:
params['country_code'] = country_code params['country_code'] = country_code
@ -3641,7 +3641,7 @@ class HTTPClient:
country_code: Optional[str] = None, country_code: Optional[str] = None,
payment_source_id: Optional[Snowflake] = None, payment_source_id: Optional[Snowflake] = None,
localize: bool = True, localize: bool = True,
) -> Response[List[store.StoreListing]]: ) -> Response[List[store.PublicStoreListing]]:
params: Dict[str, Any] = {'application_ids': app_ids} params: Dict[str, Any] = {'application_ids': app_ids}
if country_code: if country_code:
params['country_code'] = country_code params['country_code'] = country_code
@ -3654,14 +3654,14 @@ class HTTPClient:
def create_store_listing( def create_store_listing(
self, application_id: Snowflake, sku_id: Snowflake, payload: dict self, application_id: Snowflake, sku_id: Snowflake, payload: dict
) -> Response[store.StoreListing]: ) -> Response[store.PrivateStoreListing]:
return self.request( return self.request(
Route('POST', '/store/listings'), Route('POST', '/store/listings'),
json={**payload, 'application_id': application_id, 'sku_id': sku_id}, json={**payload, 'application_id': application_id, 'sku_id': sku_id},
super_properties_to_track=True, super_properties_to_track=True,
) )
def edit_store_listing(self, listing_id: Snowflake, payload: dict) -> Response[store.StoreListing]: def edit_store_listing(self, listing_id: Snowflake, payload: dict) -> Response[store.PrivateStoreListing]:
return self.request( return self.request(
Route('PATCH', '/store/listings/{listing_id}', listing_id=listing_id), Route('PATCH', '/store/listings/{listing_id}', listing_id=listing_id),
json=payload, json=payload,
@ -3675,7 +3675,7 @@ class HTTPClient:
country_code: Optional[str] = None, country_code: Optional[str] = None,
payment_source_id: Optional[Snowflake] = None, payment_source_id: Optional[Snowflake] = None,
localize: bool = True, localize: bool = True,
) -> Response[store.SKU]: ) -> Response[store.PrivateSKU]:
params = {} params = {}
if country_code: if country_code:
params['country_code'] = country_code params['country_code'] = country_code
@ -3686,7 +3686,7 @@ class HTTPClient:
return self.request(Route('GET', '/store/skus/{sku_id}', sku_id=sku_id), params=params) return self.request(Route('GET', '/store/skus/{sku_id}', sku_id=sku_id), params=params)
def edit_sku(self, sku_id: Snowflake, payload: dict) -> Response[store.SKU]: def edit_sku(self, sku_id: Snowflake, payload: dict) -> Response[store.PrivateSKU]:
return self.request( return self.request(
Route('PATCH', '/store/skus/{sku_id}', sku_id=sku_id), json=payload, super_properties_to_track=True Route('PATCH', '/store/skus/{sku_id}', sku_id=sku_id), json=payload, super_properties_to_track=True
) )

74
discord/store.py

@ -41,6 +41,7 @@ from .enums import (
SKUAccessLevel, SKUAccessLevel,
SKUFeature, SKUFeature,
SKUGenre, SKUGenre,
SKUProductLine,
SKUType, SKUType,
SubscriptionInterval, SubscriptionInterval,
SubscriptionPlanPurchaseType, SubscriptionPlanPurchaseType,
@ -76,6 +77,7 @@ if TYPE_CHECKING:
SKU as SKUPayload, SKU as SKUPayload,
CarouselItem as CarouselItemPayload, CarouselItem as CarouselItemPayload,
ContentRating as ContentRatingPayload, ContentRating as ContentRatingPayload,
PremiumPrice as PremiumPricePayload,
SKUPrice as SKUPricePayload, SKUPrice as SKUPricePayload,
StoreListing as StoreListingPayload, StoreListing as StoreListingPayload,
StoreNote as StoreNotePayload, StoreNote as StoreNotePayload,
@ -330,6 +332,8 @@ class SystemRequirements:
Any extra notes on recommended requirements. Any extra notes on recommended requirements.
""" """
# I hate this class so much
if TYPE_CHECKING: if TYPE_CHECKING:
os: OperatingSystem os: OperatingSystem
minimum_ram: Optional[int] minimum_ram: Optional[int]
@ -607,6 +611,19 @@ class StoreListing(Hashable):
The guild tied to this listing, if any. The guild tied to this listing, if any.
published: :class:`bool` published: :class:`bool`
Whether the listing is published and publicly visible. Whether the listing is published and publicly visible.
published_at: Optional[:class:`datetime.datetime`]
When the listing was published, if available.
.. note::
This data is not available for all listings.
.. versionadded:: 2.1
unpublished_at: Optional[:class:`datetime.datetime`]
When the listing was last unpublished, if available.
If this is a future date, the listing will be unpublished at that time.
.. versionadded:: 2.1
staff_note: Optional[:class:`StoreNote`] staff_note: Optional[:class:`StoreNote`]
The staff note attached to this listing. The staff note attached to this listing.
assets: List[:class:`StoreAsset`] assets: List[:class:`StoreAsset`]
@ -645,6 +662,8 @@ class StoreListing(Hashable):
'entitlement_branch_id', 'entitlement_branch_id',
'guild', 'guild',
'published', 'published',
'published_at',
'unpublished_at',
'staff_note', 'staff_note',
'assets', 'assets',
'carousel_items', 'carousel_items',
@ -693,6 +712,8 @@ class StoreListing(Hashable):
self.entitlement_branch_id: Optional[int] = _get_as_snowflake(data, 'entitlement_branch_id') self.entitlement_branch_id: Optional[int] = _get_as_snowflake(data, 'entitlement_branch_id')
self.guild: Optional[Guild] = state.create_guild(data['guild']) if 'guild' in data else None self.guild: Optional[Guild] = state.create_guild(data['guild']) if 'guild' in data else None
self.published: bool = data.get('published', True) self.published: bool = data.get('published', True)
self.published_at: Optional[datetime] = parse_time(data['published_at']) if 'published_at' in data else None
self.unpublished_at: Optional[datetime] = parse_time(data['unpublished_at']) if 'unpublished_at' in data else None
self.staff_note: Optional[StoreNote] = ( self.staff_note: Optional[StoreNote] = (
StoreNote(data=data['staff_notes'], state=state) if 'staff_notes' in data else None StoreNote(data=data['staff_notes'], state=state) if 'staff_notes' in data else None
) )
@ -902,22 +923,35 @@ class SKUPrice:
The price of the SKU with discounts applied, if any. The price of the SKU with discounts applied, if any.
sale_percentage: :class:`int` sale_percentage: :class:`int`
The percentage of the price discounted, if any. The percentage of the price discounted, if any.
exponent: :class:`int`
The offset of the currency's decimal point.
For example, if the price is 1000 and the exponent is 2, the price is $10.00.
.. versionadded:: 2.1
premium: Dict[:class:`PremiumType`, :class:`SKUPrice`]
Special SKU prices for premium (Nitro) users.
.. versionadded:: 2.1
""" """
__slots__ = ('currency', 'amount', 'sale_amount', 'sale_percentage', 'premium', 'exponent') __slots__ = ('currency', 'amount', 'sale_amount', 'sale_percentage', 'exponent', 'premium')
def __init__(self, data: Union[SKUPricePayload, SubscriptionPricePayload]) -> None: def __init__(self, data: Union[SKUPricePayload, SubscriptionPricePayload]) -> None:
self.currency: str = data.get('currency', 'usd') self.currency: str = data.get('currency', 'usd')
self.amount: int = data.get('amount', 0) self.amount: int = data.get('amount', 0)
self.sale_amount: Optional[int] = data.get('sale_amount') self.sale_amount: Optional[int] = data.get('sale_amount')
self.sale_percentage: int = data.get('sale_percentage', 0) self.sale_percentage: int = data.get('sale_percentage', 0)
self.premium = data.get('premium') self.exponent: int = data.get('exponent', data.get('currency_exponent', 0))
self.exponent: Optional[int] = data.get('exponent') self.premium: Dict[PremiumType, SKUPrice] = {
try_enum(PremiumType, premium_type): SKUPrice.from_premium(self, premium_data)
for premium_type, premium_data in data.get('premium', {}).items()
}
@classmethod @classmethod
def from_private(cls, data: SKUPayload) -> SKUPrice: def from_private(cls, data: SKUPayload) -> SKUPrice:
payload: SKUPricePayload = { payload: SKUPricePayload = {
'currency': 'usd', 'currency': 'usd',
'currency_exponent': 2,
'amount': data.get('price_tier') or 0, 'amount': data.get('price_tier') or 0,
'sale_amount': data.get('sale_price_tier'), 'sale_amount': data.get('sale_price_tier'),
} }
@ -925,6 +959,17 @@ class SKUPrice:
payload['sale_percentage'] = int((1 - (payload['sale_amount'] / payload['amount'])) * 100) payload['sale_percentage'] = int((1 - (payload['sale_amount'] / payload['amount'])) * 100)
return cls(payload) return cls(payload)
@classmethod
def from_premium(cls, parent: SKUPrice, data: PremiumPricePayload) -> SKUPrice:
payload: SKUPricePayload = {
'currency': parent.currency,
'currency_exponent': parent.exponent,
'amount': parent.amount,
'sale_amount': data.get('amount'),
'sale_percentage': data.get('percentage'),
}
return cls(payload)
def __repr__(self) -> str: def __repr__(self) -> str:
return f'<SKUPrice amount={self.amount} currency={self.currency!r}>' return f'<SKUPrice amount={self.amount} currency={self.currency!r}>'
@ -939,8 +984,13 @@ class SKUPrice:
return self.sale_percentage > 0 return self.sale_percentage > 0
def is_free(self) -> bool: def is_free(self) -> bool:
""":class:`bool`: Checks whether the SKU is free.""" """:class:`bool`: Checks whether the SKU is free.
return self.amount == 0
.. versionchanged:: 2.1
This now also checks the :attr:`sale_amount` to see if the SKU is free with discounts applied.
"""
return self.sale_amount == 0 or self.amount == 0
@property @property
def discounts(self) -> int: def discounts(self) -> int:
@ -1047,6 +1097,10 @@ class SKU(Hashable):
The legal notice of the SKU localized to different languages. The legal notice of the SKU localized to different languages.
type: :class:`SKUType` type: :class:`SKUType`
The type of the SKU. The type of the SKU.
product_line: Optional[:class:`SKUProductLine`]
The product line of the SKU, if any.
.. versionadded:: 2.1
slug: :class:`str` slug: :class:`str`
The URL slug of the SKU. The URL slug of the SKU.
dependent_sku_id: Optional[:class:`int`] dependent_sku_id: Optional[:class:`int`]
@ -1098,6 +1152,10 @@ class SKU(Hashable):
Whether this SKU is restricted. Whether this SKU is restricted.
exclusive: :class:`bool` exclusive: :class:`bool`
Whether this SKU is exclusive to Discord. Whether this SKU is exclusive to Discord.
deleted: :class:`bool`
Whether this SKU has been soft-deleted.
.. versionadded:: 2.1
show_age_gate: :class:`bool` show_age_gate: :class:`bool`
Whether the client should prompt the user to verify their age. Whether the client should prompt the user to verify their age.
bundled_skus: List[:class:`SKU`] bundled_skus: List[:class:`SKU`]
@ -1116,6 +1174,7 @@ class SKU(Hashable):
'legal_notice', 'legal_notice',
'legal_notice_localizations', 'legal_notice_localizations',
'type', 'type',
'product_line',
'slug', 'slug',
'price_tier', 'price_tier',
'price_overrides', 'price_overrides',
@ -1139,6 +1198,7 @@ class SKU(Hashable):
'premium', 'premium',
'restricted', 'restricted',
'exclusive', 'exclusive',
'deleted',
'show_age_gate', 'show_age_gate',
'bundled_skus', 'bundled_skus',
'manifests', 'manifests',
@ -1179,6 +1239,9 @@ class SKU(Hashable):
self.id: int = int(data['id']) self.id: int = int(data['id'])
self.type: SKUType = try_enum(SKUType, data['type']) self.type: SKUType = try_enum(SKUType, data['type'])
self.product_line: Optional[SKUProductLine] = (
try_enum(SKUProductLine, data['product_line']) if data.get('product_line') else None
)
self.slug: str = data['slug'] self.slug: str = data['slug']
self.dependent_sku_id: Optional[int] = _get_as_snowflake(data, 'dependent_sku_id') self.dependent_sku_id: Optional[int] = _get_as_snowflake(data, 'dependent_sku_id')
self.application_id: int = int(data['application_id']) self.application_id: int = int(data['application_id'])
@ -1233,6 +1296,7 @@ class SKU(Hashable):
self.premium: bool = data.get('premium', False) self.premium: bool = data.get('premium', False)
self.restricted: bool = data.get('restricted', False) self.restricted: bool = data.get('restricted', False)
self.exclusive: bool = data.get('exclusive', False) self.exclusive: bool = data.get('exclusive', False)
self.deleted: bool = data.get('deleted', False)
self.show_age_gate: bool = data.get('show_age_gate', False) self.show_age_gate: bool = data.get('show_age_gate', False)
self.bundled_skus: List[SKU] = [ self.bundled_skus: List[SKU] = [
SKU(data=sku, state=state, application=self.application) for sku in data.get('bundled_skus', []) SKU(data=sku, state=state, application=self.application) for sku in data.get('bundled_skus', [])

19
discord/subscriptions.py

@ -201,9 +201,13 @@ class SubscriptionInvoiceItem(Hashable):
The price of the subscription plan the item represents. This does not include discounts. The price of the subscription plan the item represents. This does not include discounts.
discounts: List[:class:`SubscriptionDiscount`] discounts: List[:class:`SubscriptionDiscount`]
A list of discounts applied to the item. A list of discounts applied to the item.
metadata: :class:`Metadata`
Extra metadata about the invoice item.
.. versionadded:: 2.1
""" """
__slots__ = ('id', 'quantity', 'amount', 'proration', 'plan_id', 'plan_price', 'discounts') __slots__ = ('id', 'quantity', 'amount', 'proration', 'plan_id', 'plan_price', 'discounts', 'metadata')
def __init__(self, data: SubscriptionInvoiceItemPayload) -> None: def __init__(self, data: SubscriptionInvoiceItemPayload) -> None:
self.id: int = int(data['id']) self.id: int = int(data['id'])
@ -213,6 +217,7 @@ class SubscriptionInvoiceItem(Hashable):
self.plan_id: int = int(data['subscription_plan_id']) self.plan_id: int = int(data['subscription_plan_id'])
self.plan_price: int = data['subscription_plan_price'] self.plan_price: int = data['subscription_plan_price']
self.discounts: List[SubscriptionDiscount] = [SubscriptionDiscount(d) for d in data['discounts']] self.discounts: List[SubscriptionDiscount] = [SubscriptionDiscount(d) for d in data['discounts']]
self.metadata: Metadata = Metadata(data.get('tenant_metadata', {}))
def __repr__(self) -> str: def __repr__(self) -> str:
return f'<SubscriptionInvoiceItem id={self.id} quantity={self.quantity} amount={self.amount}>' return f'<SubscriptionInvoiceItem id={self.id} quantity={self.quantity} amount={self.amount}>'
@ -277,6 +282,10 @@ class SubscriptionInvoice(Hashable):
When the current billing period started. When the current billing period started.
current_period_end: :class:`datetime.datetime` current_period_end: :class:`datetime.datetime`
When the current billing period ends. When the current billing period ends.
applied_discount_ids: List[:class:`int`]
The IDs of the discounts applied to the invoice.
.. versionadded:: 2.1
""" """
__slots__ = ( __slots__ = (
@ -292,6 +301,8 @@ class SubscriptionInvoice(Hashable):
'items', 'items',
'current_period_start', 'current_period_start',
'current_period_end', 'current_period_end',
'applied_discount_ids',
'applied_user_discounts',
) )
def __init__( def __init__(
@ -316,6 +327,12 @@ class SubscriptionInvoice(Hashable):
self.current_period_start: datetime = parse_time(data['subscription_period_start']) # type: ignore # Should always be a datetime self.current_period_start: datetime = parse_time(data['subscription_period_start']) # type: ignore # Should always be a datetime
self.current_period_end: datetime = parse_time(data['subscription_period_end']) # type: ignore # Should always be a datetime self.current_period_end: datetime = parse_time(data['subscription_period_end']) # type: ignore # Should always be a datetime
# These fields are unknown
self.applied_discount_ids: List[int] = [int(id) for id in data.get('applied_discount_ids', [])]
self.applied_user_discounts: Dict[int, Optional[Any]] = {
int(k): v for k, v in data.get('applied_user_discounts', {}).items()
}
def __repr__(self) -> str: def __repr__(self) -> str:
return f'<SubscriptionInvoice id={self.id} status={self.status!r} total={self.total}>' return f'<SubscriptionInvoice id={self.id} status={self.status!r} total={self.total}>'

6
discord/types/entitlements.py

@ -30,7 +30,7 @@ from typing_extensions import NotRequired
from .payments import PartialPayment from .payments import PartialPayment
from .promotions import Promotion from .promotions import Promotion
from .snowflake import Snowflake from .snowflake import Snowflake
from .store import SKU, StoreListing from .store import PublicSKU, PublicStoreListing
from .subscriptions import PartialSubscriptionPlan, SubscriptionPlan, SubscriptionTrial from .subscriptions import PartialSubscriptionPlan, SubscriptionPlan, SubscriptionTrial
from .user import PartialUser from .user import PartialUser
@ -55,7 +55,7 @@ class Entitlement(TypedDict):
ends_at: NotRequired[str] ends_at: NotRequired[str]
subscription_id: NotRequired[Snowflake] subscription_id: NotRequired[Snowflake]
subscription_plan: NotRequired[PartialSubscriptionPlan] subscription_plan: NotRequired[PartialSubscriptionPlan]
sku: NotRequired[SKU] sku: NotRequired[PublicSKU]
payment: NotRequired[PartialPayment] payment: NotRequired[PartialPayment]
@ -78,7 +78,7 @@ class Gift(GatewayGift):
uses: int uses: int
redeemed: bool redeemed: bool
revoked: NotRequired[bool] revoked: NotRequired[bool]
store_listing: NotRequired[StoreListing] store_listing: NotRequired[PublicStoreListing]
promotion: NotRequired[Promotion] promotion: NotRequired[Promotion]
subscription_trial: NotRequired[SubscriptionTrial] subscription_trial: NotRequired[SubscriptionTrial]
subscription_plan: NotRequired[SubscriptionPlan] subscription_plan: NotRequired[SubscriptionPlan]

4
discord/types/payments.py

@ -29,7 +29,7 @@ from typing_extensions import NotRequired
from .billing import PartialPaymentSource from .billing import PartialPaymentSource
from .snowflake import Snowflake from .snowflake import Snowflake
from .store import SKU from .store import PublicSKU
from .subscriptions import PartialSubscription from .subscriptions import PartialSubscription
@ -56,6 +56,6 @@ class Payment(PartialPayment):
downloadable_refund_invoices: NotRequired[List[str]] downloadable_refund_invoices: NotRequired[List[str]]
refund_disqualification_reasons: NotRequired[List[str]] refund_disqualification_reasons: NotRequired[List[str]]
flags: int flags: int
sku: NotRequired[SKU] sku: NotRequired[PublicSKU]
payment_source: NotRequired[PartialPaymentSource] payment_source: NotRequired[PartialPaymentSource]
subscription: NotRequired[PartialSubscription] subscription: NotRequired[PartialSubscription]

69
discord/types/store.py

@ -64,16 +64,14 @@ class CarouselItem(TypedDict, total=False):
youtube_video_id: str youtube_video_id: str
class StoreListing(TypedDict): class BaseStoreListing(TypedDict):
id: Snowflake id: Snowflake
summary: NotRequired[LOCALIZED_STR] summary: NotRequired[LOCALIZED_STR]
description: NotRequired[LOCALIZED_STR] description: NotRequired[LOCALIZED_STR]
tagline: NotRequired[LOCALIZED_STR] tagline: NotRequired[LOCALIZED_STR]
flavor_text: NotRequired[str] flavor_text: NotRequired[str]
published: NotRequired[bool]
entitlement_branch_id: NotRequired[Snowflake] entitlement_branch_id: NotRequired[Snowflake]
staff_notes: NotRequired[StoreNote] staff_notes: NotRequired[StoreNote]
guild: NotRequired[PartialGuild]
assets: NotRequired[List[StoreAsset]] assets: NotRequired[List[StoreAsset]]
carousel_items: NotRequired[List[CarouselItem]] carousel_items: NotRequired[List[CarouselItem]]
preview_video: NotRequired[StoreAsset] preview_video: NotRequired[StoreAsset]
@ -84,17 +82,36 @@ class StoreListing(TypedDict):
thumbnail: NotRequired[StoreAsset] thumbnail: NotRequired[StoreAsset]
header_logo_light_theme: NotRequired[StoreAsset] header_logo_light_theme: NotRequired[StoreAsset]
header_logo_dark_theme: NotRequired[StoreAsset] header_logo_dark_theme: NotRequired[StoreAsset]
sku: SKU sku: PublicSKU
child_skus: NotRequired[List[SKU]] child_skus: NotRequired[List[PublicSKU]]
alternative_skus: NotRequired[List[SKU]] alternative_skus: NotRequired[List[PublicSKU]]
published_at: NotRequired[str]
unpublished_at: NotRequired[str]
class PublicStoreListing(BaseStoreListing):
guild: NotRequired[PartialGuild]
class PrivateStoreListing(BaseStoreListing):
published: bool
StoreListing = Union[PublicStoreListing, PrivateStoreListing]
class PremiumPrice(TypedDict):
amount: int
percentage: int
class SKUPrice(TypedDict): class SKUPrice(TypedDict):
currency: str currency: str
currency_exponent: int
amount: int amount: int
sale_amount: NotRequired[Optional[int]] sale_amount: NotRequired[Optional[int]]
sale_percentage: NotRequired[int] sale_percentage: NotRequired[int]
premium: NotRequired[bool] premium: NotRequired[Dict[Literal[1, 2, 3], PremiumPrice]]
class ContentRating(TypedDict): class ContentRating(TypedDict):
@ -102,17 +119,21 @@ class ContentRating(TypedDict):
descriptors: List[int] descriptors: List[int]
SKUType = Literal[1, 2, 3, 4, 5, 6]
class PartialSKU(TypedDict): class PartialSKU(TypedDict):
id: Snowflake id: Snowflake
type: Literal[1, 2, 3, 4, 5, 6] type: SKUType
premium: bool premium: bool
preorder_release_date: Optional[str] preorder_release_date: Optional[str]
preorder_released_at: Optional[str] preorder_released_at: Optional[str]
class SKU(PartialSKU): class BaseSKU(PartialSKU):
id: Snowflake id: Snowflake
type: Literal[1, 2, 3, 4, 5, 6] type: SKUType
product_line: Optional[Literal[1, 2, 3, 4, 5, 6, 7]]
name: LOCALIZED_STR name: LOCALIZED_STR
summary: NotRequired[LOCALIZED_STR] summary: NotRequired[LOCALIZED_STR]
legal_notice: NotRequired[LOCALIZED_STR] legal_notice: NotRequired[LOCALIZED_STR]
@ -121,18 +142,11 @@ class SKU(PartialSKU):
application_id: Snowflake application_id: Snowflake
application: NotRequired[PartialApplication] application: NotRequired[PartialApplication]
flags: int flags: int
price_tier: NotRequired[int]
price: NotRequired[Union[SKUPrice, Dict[str, int]]]
sale_price_tier: NotRequired[int]
sale_price: NotRequired[Dict[str, int]]
access_level: Literal[1, 2, 3] access_level: Literal[1, 2, 3]
features: List[int] features: List[int]
locales: NotRequired[List[str]] locales: NotRequired[List[str]]
genres: NotRequired[List[int]] genres: NotRequired[List[int]]
available_regions: NotRequired[List[str]] available_regions: NotRequired[List[str]]
content_rating_agency: NotRequired[Literal[1, 2]]
content_rating: NotRequired[ContentRating]
content_ratings: NotRequired[Dict[Literal[1, 2], ContentRating]]
system_requirements: NotRequired[Dict[Literal[1, 2, 3], SystemRequirements]] system_requirements: NotRequired[Dict[Literal[1, 2, 3], SystemRequirements]]
release_date: Optional[str] release_date: Optional[str]
preorder_release_date: NotRequired[Optional[str]] preorder_release_date: NotRequired[Optional[str]]
@ -141,11 +155,30 @@ class SKU(PartialSKU):
premium: NotRequired[bool] premium: NotRequired[bool]
restricted: NotRequired[bool] restricted: NotRequired[bool]
exclusive: NotRequired[bool] exclusive: NotRequired[bool]
deleted: NotRequired[bool]
show_age_gate: bool show_age_gate: bool
bundled_skus: NotRequired[List[SKU]]
manifest_labels: Optional[List[Snowflake]] manifest_labels: Optional[List[Snowflake]]
class PublicSKU(BaseSKU):
bundled_skus: NotRequired[List[PublicSKU]]
price: SKUPrice
content_rating_agency: NotRequired[Literal[1, 2]]
content_rating: NotRequired[ContentRating]
class PrivateSKU(BaseSKU):
bundled_skus: NotRequired[List[PrivateSKU]]
price_tier: int
price: Dict[str, int]
sale_price_tier: int
sale_price: Dict[str, int]
content_ratings: Dict[Literal[1, 2], ContentRating]
SKU = Union[PublicSKU, PrivateSKU]
class SKUPurchase(TypedDict): class SKUPurchase(TypedDict):
entitlements: List[Entitlement] entitlements: List[Entitlement]
library_applications: NotRequired[List[LibraryApplication]] library_applications: NotRequired[List[LibraryApplication]]

3
discord/types/subscriptions.py

@ -73,6 +73,7 @@ class SubscriptionInvoiceItem(TypedDict):
subscription_plan_id: Snowflake subscription_plan_id: Snowflake
subscription_plan_price: int subscription_plan_price: int
discounts: List[SubscriptionDiscount] discounts: List[SubscriptionDiscount]
tenant_metadata: NotRequired[Dict[str, Any]]
class SubscriptionInvoice(TypedDict): class SubscriptionInvoice(TypedDict):
@ -86,6 +87,8 @@ class SubscriptionInvoice(TypedDict):
items: List[SubscriptionInvoiceItem] items: List[SubscriptionInvoiceItem]
current_period_start: str current_period_start: str
current_period_end: str current_period_end: str
applied_discount_ids: NotRequired[List[Snowflake]]
applied_user_discounts: NotRequired[Dict[Snowflake, Optional[Any]]]
class SubscriptionRenewalMutations(TypedDict, total=False): class SubscriptionRenewalMutations(TypedDict, total=False):

6
docs/api.rst

@ -3960,6 +3960,12 @@ of :class:`enum.Enum`.
The payment source is an iDEAL account. The payment source is an iDEAL account.
.. attribute:: cash_app
The payment source is a Cash App account.
.. versionadded:: 2.1
.. class:: PaymentGateway .. class:: PaymentGateway
Represents the payment gateway used for a payment source. Represents the payment gateway used for a payment source.

Loading…
Cancel
Save