diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 56615bd6..5bd80fb8 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -21,7 +21,7 @@ jobs: - name: Install deps run: | pip install -r requirements.txt - pip install -r test-requirements.txt + pip install "pytest>=7.2.2,<8.0.0" - name: Run tests run: pytest tests/ diff --git a/README.md b/README.md index c82e80f8..2cd26e6a 100644 --- a/README.md +++ b/README.md @@ -30,15 +30,15 @@ The package is compatible with Python versions `3.7+`. Install the package from PyPi using the following pip command: ```bash -pip install maxio-advanced-billing-sdk==7.0.1 +pip install maxio-advanced-billing-sdk==8.0.0 ``` You can also view the package at: -https://pypi.python.org/pypi/maxio-advanced-billing-sdk/7.0.1 +https://pypi.python.org/pypi/maxio-advanced-billing-sdk/8.0.0 ## Initialize the API Client -**_Note:_** Documentation for the client can be found [here.](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/client.md) +**_Note:_** Documentation for the client can be found [here.](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/client.md) The following parameters are configurable for the API Client: @@ -46,7 +46,7 @@ The following parameters are configurable for the API Client: | --- | --- | --- | | site | `str` | The subdomain for your Advanced Billing site.
*Default*: `'subdomain'` | | environment | `Environment` | The API environment.
**Default: `Environment.US`** | -| http_client_instance | `HttpClient` | The Http Client passed from the sdk user for making requests | +| http_client_instance | `Union[Session, HttpClientProvider]` | The Http Client passed from the sdk user for making requests | | override_http_client_configuration | `bool` | The value which determines to override properties of the passed Http Client from the sdk user | | http_call_back | `HttpCallBack` | The callback value that is invoked before and after an HTTP call is made to an endpoint | | timeout | `float` | The value to use for connection timeout.
**Default: 120** | @@ -54,11 +54,13 @@ The following parameters are configurable for the API Client: | backoff_factor | `float` | A backoff factor to apply between attempts after the second try.
**Default: 2** | | retry_statuses | `Array of int` | The http statuses on which retry is to be done.
**Default: [408, 413, 429, 500, 502, 503, 504, 521, 522, 524]** | | retry_methods | `Array of string` | The http methods on which retry is to be done.
**Default: ['GET', 'PUT']** | -| proxy_settings | [`ProxySettings`](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/proxy-settings.md) | Optional proxy configuration to route HTTP requests through a proxy server. | -| basic_auth_credentials | [`BasicAuthCredentials`](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/auth/basic-authentication.md) | The credential object for Basic Authentication | +| proxy_settings | [`ProxySettings`](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/proxy-settings.md) | Optional proxy configuration to route HTTP requests through a proxy server. | +| basic_auth_credentials | [`BasicAuthCredentials`](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/auth/basic-authentication.md) | The credential object for Basic Authentication | The API client can be initialized as follows: +### Code-Based Client Initialization + ```python from advancedbilling.advanced_billing_client import AdvancedBillingClient from advancedbilling.configuration import Environment @@ -74,6 +76,17 @@ client = AdvancedBillingClient( ) ``` +### Environment-Based Client Initialization + +```python +from advancedbilling.advanced_billing_client import AdvancedBillingClient + +# Specify the path to your .env file if it’s located outside the project’s root directory. +client = AdvancedBillingClient.from_environment(dotenv_path='/path/to/.env') +``` + +See the [Environment-Based Client Initialization](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/environment-based-client-initialization.md) section for details. + ## Environments The SDK can be configured to use a different environment for making API calls. Available environments are: @@ -89,58 +102,59 @@ The SDK can be configured to use a different environment for making API calls. A This API uses the following authentication schemes. -* [`BasicAuth (Basic Authentication)`](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/auth/basic-authentication.md) +* [`BasicAuth (Basic Authentication)`](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/auth/basic-authentication.md) ## List of APIs -* [API Exports](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/api-exports.md) -* [Advance Invoice](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/advance-invoice.md) -* [Billing Portal](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/billing-portal.md) -* [Component Price Points](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/component-price-points.md) -* [Custom Fields](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/custom-fields.md) -* [Events-Based Billing Segments](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/events-based-billing-segments.md) -* [Payment Profiles](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/payment-profiles.md) -* [Product Families](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/product-families.md) -* [Product Price Points](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/product-price-points.md) -* [Proforma Invoices](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/proforma-invoices.md) -* [Reason Codes](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/reason-codes.md) -* [Referral Codes](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/referral-codes.md) -* [Sales Commissions](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/sales-commissions.md) -* [Subscription Components](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/subscription-components.md) -* [Subscription Groups](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/subscription-groups.md) -* [Subscription Group Invoice Account](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/subscription-group-invoice-account.md) -* [Subscription Group Status](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/subscription-group-status.md) -* [Subscription Invoice Account](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/subscription-invoice-account.md) -* [Subscription Notes](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/subscription-notes.md) -* [Subscription Products](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/subscription-products.md) -* [Subscription Status](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/subscription-status.md) -* [Coupons](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/coupons.md) -* [Components](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/components.md) -* [Customers](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/customers.md) -* [Events](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/events.md) -* [Insights](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/insights.md) -* [Invoices](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/invoices.md) -* [Offers](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/offers.md) -* [Products](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/products.md) -* [Sites](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/sites.md) -* [Subscriptions](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/subscriptions.md) -* [Webhooks](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/controllers/webhooks.md) +* [API Exports](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/api-exports.md) +* [Advance Invoice](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/advance-invoice.md) +* [Billing Portal](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/billing-portal.md) +* [Component Price Points](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/component-price-points.md) +* [Custom Fields](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/custom-fields.md) +* [Events-Based Billing Segments](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/events-based-billing-segments.md) +* [Payment Profiles](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/payment-profiles.md) +* [Product Families](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/product-families.md) +* [Product Price Points](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/product-price-points.md) +* [Proforma Invoices](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/proforma-invoices.md) +* [Reason Codes](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/reason-codes.md) +* [Referral Codes](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/referral-codes.md) +* [Sales Commissions](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/sales-commissions.md) +* [Subscription Components](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/subscription-components.md) +* [Subscription Groups](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/subscription-groups.md) +* [Subscription Group Invoice Account](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/subscription-group-invoice-account.md) +* [Subscription Group Status](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/subscription-group-status.md) +* [Subscription Invoice Account](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/subscription-invoice-account.md) +* [Subscription Notes](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/subscription-notes.md) +* [Subscription Products](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/subscription-products.md) +* [Subscription Status](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/subscription-status.md) +* [Coupons](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/coupons.md) +* [Components](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/components.md) +* [Customers](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/customers.md) +* [Events](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/events.md) +* [Insights](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/insights.md) +* [Invoices](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/invoices.md) +* [Offers](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/offers.md) +* [Products](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/products.md) +* [Sites](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/sites.md) +* [Subscriptions](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/subscriptions.md) +* [Webhooks](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/controllers/webhooks.md) ## SDK Infrastructure ### Configuration -* [ProxySettings](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/proxy-settings.md) +* [ProxySettings](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/proxy-settings.md) +* [Environment-Based Client Initialization](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/environment-based-client-initialization.md) ### HTTP -* [HttpResponse](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/http-response.md) -* [HttpRequest](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/http-request.md) +* [HttpResponse](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/http-response.md) +* [HttpRequest](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/http-request.md) ### Utilities -* [ApiHelper](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/api-helper.md) -* [HttpDateTime](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/http-date-time.md) -* [RFC3339DateTime](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/rfc3339-date-time.md) -* [UnixDateTime](https://www.github.com/maxio-com/ab-python-sdk/tree/7.0.1/doc/unix-date-time.md) +* [ApiHelper](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/api-helper.md) +* [HttpDateTime](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/http-date-time.md) +* [RFC3339DateTime](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/rfc3339-date-time.md) +* [UnixDateTime](https://www.github.com/maxio-com/ab-python-sdk/tree/8.0.0/doc/unix-date-time.md) diff --git a/advancedbilling/__init__.py b/advancedbilling/__init__.py index 67671340..195fc7af 100644 --- a/advancedbilling/__init__.py +++ b/advancedbilling/__init__.py @@ -6,4 +6,5 @@ 'exceptions', 'http', 'models', + 'utilities', ] diff --git a/advancedbilling/advanced_billing_client.py b/advancedbilling/advanced_billing_client.py index b5d23185..fa32b03f 100644 --- a/advancedbilling/advanced_billing_client.py +++ b/advancedbilling/advanced_billing_client.py @@ -220,8 +220,11 @@ def __init__(self, http_client_instance=None, .base_uri_executor(self.config.get_base_uri)\ .user_agent(BaseController.user_agent(), BaseController.user_agent_parameters()) - self.auth_managers = {key: None for key in ['BasicAuth']} - self.auth_managers['BasicAuth'] = BasicAuth( - self.config.basic_auth_credentials) + self.auth_managers = { + 'BasicAuth': BasicAuth(self.config.basic_auth_credentials) + } self.global_configuration = self.global_configuration.auth_managers(self.auth_managers) + @classmethod + def from_environment(cls, dotenv_path=None, **overrides): + return cls(config=Configuration.from_environment(dotenv_path=dotenv_path, **overrides)) diff --git a/advancedbilling/configuration.py b/advancedbilling/configuration.py index 8b4891e3..841307b9 100644 --- a/advancedbilling/configuration.py +++ b/advancedbilling/configuration.py @@ -7,6 +7,9 @@ https://www.apimatic.io ). """ +import os +from dotenv import load_dotenv +from advancedbilling.http.proxy_settings import ProxySettings from enum import Enum from advancedbilling.api_helper import APIHelper from apimatic_core.http.configurations.http_client_configuration import HttpClientConfiguration @@ -20,12 +23,66 @@ class Environment(Enum): # Advanced Billing environment hosted in EU. Use only when you requested EU hosting for your AB account. EU = 1 + @classmethod + def from_value(cls, value, default=None): + """ + Convert a value (string or int) to an Environment enum member. + + Args: + value (Union[str, int]): The value to convert. + default (Environment): The fallback enum member if conversion fails. + + Returns: + Environment: Matching enum member or fallback if invalid. + """ + if value is None: + return default + + # Try to match directly by enum member + if isinstance(value, cls): + return value + + # Handle integer or string conversion + for member in cls: + if str(member.value).lower() == str(value).lower() or member.name.lower() == str(value).lower(): + return member + + # Fallback to provided default + return default + class Server(Enum): """An enum for API servers""" PRODUCTION = 0 EBB = 1 + @classmethod + def from_value(cls, value, default=None): + """ + Convert a value (string or int) to an Server enum member. + + Args: + value (Union[str, int]): The value to convert. + default (Server): The fallback enum member if conversion fails. + + Returns: + Server: Matching enum member or fallback if invalid. + """ + if value is None: + return default + + # Try to match directly by enum member + if isinstance(value, cls): + return value + + # Handle integer or string conversion + for member in cls: + if str(member.value).lower() == str(value).lower() or member.name.lower() == str(value).lower(): + return member + + # Fallback to provided default + return default + class Configuration(HttpClientConfiguration): """A class used for configuring the SDK by a user. @@ -144,3 +201,47 @@ def get_base_uri(self, server=Server.PRODUCTION): return APIHelper.append_url_with_template_parameters( self.environments[self.environment][server], parameters ) + + @classmethod + def from_environment(cls, dotenv_path=None, **overrides): + """ + Creates a Configuration object using values from a .env file, environment variables, and optional overrides. + + Args: + dotenv_path (str, optional): Path to the .env file to load. If None, the default .env file is used. + **overrides: Additional configuration values to override those loaded from the .env file and environment variables. + + Returns: + Configuration: A configuration object populated with the resolved values. + """ + + # load .env automatically + load_dotenv(dotenv_path or None, override=True) + + override_http_client_configuration = os.getenv('OVERRIDE_HTTP_CLIENT_CONFIGURATION', 'false').lower() == 'true' + timeout = int(os.getenv('TIMEOUT', '120')) + max_retries = int(os.getenv('MAX_RETRIES', '0')) + backoff_factor = float(os.getenv('BACKOFF_FACTOR', '2')) + statuses = os.getenv('RETRY_STATUSES', None) + retry_statuses = [int(v.strip()) for v in statuses.split(',') if v.strip().isdigit()] if statuses else None + methods = os.getenv('RETRY_METHODS', None) + retry_methods = [v.strip() for v in methods.split(',') if v.strip()] if methods else None + environment = Environment.from_value(os.getenv('ENVIRONMENT'), Environment.US) + site = os.getenv('SITE', 'subdomain') + + from advancedbilling.http.auth.basic_auth import BasicAuthCredentials + # Preparing default configuration + default_config = cls( + override_http_client_configuration=override_http_client_configuration, + timeout=timeout, + max_retries=max_retries, + backoff_factor=backoff_factor, + retry_statuses=retry_statuses, + retry_methods=retry_methods, + environment=environment, + site=site, + proxy_settings=ProxySettings.from_environment(), + basic_auth_credentials=BasicAuthCredentials.from_environment() + ) + + return default_config.clone_with(**overrides) \ No newline at end of file diff --git a/advancedbilling/controllers/advance_invoice_controller.py b/advancedbilling/controllers/advance_invoice_controller.py index 0d556fad..d41c9353 100644 --- a/advancedbilling/controllers/advance_invoice_controller.py +++ b/advancedbilling/controllers/advance_invoice_controller.py @@ -32,7 +32,7 @@ def issue_advance_invoice(self, """Does a POST request to /subscriptions/{subscription_id}/advance_invoice/issue.json. Generate an invoice in advance for a subscription's next renewal date. - [Please see our + [See our docs](https://maxio.zendesk.com/hc/en-us/articles/24252026404749-Issue- Invoice-In-Advance) for more information on advance invoices, including eligibility on generating one; for the most part, they @@ -144,8 +144,7 @@ def void_advance_invoice(self, A `reason` is required in order to void, and the invoice must have an open status. Voiding will cause any prepayments and credits that were applied to the invoice to be returned to the subscription. For a full - overview of the impact of voiding, please [see our help - docs]($m/Invoice). + overview of the impact of voiding, [see our help docs]($m/Invoice). Args: subscription_id (int): The Chargify id of the subscription diff --git a/advancedbilling/controllers/base_controller.py b/advancedbilling/controllers/base_controller.py index 41502638..c53ca396 100644 --- a/advancedbilling/controllers/base_controller.py +++ b/advancedbilling/controllers/base_controller.py @@ -30,7 +30,7 @@ class BaseController(object): @staticmethod def user_agent(): - return 'AB SDK Python:7.0.1 on OS {os-info}' + return 'AB SDK Python:8.0.0 on OS {os-info}' @staticmethod def user_agent_parameters(): diff --git a/advancedbilling/controllers/billing_portal_controller.py b/advancedbilling/controllers/billing_portal_controller.py index 80d4d940..eb2dea83 100644 --- a/advancedbilling/controllers/billing_portal_controller.py +++ b/advancedbilling/controllers/billing_portal_controller.py @@ -61,7 +61,7 @@ def enable_billing_portal_for_customer(self, only when absolutely necessary. Management URLs are good for 65 days, so you should re-use a previously generated one as much as possible. If you use the URL frequently (such as to display on your website), - please **do not** make an API request to Advanced Billing every time. + **do not** make an API request to Advanced Billing every time. Args: customer_id (int): The Chargify id of the customer diff --git a/advancedbilling/controllers/component_price_points_controller.py b/advancedbilling/controllers/component_price_points_controller.py index cdc3bde7..b72b0b2d 100644 --- a/advancedbilling/controllers/component_price_points_controller.py +++ b/advancedbilling/controllers/component_price_points_controller.py @@ -280,8 +280,8 @@ def update_component_price_point(self, body=None): """Does a PUT request to /components/{component_id}/price_points/{price_point_id}.json. - When updating a price point, it's prices can be updated as well by - creating new prices or editing / removing existing ones. + When updating a price point, prices can be updated as well by creating + new prices or editing / removing existing ones. Passing in a price bracket without an `id` will attempt to create a new price. Including an `id` will update the corresponding price, and including diff --git a/advancedbilling/controllers/components_controller.py b/advancedbilling/controllers/components_controller.py index 4d522ad8..bbc1d824 100644 --- a/advancedbilling/controllers/components_controller.py +++ b/advancedbilling/controllers/components_controller.py @@ -44,7 +44,7 @@ def create_metered_component(self, which DO NOT reset to zero at the start of every billing period. If you want to bill for a quantity of something that does not change unless you change it, then you want quantity components, instead. - For more information on components, please see our documentation + For more information on components, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Compo nents-Overview). @@ -114,7 +114,7 @@ def create_quantity_based_component(self, other services. The allocated quantity for one-time quantity-based components immediately gets reset back to zero after the allocation is made. - For more information on components, please see our documentation + For more information on components, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Compo nents-Overview). @@ -172,7 +172,7 @@ def create_on_off_component(self, component can then be added and “allocated” for a subscription. On/off components are used for any flat fee, recurring add on (think $99/month for tech support or a flat add on shipping fee). - For more information on components, please see our documentation + For more information on components, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Compo nents-Overview). @@ -233,7 +233,7 @@ def create_prepaid_usage_component(self, the end of the period for the amount of units used, prepaid components are charged for at the time of purchase, and we subsequently keep track of the usage against the amount purchased. - For more information on components, please see our documentation + For more information on components, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Compo nents-Overview). @@ -299,7 +299,7 @@ def create_event_based_component(self, So, instead of reporting usage directly for each component (as you would with metered components), the usage is derived from analysis of your events. - For more information on components, please see our documentation + For more information on components, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Compo nents-Overview). diff --git a/advancedbilling/controllers/coupons_controller.py b/advancedbilling/controllers/coupons_controller.py index 6791a8eb..747767bd 100644 --- a/advancedbilling/controllers/coupons_controller.py +++ b/advancedbilling/controllers/coupons_controller.py @@ -40,12 +40,11 @@ def create_coupon(self, ## Coupons Documentation Coupons can be administered in the Advanced Billing application or - created via API. Please view our section on [creating + created via API. View our section on [creating coupons](https://maxio.zendesk.com/hc/en-us/articles/24261212433165-Cre ating-Editing-Deleting-Coupons) for more information. Additionally, for documentation on how to apply a coupon to a - subscription within the Advanced Billing UI, please see our - documentation + subscription within the Advanced Billing UI, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupo ns-and-Subscriptions). ## Create Coupon @@ -104,9 +103,6 @@ def list_coupons_for_product_family(self, """Does a GET request to /product_families/{product_family_id}/coupons.json. List coupons for a specific Product Family in a Site. - If the coupon is set to `use_site_exchange_rate: true`, it will return - pricing based on the current exchange rate. If the flag is set to - false, it will return all of the defined prices for each currency. Args: options (dict, optional): Key-value pairs for any of the @@ -422,9 +418,6 @@ def list_coupons(self, """Does a GET request to /coupons.json. You can retrieve a list of coupons. - If the coupon is set to `use_site_exchange_rate: true`, it will return - pricing based on the current exchange rate. If the flag is set to - false, it will return all of the defined prices for each currency. Args: options (dict, optional): Key-value pairs for any of the @@ -503,8 +496,8 @@ def read_coupon_usage(self, Args: product_family_id (int): The Advanced Billing id of the product - family to which the coupon belongs - coupon_id (int): The Advanced Billing id of the coupon + family to which the coupon belongs. + coupon_id (int): The Advanced Billing id of the coupon. Returns: List[CouponUsage]: Response from the API. OK @@ -693,8 +686,7 @@ def create_coupon_subcodes(self, [here](https://maxio.zendesk.com/hc/en-us/articles/24261208729229-Coupo n-Codes). Additionally, for documentation on how to apply a coupon to a - Subscription within the Advanced Billing UI, please see our - documentation + Subscription within the Advanced Billing UI, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupo ns-and-Subscriptions). ## Create Coupon Subcode diff --git a/advancedbilling/controllers/custom_fields_controller.py b/advancedbilling/controllers/custom_fields_controller.py index 3f49f001..691b7788 100644 --- a/advancedbilling/controllers/custom_fields_controller.py +++ b/advancedbilling/controllers/custom_fields_controller.py @@ -35,45 +35,35 @@ def create_metafields(self, body=None): """Does a POST request to /{resource_type}/metafields.json. - ## Custom Fields: Metafield Intro - **Advanced Billing refers to Custom Fields in the API documentation as - metafields and metadata.** Within the Advanced Billing UI, metadata - and metafields are grouped together under the umbrella of "Custom - Fields." All of our UI-based documentation that references custom - fields will not cite the terminology metafields or metadata. - + **Metafield is the custom field** - + **Metadata is the data populating the custom field.** - Advanced Billing Metafields are used to add meaningful attributes to - subscription and customer resources. Full documentation on how to - create Custom Fields in the Advanced Billing UI can be located - [here](https://maxio.zendesk.com/hc/en-us/sections/24266118312589-Custo - m-Fields). For additional documentation on how to record data within - custom fields, please see our subscription-based documentation - [here](https://maxio.zendesk.com/hc/en-us/articles/24251701302925-Subsc - ription-Summary-Custom-Fields-Tab). - Metafield are the place where you will set up your resource to accept - additional data. It is scoped to the site instead of a specific - customer or subscription. Think of it as the key, and Metadata as the - value on every record. - ## Create Metafields - Use this endpoint to create metafields for your Site. Metafields can - be populated with metadata after the fact. - Each site is limited to 100 unique Metafields (i.e. keys, or names) - per resource. This means you can have 100 Metafields for Subscription - and another 100 for Customer. - ### Metafields "On-the-Fly" - It is possible to create Metafields “on the fly” when you create your - Metadata – if a non-existent name is passed when creating Metadata, a - Metafield for that key will be automatically created. The Metafield - API, however, gives you more control over your “keys”. - ### Metafield Scope Warning - If configuring metafields in the Admin UI or via the API, be careful - sending updates to metafields with the scope attribute – **if a - partial update is sent it will overwrite the current configuration**. + Creates metafields on a Site for either the Subscriptions or Customers + resource. + Metafields and their metadata are created in the Custom Fields + configuration page on your Site. Metafields can be populated with + metadata when you create them or later with the [Update + Metafield]($e/Custom%20Fields/updateMetafield), [Create + Metadata]($e/Custom%20Fields/createMetadata), or [Update + Metadata]($e/Custom%20Fields/updateMetadata) endpoints. The Create + Metadata and Update Metadata endpoints allow you to add metafields and + metadata values to a specific subscription or customer. + Each site is limited to 100 unique metafields per resource. This means + you can have 100 metafields for Subscriptions and another 100 for + Customers. + > Note: After creating a metafield, the resource type cannot be + modified. + In the UI and product documentation, metafields and metadata are + called Custom Fields. + - Metafield is the custom field + - Metadata is the data populating the custom field. + See [Custom Fields + Reference](https://docs.maxio.com/hc/en-us/articles/24266140850573-Cust + om-Fields-Reference) and [Custom Fields + Tab](https://maxio.zendesk.com/hc/en-us/articles/24251701302925-Subscri + ption-Summary-Custom-Fields-Tab) for information on using Custom + Fields in the Advanced Billing UI. Args: - resource_type (ResourceType): the resource type to which the - metafields belong + resource_type (ResourceType): The resource type to which the + metafields belong. body (CreateMetafieldsRequest, optional): The request body parameter. @@ -118,8 +108,8 @@ def list_metafields(self, options=dict()): """Does a GET request to /{resource_type}/metafields.json. - This endpoint lists metafields associated with a site. The metafield - description and usage is contained in the response. + Lists the metafields and their associated details for a Site and + resource type. You can filter the request to a specific metafield. Args: options (dict, optional): Key-value pairs for any of the @@ -128,9 +118,9 @@ def list_metafields(self, being the key and their desired values being the value. A list of parameters that can be used are:: - resource_type -- ResourceType -- the resource type to - which the metafields belong - name -- str -- filter by the name of the metafield + resource_type -- ResourceType -- The resource type to + which the metafields belong. + name -- str -- Filter by the name of the metafield. page -- int -- Result records are organized in pages. By default, the first page of results is displayed. The page parameter specifies a page number of results to @@ -196,12 +186,42 @@ def update_metafield(self, body=None): """Does a PUT request to /{resource_type}/metafields.json. - Use the following method to update metafields for your Site. - Metafields can be populated with metadata after the fact. + Updates metafields on your Site for a resource type. Depending on the + request structure, you can update or add metafields and metadata to + the Subscriptions or Customers resource. + With this endpoint, you can: + - Add metafields. If the metafield specified in current_name does not + exist, a new metafield is added. + >Note: Each site is limited to 100 unique metafields per resource. + This means you can have 100 metafields for Subscriptions and another + 100 for Customers. + - Change the name of a metafield. + >Note: To keep the metafield name the same and only update the + metadata for the metafield, you must use the current metafield name in + both the `current_name` and `name` parameters. + - Change the input type for the metafield. For example, you can change + a metafield input type from text to a dropdown. If you change the + input type from text to a dropdown or radio, you must update the + specific subscriptions or customers where the metafield was used to + reflect the updated metafield and metadata. + - Add metadata values to the existing metadata for a dropdown or radio + metafield. + >Note: Updates to metadata overwrite. To add one or more values, you + must specify all metadata values including the new value you want to + add. + - Add new metadata to a dropdown or radio for a metafield that was + created without metadata. + - Remove metadata for a dropdown or radio for a metafield. + >Note: Updates to metadata overwrite existing values. To remove one + or more values, specify all metadata values except those you want to + remove. + - Add or update scope settings for a metafield. + >Note: Scope changes overwrite existing settings. You must specify + the complete scope, including the changes you want to make. Args: - resource_type (ResourceType): the resource type to which the - metafields belong + resource_type (ResourceType): The resource type to which the + metafields belong. body (UpdateMetafieldsRequest, optional): The request body parameter. @@ -247,14 +267,13 @@ def delete_metafield(self, name=None): """Does a DELETE request to /{resource_type}/metafields.json. - Use the following method to delete a metafield. This will remove the - metafield from the Site. - Additionally, this will remove the metafield and associated metadata - with all Subscriptions on the Site. + Deletes a metafield from your Site. Removes the metafield and + associated metadata from all Subscriptions or Customers resources on + the Site. Args: - resource_type (ResourceType): the resource type to which the - metafields belong + resource_type (ResourceType): The resource type to which the + metafields belong. name (str, optional): The name of the metafield to be deleted Returns: @@ -289,38 +308,21 @@ def create_metadata(self, body=None): """Does a POST request to /{resource_type}/{resource_id}/metadata.json. - ## Custom Fields: Metadata Intro - **Advanced Billing refers to Custom Fields in the API documentation as - metafields and metadata.** Within the Advanced Billing UI, metadata - and metafields are grouped together under the umbrella of "Custom - Fields." All of our UI-based documentation that references custom - fields will not cite the terminology metafields or metadata. - + **Metafield is the custom field** - + **Metadata is the data populating the custom field.** - Advanced Billing Metafields are used to add meaningful attributes to - subscription and customer resources. Full documentation on how to - create Custom Fields in the Advanced Billing UI can be located - [here](https://maxio.zendesk.com/hc/en-us/articles/24266164865677-Custo - m-Fields-Overview). For additional documentation on how to record data - within custom fields, please see our subscription-based documentation - [here.](https://maxio.zendesk.com/hc/en-us/articles/24251701302925-Subs - cription-Summary-Custom-Fields-Tab) - Metadata is associated to a customer or subscription, and corresponds - to a Metafield. When creating a new metadata object for a given - record, **if the metafield is not present it will be created**. - ## Metadata limits - Metadata values are limited to 2kB in size. Additonally, there are - limits on the number of unique metafields available per resource. - ## Create Metadata - This method will create a metafield for the site on the fly if it does - not already exist, and populate the metadata value. - ### Subscription or Customer Resource - Please pay special attention to the resource you use when creating - metadata. + Creates metadata and metafields for a specific subscription or + customer, or updates metadata values of existing metafields for a + subscription or customer. Metadata values are limited to 2 KB in size. + If you create metadata on a subscription or customer with a metafield + that does not already exist, the metafield is created with the + metadata you specify and it is always added as a text field. You can + update the input_type for the metafield with the [Update + Metafield]($e/Custom%20Fields/updateMetafield) endpoint. + >Note: Each site is limited to 100 unique metafields per resource. + This means you can have 100 metafields for Subscriptions and another + 100 for Customers. Args: - resource_type (ResourceType): the resource type to which the - metafields belong + resource_type (ResourceType): The resource type to which the + metafields belong. resource_id (int): The Advanced Billing id of the customer or the subscription for which the metadata applies body (CreateMetadataRequest, optional): The request body parameter. @@ -371,11 +373,7 @@ def list_metadata(self, options=dict()): """Does a GET request to /{resource_type}/{resource_id}/metadata.json. - This request will list all of the metadata belonging to a particular - resource (ie. subscription, customer) that is specified. - ## Metadata Data - This endpoint will also display the current stats of your metadata to - use as a tool for pagination. + Lists metadata and metafields for a specific customer or subscription. Args: options (dict, optional): Key-value pairs for any of the @@ -384,8 +382,8 @@ def list_metadata(self, being the key and their desired values being the value. A list of parameters that can be used are:: - resource_type -- ResourceType -- the resource type to - which the metafields belong + resource_type -- ResourceType -- The resource type to + which the metafields belong. resource_id -- int -- The Advanced Billing id of the customer or the subscription for which the metadata applies @@ -451,12 +449,21 @@ def update_metadata(self, body=None): """Does a PUT request to /{resource_type}/{resource_id}/metadata.json. - This method allows you to update the existing metadata associated with - a subscription or customer. + Updates metadata and metafields on the Site and the customer or + subscription specified, and updates the metadata value on a + subscription or customer. + If you update metadata on a subscription or customer with a metafield + that does not already exist, the metafield is created with the + metadata you specify and it is always added as a text field to the + Site and to the subscription or customer you specify. You can update + the input_type for the metafield with the Update Metafield endpoint. + Each site is limited to 100 unique metafields per resource. This means + you can have 100 metafields for Subscription and another 100 for + Customer. Args: - resource_type (ResourceType): the resource type to which the - metafields belong + resource_type (ResourceType): The resource type to which the + metafields belong. resource_id (int): The Advanced Billing id of the customer or the subscription for which the metadata applies body (UpdateMetadataRequest, optional): The request body parameter. @@ -510,29 +517,12 @@ def delete_metadata(self, names=None): """Does a DELETE request to /{resource_type}/{resource_id}/metadata.json. - This method removes the metadata from the subscriber/customer cited. - ## Query String Usage - For instance if you wanted to delete the metadata for customer 99 - named weight you would request: - ``` - https://acme.chargify.com/customers/99/metadata.json?name=weight - ``` - If you want to delete multiple metadata fields for a customer 99 - named: `weight` and `age` you wrould request: - ``` - https://acme.chargify.com/customers/99/metadata.json?names[]=weight&nam - es[]=age - ``` - ## Successful Response - For a success, there will be a code `200` and the plain text response - `true`. - ## Unsuccessful Response - When a failed response is encountered, you will receive a `404` - response and the plain text response of `true`. + Deletes one or more metafields (and associated metadata) from the + specified subscription or customer. Args: - resource_type (ResourceType): the resource type to which the - metafields belong + resource_type (ResourceType): The resource type to which the + metafields belong. resource_id (int): The Advanced Billing id of the customer or the subscription for which the metadata applies name (str, optional): Name of field to be removed. @@ -578,17 +568,7 @@ def list_metadata_for_resource_type(self, options=dict()): """Does a GET request to /{resource_type}/metadata.json. - This method will provide you information on usage of metadata across - your selected resource (ie. subscriptions, customers) - ## Metadata Data - This endpoint will also display the current stats of your metadata to - use as a tool for pagination. - ### Metadata for multiple records - `https://acme.chargify.com/subscriptions/metadata.json?resource_ids[]=1 - &resource_ids[]=2` - ## Read Metadata for a Site - This endpoint will list the number of pages of metadata information - that are contained within a site. + Lists metadata for a specified array of subscriptions or customers. Args: options (dict, optional): Key-value pairs for any of the @@ -597,8 +577,8 @@ def list_metadata_for_resource_type(self, being the key and their desired values being the value. A list of parameters that can be used are:: - resource_type -- ResourceType -- the resource type to - which the metafields belong + resource_type -- ResourceType -- The resource type to + which the metafields belong. page -- int -- Result records are organized in pages. By default, the first page of results is displayed. The page parameter specifies a page number of results to diff --git a/advancedbilling/controllers/customers_controller.py b/advancedbilling/controllers/customers_controller.py index b74d2406..fb965831 100644 --- a/advancedbilling/controllers/customers_controller.py +++ b/advancedbilling/controllers/customers_controller.py @@ -49,7 +49,7 @@ def create_customer(self, Advanced Billing requires that you use the ISO Standard Country codes when formatting country attribute of the customer. Countries should be formatted as 2 characters. For more information, - please see the following wikipedia article on + see the following wikipedia article on [ISO_3166-1.](http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) ## Required State Format Advanced Billing requires that you use the ISO Standard State codes @@ -57,7 +57,7 @@ def create_customer(self, + US States (2 characters): [ISO_3166-2](https://en.wikipedia.org/wiki/ISO_3166-2:US) + States Outside the US (2-3 characters): To find the correct state - codes outside of the US, please go to + codes outside of the US, go to [ISO_3166-1](http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) and click on the link in the “ISO 3166-2 codes” column next to country you wish to populate. @@ -118,7 +118,7 @@ def list_customers(self, + Search by an organization + Search by a reference value from your application + Search by a first or last name - To retrieve a single, exact match by reference, please use the [lookup + To retrieve a single, exact match by reference, use the [lookup endpoint](https://developers.chargify.com/docs/api-docs/b710d8fbef104-r ead-customer-by-reference). diff --git a/advancedbilling/controllers/invoices_controller.py b/advancedbilling/controllers/invoices_controller.py index 39126f51..06b60997 100644 --- a/advancedbilling/controllers/invoices_controller.py +++ b/advancedbilling/controllers/invoices_controller.py @@ -1030,6 +1030,38 @@ def create_invoice(self, ] ... ``` + #### Using Coupon Subcodes + You can also use coupon subcodes to apply existing coupons with + specific subcodes: + ```json + ... + "coupons": [ + { + "subcode": "SUB1", + "product_family_id": 1 + } + ] + ... + ``` + **Important:** You cannot specify both `code` and `subcode` for the + same coupon. Use either: + - `code` to apply a main coupon + - `subcode` to apply a specific coupon subcode + The API response will include both the main coupon code and the + subcode used: + ```json + ... + "coupons": [ + { + "code": "MAIN123", + "subcode": "SUB1", + "product_family_id": 1, + "percentage": 10, + "description": "Special discount" + } + ] + ... + ``` ### Coupon options #### Code Coupon `code` will be displayed on invoice discount section. @@ -1038,6 +1070,12 @@ def create_invoice(self, Lowercase letters will be converted to uppercase. It can be used to select an existing coupon from the catalog, or as an ad hoc coupon when passed with `percentage` or `amount`. + #### Subcode + Coupon `subcode` allows you to apply existing coupons using their + subcodes. When a subcode is used, the API response will include both + the main coupon code and the specific subcode that was applied. + Subcodes are case-insensitive and will be converted to uppercase + automatically. #### Percentage Coupon `percentage` can take values from 0 to 100 and up to 4 decimal places. It cannot be used with `amount`. Only for ad hoc coupons, will @@ -1100,7 +1138,7 @@ def create_invoice(self, #### Addresses The seller, shipping and billing addresses can be sent to override the site's defaults. Each address requires to send a `first_name` at a - minimum in order to work. Please see below for the details on which + minimum in order to work. See below for the details on which parameters can be sent for each address object. #### Memo and Payment Instructions A custom memo can be sent with the `memo` parameter to override the @@ -1161,16 +1199,16 @@ def send_invoice(self, automatically generated invoices. Additionally, this endpoint supports email delivery to direct recipients, carbon-copy (cc) recipients, and blind carbon-copy (bcc) recipients. - Please note that if no recipient email addresses are specified in the - request, then the subscription's default email configuration will be - used. For example, if `recipient_emails` is left blank, then the - invoice will be delivered to the subscription's customer email address. - On success, a 204 no-content response will be returned. Please note - that this does not indicate that email(s) have been delivered, but - instead indicates that emails have been successfully queued for - delivery. If _any_ invalid or malformed email address is found in the - request body, the entire request will be rejected and a 422 response - will be returned. + If no recipient email addresses are specified in the request, then the + subscription's default email configuration will be used. For example, + if `recipient_emails` is left blank, then the invoice will be + delivered to the subscription's customer email address. + On success, a 204 no-content response will be returned. The response + does not indicate that email(s) have been delivered, but instead + indicates that emails have been successfully queued for delivery. If + _any_ invalid or malformed email address is found in the request body, + the entire request will be rejected and a 422 response will be + returned. Args: uid (str): The unique identifier for the invoice, this does not diff --git a/advancedbilling/controllers/payment_profiles_controller.py b/advancedbilling/controllers/payment_profiles_controller.py index 4f278db5..f7402e45 100644 --- a/advancedbilling/controllers/payment_profiles_controller.py +++ b/advancedbilling/controllers/payment_profiles_controller.py @@ -33,41 +33,29 @@ def create_payment_profile(self, body=None): """Does a POST request to /payment_profiles.json. - Use this endpoint to create a payment profile for a customer. - Payment Profiles house the credit card, ACH (Authorize.Net or Stripe - only,) or PayPal (Braintree only,) data for a customer. The payment - information is attached to the customer within Advanced Billing, as - opposed to the Subscription itself. - You must include a customer_id so that Advanced Billing will attach it - to the customer entry. If no customer_id is included the API will - return a 404. - ## Create a Payment Profile for ACH usage - If you would like to create a payment method that is a Bank Account - applicable for ACH payments use the following: - ```json - { - "payment_profile": { - "customer_id": [Valid-Customer-ID], - "bank_name": "Best Bank", - "bank_routing_number": "021000089", - "bank_account_number": "111111111111", - "bank_account_type": "checking", - "bank_account_holder_type": "business", - "payment_type": "bank_account" - } - } - ``` - ## Taxable Subscriptions - If your subscriber pays taxes on their purchased product, and you are - attempting to create or update the `payment_profile`, complete address - information is required. For information on required address - formatting to allow your subscriber to be taxed, please see our - documentation - [here](https://developers.chargify.com/docs/developer-docs/d2e9e34db740 - e-signups#taxes) - ## Payment Profile Documentation - Full documentation on how Payment Profiles operate within Advanced - Billing can be located under the following links: + Creates a payment profile for a customer. + When you create a new payment profile for a customer via the API, it + does not automatically make the profile current for any of the + customer’s subscriptions. To use the payment profile as the default, + you must set it explicitly for the subscription or subscription group. + Select an option from the **Request Examples** drop-down on the right + side of the portal to see examples of common scenarios for creating + payment profiles. + Do not use real card information for testing. See the Sites articles + that cover [testing your site + setup](https://docs.maxio.com/hc/en-us/articles/24250712113165-Testing- + Overview#testing-overview-0-0) for more details on testing in your + sandbox. + Note that collecting and sending raw card details in production + requires [PCI + compliance](https://docs.maxio.com/hc/en-us/articles/24183956938381-PCI + -Compliance#pci-compliance-0-0) on your end. If your business is not + PCI compliant, use + [Chargify.js](https://docs.maxio.com/hc/en-us/articles/38163190843789-C + hargify-js-Overview#chargify-js-overview-0-0) to collect credit card + or bank account information. + See the following articles to learn more about subscriptions and + payments: + [Subscriber Payment Details](https://maxio.zendesk.com/hc/en-us/articles/24251599929613-Sub scription-Summary-Payment-Details-Tab) @@ -77,213 +65,50 @@ def create_payment_profile(self, + [Public Signup Pages payment settings](https://maxio.zendesk.com/hc/en-us/articles/24261368332557-In dividual-Page-Settings) - ## Create a Payment Profile with a Chargify.js token - ```json - { - "payment_profile": { - "customer_id": 1036, - "chargify_token": "tok_w68qcpnftyv53jk33jv6wk3w" - } - } - ``` - ## Active Payment Methods - Creating a new payment profile for a Customer via the API will not - make that Payment Profile current for any of the Customer’s - Subscriptions. In order to utilize the payment profile as the default, - it must be set as the default payment profile for the subscription or - subscription group. - ## Requirements - Either the full_number, expiration_month, and expiration_year or if - you have an existing vault_token from your gateway, that vault_token - and the current_vault are required. - Passing in the vault_token and current_vault are only allowed when - creating a new payment profile. - ### Taxable Subscriptions - If your subscriber pays taxes on their purchased product, and you are - attempting to create or update the `payment_profile`, complete address - information is required. For information on required address - formatting to allow your subscriber to be taxed, please see our - documentation - [here](https://developers.chargify.com/docs/developer-docs/d2e9e34db740 - e-signups#taxes) - ## BraintreeBlue - Some merchants use Braintree JavaScript libraries directly and then - pass `payment_method_nonce` and/or `paypal_email` to create a payment - profile. This implementation is deprecated and does not handle 3D - Secure. Instead, we have provided - [Chargify.js](https://developers.chargify.com/docs/developer-docs/ZG9jO - jE0NjAzNDI0-overview) which is continuously improved and supports - Credit Cards (along with 3D Secure), PayPal and ApplePay payment types. - ## GoCardless - For more information on GoCardless, please view the following - resources: - + [Full documentation on - GoCardless](https://maxio.zendesk.com/hc/en-us/articles/24176159136909- - GoCardless) - + [Using Chargify.js with GoCardless - minimal + + + [Taxes](https://developers.chargify.com/docs/developer-docs/d2e9e34db74 + 0e-signups#taxes) + + + [Chargify.js](https://docs.maxio.com/hc/en-us/articles/38163190843789-C + hargify-js-Overview) + + [Chargify.js with GoCardless - minimal example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl es#h_01K0PJ15QQZKCER8CFK40MR6XJ) - + [Using Chargify.js with GoCardless - full + + [Chargify.js with GoCardless - full example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl es#h_01K0PJ15QR09JVHWW0MCA7HVJV) - ### GoCardless with Local Bank Details - Following examples create customer, bank account and mandate in - GoCardless: - ```json - { - "payment_profile": { - "customer_id": "Valid-Customer-ID", - "bank_name": "Royal Bank of France", - "bank_account_number": "0000000", - "bank_routing_number": "0003", - "bank_branch_code": "00006", - "payment_type": "bank_account", - "billing_address": "20 Place de la Gare", - "billing_city": "Colombes", - "billing_state": "Île-de-France", - "billing_zip": "92700", - "billing_country": "FR" - } - } - ``` - ### GoCardless with IBAN - ```json - { - "payment_profile": { - "customer_id": "24907598", - "bank_name": "French Bank", - "bank_iban": "FR1420041010050500013M02606", - "payment_type": "bank_account", - "billing_address": "20 Place de la Gare", - "billing_city": "Colombes", - "billing_state": "Île-de-France", - "billing_zip": "92700", - "billing_country": "FR" - } - } - ``` - ### Importing GoCardless - If the customer, bank account, and mandate already exist in - GoCardless, a payment profile can be created by using the IDs. In - order to create masked versions of `bank_account_number` and - `bank_routing_number` that are used to display within Advanced Billing - Admin UI, you can pass the last four digits for this fields which then - will be saved in this form `XXXX[four-provided-digits]`. - ```json - { - "payment_profile": { - "customer_id": "24907598", - "customer_vault_token": [Existing GoCardless Customer ID] - "vault_token": [Existing GoCardless Mandate ID], - "current_vault": "gocardless", - "bank_name": "French Bank", - "bank_account_number": [Last Four Of The Existing Account Number - or IBAN if applicable], - "bank_routing_number": [Last Four Of The Existing Routing Number], - "payment_type": "bank_account", - "billing_address": "20 Place de la Gare", - "billing_city": "Colombes", - "billing_state": "Île-de-France", - "billing_zip": "92700", - "billing_country": "FR" - } - } - ``` - ## SEPA Direct Debit - For more information on Stripe SEPA Direct Debit, please view the - following resources: - + [Full documentation on Stripe SEPA Direct - Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Strip - e-SEPA-and-BECS-Direct-Debit) - + [Using Chargify.js with Stripe Direct Debit - minimal + + [Chargify.js with Stripe Direct Debit - minimal example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl es#h_01K0PJ15QQFKKN8Z7B7DZ9AJS5) - + [Using Chargify.js with Stripe Direct Debit - full + + [Chargify.js with Stripe Direct Debit - full example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl es#h_01K0PJ15QRECQQ4ECS3ZA55GY7) - ### Stripe SEPA Direct Debit Payment Profiles - The following example creates a customer, bank account and mandate in - Stripe: - ```json - { - "payment_profile": { - "customer_id": "24907598", - "bank_name": "Deutsche bank", - "bank_iban": "DE89370400440532013000", - "payment_type": "bank_account", - "billing_address": "Test", - "billing_city": "Berlin", - "billing_state": "Brandenburg", - "billing_zip": "12345", - "billing_country": "DE" - } - } - ``` - ## Stripe BECS Direct Debit - For more information on Stripe BECS Direct Debit, please view the - following resources: - + [Full documentation on Stripe BECS Direct - Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Strip - e-SEPA-and-BECS-Direct-Debit) - + [Using Chargify.js with Stripe BECS Direct Debit - minimal + + [Chargify.js with Stripe BECS Direct Debit - minimal example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0Nj AzNDIy-examples#minimal-example-with-sepa-or-becs-direct-debit-stripe-g ateway) - + [Using Chargify.js with Stripe BECS Direct Debit - full + + [Chargify.js with Stripe BECS Direct Debit - full example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0Nj AzNDIy-examples#full-example-with-sepa-direct-debit-stripe-gateway) - ### Stripe BECS Direct Debit Payment Profiles - The following example creates a customer, bank account and mandate in - Stripe: - ```json - { - "payment_profile": { - "customer_id": "24907598", - "bank_name": "Australian bank", - "bank_branch_code": "000000", - "bank_account_number": "000123456" - "payment_type": "bank_account", - "billing_address": "Test", - "billing_city": "Stony Rise", - "billing_state": "Tasmania", - "billing_zip": "12345", - "billing_country": "AU" - } - } - ``` - ## Stripe BACS Direct Debit - Contact the support team to enable this payment method. - For more information on Stripe BACS Direct Debit, please view the - following resources: + + [Full documentation on + GoCardless](https://maxio.zendesk.com/hc/en-us/articles/24176159136909- + GoCardless) + + [Full documentation on Stripe SEPA Direct + Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Strip + e-SEPA-and-BECS-Direct-Debit) + + [Full documentation on Stripe BECS Direct + Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Strip + e-SEPA-and-BECS-Direct-Debit) + [Full documentation on Stripe BACS Direct Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Strip e-SEPA-and-BECS-Direct-Debit) - ### Stripe BACS Direct Debit Payment Profiles - The following example creates a customer, bank account and mandate in - Stripe: - ```json - { - "payment_profile": { - "customer_id": "24907598", - "bank_name": "British bank", - "bank_branch_code": "108800", - "bank_account_number": "00012345" - "payment_type": "bank_account", - "billing_address": "Test", - "billing_city": "London", - "billing_state": "LND", - "billing_zip": "12345", - "billing_country": "GB" - } - } - ``` - ## 3D Secure - Checkout - It may happen that a payment needs 3D Secure Authentication when the - payment profile is created; this is referred to in our help docs as a - [post-authentication + ## 3D Secure Authentication during payment profile creation. + When a payment requires 3D Secure Authentication to adhear to Strong + Customer Authentication (SCA) during payment profile creation, the + request enters a [post-authentication flow](https://maxio.zendesk.com/hc/en-us/articles/24176278996493-Testin g-Implementing-3D-Secure#psd2-flows-pre-authentication-and-post-authent - ication). The server returns `422 Unprocessable Entity` in this case + ication). In this case, a 422 Unprocessable Entity status is returned with the following response: ```json { @@ -315,43 +140,40 @@ def create_payment_profile(self, ``` To let the customer go through 3D Secure Authentication, they need to be redirected to the URL specified in `action_link`. - Optionally, you can specify `callback_url` parameter in the - `action_link` URL if you’d like to be notified about the result of 3D - Secure Authentication. The `callback_url` will return the following - information: + Optionally, you can specify the `callback_url` parameter in the + `action_link` URL to receive notification about the result of 3D + Secure Authentication. + The `callback_url` will return the following information: - whether the authentication was successful (`success`) - the payment profile ID (`payment_profile_id`) - Lastly, you can also specify a `redirect_url` parameter within the - `action_link` URL if you’d like to redirect a customer back to your - site. - It is not possible to use `action_link` in an iframe inside a custom - application. You have to redirect the customer directly to the - `action_link`, then, to be notified about the result, use - `redirect_url` or `callback_url`. + You can also specify a `redirect_url` parameter in the `action_link` + URL to redirect the customer back to your site. + You cannot use action_link in an iframe inside a custom application. + You must redirect the customer directly to the `action_link` and use + the `redirect_url` or `callback_url` to be notified of the result. The final URL that you send a customer to complete 3D Secure may resemble the following, where the first half is the `action_link` and the second half contains a `redirect_url` and `callback_url`: - `https://checkout-test.chargifypay.test/3d-secure/checkout/pay_uerzhsxd - 5uhkbodx5jhvkg6yeu?one_time_token_id=93&callback_url=http://localhost:4 - 000&redirect_url=https://yourpage.com` + `https://checkout-test.chargifypay.test/3d-secure/checkout/pay_uerzhsx + d5uhkbodx5jhvkg6yeu?one_time_token_id=93&callback_url=http://localhost: + 4000&redirect_url=https://yourpage.com` ### Example Redirect Flow - You may wish to redirect customers to different pages depending on - whether their SCA was performed successfully. Here's an example flow - to use as a reference: - 1. Create a payment profile via API; it requires 3DS - 2. You receive a `action_link` in the response. + Here's an example flow to redirect customers to different pages + depending on whether SCA was performed successfully: + 1. Create a payment profile via the API; it requires 3DS. + 2. You receive an `action_link` in the response. 3. Use this `action_link` to, for example, connect with your internal - resources or generate a session_id - 4. Include 1 of those attributes inside the `callback_url` and - `redirect_url` to be aware which “session” this applies to + resources or generate a `session_id`. + 4. Include one of those attributes inside the `callback_url` and + `redirect_url` to be aware which “session” this applies to. 5. Redirect the customer to the `action_link` with `callback_url` and `redirect_url` applied - 6. After the customer finishes 3DS authentication, we let you know the - result by making a request to applied `callback_url`. + 6. After the customer completes 3DS authentication, we notify you of + the result via the applied `callback_url`. 7. After that, we redirect the customer to the `redirect_url`; at this - point the result of authentication is known + point the result of authentication is known. 8. Optionally, you can use the applied "msg" param in the - `redirect_url` to determine whether it was successful or not + `redirect_url` to determine if the redirect was successful. Args: body (CreatePaymentProfileRequest, optional): When following the @@ -466,8 +288,8 @@ def read_payment_profile(self, Using the GET method you can retrieve a Payment Profile identified by its unique ID. - Please note that a different JSON object will be returned if the card - method on file is a bank account. + Note that a different JSON object will be returned if the card method + on file is a bank account. ### Response for Bank Account Example response for Bank Account: ``` diff --git a/advancedbilling/controllers/product_families_controller.py b/advancedbilling/controllers/product_families_controller.py index a4774504..f784da24 100644 --- a/advancedbilling/controllers/product_families_controller.py +++ b/advancedbilling/controllers/product_families_controller.py @@ -32,8 +32,7 @@ def list_products_for_product_family(self, options=dict()): """Does a GET request to /product_families/{product_family_id}/products.json. - This method allows to retrieve a list of Products belonging to a - Product Family. + Retrieves a list of Products belonging to a Product Family. Args: options (dict, optional): Key-value pairs for any of the @@ -156,9 +155,9 @@ def create_product_family(self, body=None): """Does a POST request to /product_families.json. - This method will create a Product Family within your Advanced Billing - site. Create a Product Family to act as a container for your products, - components and coupons. + Creates a Product Family within your Advanced Billing site. Create a + Product Family to act as a container for your products, components and + coupons. Full documentation on how Product Families operate within the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24261098936205-Produ @@ -204,7 +203,7 @@ def list_product_families(self, options=dict()): """Does a GET request to /product_families.json. - This method allows to retrieve a list of Product Families for a site. + Retrieve a list of Product Families for a site. Args: options (dict, optional): Key-value pairs for any of the @@ -283,8 +282,8 @@ def read_product_family(self, id): """Does a GET request to /product_families/{id}.json. - This method allows to retrieve a Product Family via the - `product_family_id`. The response will contain a Product Family object. + Retrieves a Product Family via the `product_family_id`. The response + will contain a Product Family object. The product family can be specified either with the id number, or with the `handle:my-family` format. diff --git a/advancedbilling/controllers/product_price_points_controller.py b/advancedbilling/controllers/product_price_points_controller.py index 6221930a..534ec884 100644 --- a/advancedbilling/controllers/product_price_points_controller.py +++ b/advancedbilling/controllers/product_price_points_controller.py @@ -39,9 +39,9 @@ def create_product_price_point(self, body=None): """Does a POST request to /products/{product_id}/price_points.json. - [Product Price Point - Documentation](https://maxio.zendesk.com/hc/en-us/articles/242611119477 - 89-Product-Price-Points) + Creates a Product Price Point. See the [Product Price + Point](https://maxio.zendesk.com/hc/en-us/articles/24261111947789-Produ + ct-Price-Points) documentation for details. Args: product_id (int | str): The id or handle of the product. When @@ -91,7 +91,7 @@ def list_product_price_points(self, options=dict()): """Does a GET request to /products/{product_id}/price_points.json. - Use this endpoint to retrieve a list of product price points. + Retrieves a list of product price points. Args: options (dict, optional): Key-value pairs for any of the @@ -183,8 +183,8 @@ def update_product_price_point(self, body=None): """Does a PUT request to /products/{product_id}/price_points/{price_point_id}.json. - Use this endpoint to update a product price point. - Note: Custom product price points are not able to be updated. + Updates a product price point. + Note: Custom product price points cannot be updated. Args: product_id (int | str): The id or handle of the product. When @@ -316,7 +316,7 @@ def archive_product_price_point(self, price_point_id): """Does a DELETE request to /products/{product_id}/price_points/{price_point_id}.json. - Use this endpoint to archive a product price point. + Archives a product price point. Args: product_id (int | str): The id or handle of the product. When @@ -420,10 +420,9 @@ def promote_product_price_point_to_default(self, price_point_id): """Does a PATCH request to /products/{product_id}/price_points/{price_point_id}/default.json. - Use this endpoint to make a product price point the default for the + Sets a product price point as the default for the product. + Note: Custom product price points cannot be set as the default for a product. - Note: Custom product price points are not able to be set as the - default for a product. Args: product_id (int): The Advanced Billing id of the product to which @@ -471,8 +470,7 @@ def bulk_create_product_price_points(self, body=None): """Does a POST request to /products/{product_id}/price_points/bulk.json. - Use this endpoint to create multiple product price points in one - request. + Creates multiple product price points in one request. Args: product_id (int): The Advanced Billing id of the product to which @@ -523,8 +521,8 @@ def create_product_currency_prices(self, body=None): """Does a POST request to /product_price_points/{product_price_point_id}/currency_prices.json. - This endpoint allows you to create currency prices for a given - currency that has been defined on the site level in your settings. + Creates currency prices for a given currency that has been defined on + the site level in your settings. When creating currency prices, they need to mirror the structure of your primary pricing. If the product price point defines a trial and/or setup fee, each currency must also define a trial and/or setup @@ -580,13 +578,13 @@ def update_product_currency_prices(self, body=None): """Does a PUT request to /product_price_points/{product_price_point_id}/currency_prices.json. - This endpoint allows you to update the `price`s of currency prices for - a given currency that exists on the product price point. + Updates the `price`s of currency prices for a given currency that + exists on the product price point. When updating the pricing, it needs to mirror the structure of your primary pricing. If the product price point defines a trial and/or setup fee, each currency must also define a trial and/or setup fee. - Note: Currency Prices are not able to be updated for custom product - price points. + Note: Currency Prices cannot be updated for custom product price + points. Args: product_price_point_id (int): The Advanced Billing id of the diff --git a/advancedbilling/controllers/products_controller.py b/advancedbilling/controllers/products_controller.py index aa024c25..cd8f6c3a 100644 --- a/advancedbilling/controllers/products_controller.py +++ b/advancedbilling/controllers/products_controller.py @@ -31,7 +31,8 @@ def create_product(self, body=None): """Does a POST request to /product_families/{product_family_id}/products.json. - Use this method to create a product within your Advanced Billing site. + Creates a product in your Advanced Billing site. + See the following product docuemation for more information: + [Products Documentation](https://maxio.zendesk.com/hc/en-us/articles/242610901176 45-Products-Overview) @@ -86,8 +87,7 @@ def read_product(self, product_id): """Does a GET request to /products/{product_id}.json. - This endpoint allows you to read the current details of a product that - you've created in Advanced Billing. + Reads the current details of a product. Args: product_id (int): The Advanced Billing id of the product @@ -127,7 +127,7 @@ def update_product(self, body=None): """Does a PUT request to /products/{product_id}.json. - Use this method to change aspects of an existing product. + Updates aspects of an existing product. ### Input Attributes Update Notes + `update_return_params` The parameters we will append to your `update_return_url`. See Return URLs and Parameters @@ -183,9 +183,8 @@ def archive_product(self, product_id): """Does a DELETE request to /products/{product_id}.json. - Sending a DELETE request to this endpoint will archive the product. - All current subscribers will be unffected; their subscription/purchase - will continue to be charged monthly. + Archives the product. All current subscribers will be unffected; their + subscription/purchase will continue to be charged monthly. This will restrict the option to chose the product for purchase via the Billing Portal, as well as disable Public Signup Pages for the product. @@ -228,7 +227,7 @@ def read_product_by_handle(self, api_handle): """Does a GET request to /products/handle/{api_handle}.json. - This method allows to retrieve a Product object by its `api_handle`. + Retrieves a Product object by its `api_handle`. Args: api_handle (str): The handle of the product diff --git a/advancedbilling/controllers/proforma_invoices_controller.py b/advancedbilling/controllers/proforma_invoices_controller.py index 40c8af6a..2e7272c6 100644 --- a/advancedbilling/controllers/proforma_invoices_controller.py +++ b/advancedbilling/controllers/proforma_invoices_controller.py @@ -199,8 +199,7 @@ def create_proforma_invoice(self, response. If the information becomes outdated, simply void the old proforma invoice and generate a new one. If you would like to preview the next billing amounts without - generating a full proforma invoice, please use the renewal preview - endpoint. + generating a full proforma invoice, use the renewal preview endpoint. ## Restrictions Proforma invoices are only available on Relationship Invoicing sites. To create a proforma invoice, the subscription must not be in a group, diff --git a/advancedbilling/controllers/sales_commissions_controller.py b/advancedbilling/controllers/sales_commissions_controller.py index 9008c860..b5207c99 100644 --- a/advancedbilling/controllers/sales_commissions_controller.py +++ b/advancedbilling/controllers/sales_commissions_controller.py @@ -44,7 +44,7 @@ def list_sales_commission_settings(self, Access to the Sales Commission API endpoints is available to users with financial access, where the seller has the Advanced Analytics component enabled. For further information on getting access to - Advanced Analytics please contact Maxio support. + Advanced Analytics contact Maxio support. > Note: The request is at seller level, it means `<>` variable will be replaced by `app` @@ -136,7 +136,7 @@ def list_sales_reps(self, Access to the Sales Commission API endpoints is available to users with financial access, where the seller has the Advanced Analytics component enabled. For further information on getting access to - Advanced Analytics please contact Maxio support. + Advanced Analytics contact Maxio support. > Note: The request is at seller level, it means `<>` variable will be replaced by `app` @@ -233,7 +233,7 @@ def read_sales_rep(self, Access to the Sales Commission API endpoints is available to users with financial access, where the seller has the Advanced Analytics component enabled. For further information on getting access to - Advanced Analytics please contact Maxio support. + Advanced Analytics contact Maxio support. > Note: The request is at seller level, it means `<>` variable will be replaced by `app` diff --git a/advancedbilling/controllers/subscription_components_controller.py b/advancedbilling/controllers/subscription_components_controller.py index 65953696..a2c43b62 100644 --- a/advancedbilling/controllers/subscription_components_controller.py +++ b/advancedbilling/controllers/subscription_components_controller.py @@ -781,49 +781,46 @@ def create_usage(self, body=None): """Does a POST request to /subscriptions/{subscription_id_or_reference}/components/{component_id}/usages.json. - ## Documentation + Records an instance of metered or prepaid usage for a subscription. + You can report metered or prepaid usage to Advanced Billing as often + as you wish. You can report usage as it happens or periodically, such + as each night or once per billing period. Full documentation on how to create Components in the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24261149711501-Creat e-Edit-and-Archive-Components). Additionally, for information on how - to record component usage against a subscription, please see the - following resources: - + [Recording Metered Component + to record component usage against a subscription, see the following + resources: + It is not possible to record metered usage for more than one component + at a time Usage should be reported as one API call per component on a + single subscription. For example, to record that a subscriber has sent + both an SMS Message and an Email, send an API call for each. + See the following product documention articles for more information: + - [Create and Manage + Components](https://maxio.zendesk.com/hc/en-us/articles/24261149711501- + Create-Edit-and-Archive-Components). A + - [Recording Metered Component Usage](https://maxio.zendesk.com/hc/en-us/articles/24251890500109-Repor ting-Component-Allocations#reporting-metered-component-usage) - + [Reporting Prepaid Component + - [Reporting Prepaid Component Status](https://maxio.zendesk.com/hc/en-us/articles/24251890500109-Repo rting-Component-Allocations#reporting-prepaid-component-status) - You may choose to report metered or prepaid usage to Advanced Billing - as often as you wish. You may report usage as it happens. You may also - report usage periodically, such as each night or once per billing - period. If usage events occur in your system very frequently (on the - order of thousands of times an hour), it is best to accumulate usage - into batches on your side, and then report those batches less - frequently, such as daily. This will ensure you remain below any API - throttling limits. If your use case requires higher rates of usage - reporting, we recommend utilizing Events Based Components. - ## Create Usage for Subscription - This endpoint allows you to record an instance of metered or prepaid - usage for a subscription. The `quantity` from usage for each component - is accumulated to the `unit_balance` on the [Component Line - Item](./b3A6MTQxMDgzNzQ-read-subscription-component) for the + The `quantity` from usage for each component is accumulated to the + `unit_balance` on the [Component Line + Item]($e/Subscription%20Components/readSubscriptionComponent) for the subscription. ## Price Point ID usage If you are using price points, for metered and prepaid usage - components, Advanced Billing gives you the option to specify a price + components Advanced Billing gives you the option to specify a price point in your request. You do not need to specify a price point ID. If a price point is not included, the default price point for the component will be used when the usage is recorded. - If an invalid `price_point_id` is submitted, the endpoint will return - an error. ## Deducting Usage - In the event that you need to reverse a previous usage report or - otherwise deduct from the current usage balance, you may provide a - negative quantity. + If you need to reverse a previous usage report or otherwise deduct + from the current usage balance, you can provide a negative quantity. Example: - Previously recorded: + Previously recorded quantity was 5000: ```json { "usage": { @@ -832,8 +829,7 @@ def create_usage(self, } } ``` - At this point, `unit_balance` would be `5000`. To reduce the balance - to `0`, POST the following payload: + To reduce the quantity to `0`, POST the following payload: ```json { "usage": { @@ -845,12 +841,6 @@ def create_usage(self, The `unit_balance` has a floor of `0`; negative unit balances are never allowed. For example, if the usage balance is 100 and you deduct 200 units, the unit balance would then be `0`, not `-100`. - ## FAQ - Q. Is it possible to record metered usage for more than one component - at a time? - A. No. Usage should be reported as one API call per component on a - single subscription. For example, to record that a subscriber has sent - both an SMS Message and an Email, send an API call for each. Args: subscription_id_or_reference (int | str): Either the Advanced diff --git a/advancedbilling/controllers/subscription_group_status_controller.py b/advancedbilling/controllers/subscription_group_status_controller.py index 715f3c88..d14fd73c 100644 --- a/advancedbilling/controllers/subscription_group_status_controller.py +++ b/advancedbilling/controllers/subscription_group_status_controller.py @@ -30,13 +30,13 @@ def cancel_subscriptions_in_group(self, body=None): """Does a POST request to /subscription_groups/{uid}/cancel.json. - This endpoint will immediately cancel all subscriptions within the - specified group. The group is identified by it's `uid` passed in the - URL. To successfully cancel the group, the primary subscription must - be on automatic billing. The group members as well must be on - automatic billing or they must be prepaid. - In order to cancel a subscription group while also charging for any - unbilled usage on metered or prepaid components, the + Cancels all subscriptions within the specified group immediately. The + group is identified by the `uid` that is passed in the URL. To + successfully cancel the group, the primary subscription must be on + automatic billing. The group members must be on automatic billing or + prepaid. + To cancel a subscription group while also charging for any unbilled + usage on metered or prepaid components, the `charge_unbilled_usage=true` parameter must be included in the request. Args: @@ -79,7 +79,7 @@ def initiate_delayed_cancellation_for_group(self, This endpoint will schedule all subscriptions within the specified group to be canceled at the end of their billing period. The group is - identified by it's uid passed in the URL. + identified by its uid passed in the URL. All subscriptions in the group must be on automatic billing in order to successfully cancel them, and the group must not be in a "past_due" state. diff --git a/advancedbilling/controllers/subscription_groups_controller.py b/advancedbilling/controllers/subscription_groups_controller.py index 84bafb70..52402425 100644 --- a/advancedbilling/controllers/subscription_groups_controller.py +++ b/advancedbilling/controllers/subscription_groups_controller.py @@ -51,6 +51,12 @@ def signup_with_subscription_group(self, When passing product to a subscription you can use either `product_id` or `product_handle` or `offer_id`. You can also use `custom_price` instead. + The subscription request examples below will be split into two + sections. + The first section, "Subscription Customization", will focus on passing + different information with a subscription, such as components, + calendar billing, and custom fields. These examples will presume you + are using a secure chargify_token generated by Chargify.js. Args: body (SubscriptionGroupSignupRequest, optional): The request body @@ -412,9 +418,9 @@ def add_subscription_to_group(self, part of a subscription group, a new group will be created and the subscription will become part of the group with the specified target customer set as the responsible payer for the group's subscriptions. - **Please Note:** In order to add an existing subscription to a - subscription group, it must belong to either the same customer record - as the target, or be within the same customer hierarchy. + **Note:** In order to add an existing subscription to a subscription + group, it must belong to either the same customer record as the + target, or be within the same customer hierarchy. Rather than specifying a customer, the `target` parameter could instead simply have a value of * `"self"` which indicates the subscription will be paid for not by @@ -423,8 +429,8 @@ def add_subscription_to_group(self, subscribing customer's parent within a customer hierarchy, or * `"eldest"` which indicates the subscription will be paid for by the root-level customer in the subscribing customer's hierarchy. - To create a new subscription into a subscription group, please - reference the following: + To create a new subscription into a subscription group, reference the + following: [Create Subscription in a Subscription Group](https://developers.chargify.com/docs/api-docs/d571659cf0f24-crea te-subscription#subscription-in-a-subscription-group) diff --git a/advancedbilling/controllers/subscription_invoice_account_controller.py b/advancedbilling/controllers/subscription_invoice_account_controller.py index 2cb811d9..608c8831 100644 --- a/advancedbilling/controllers/subscription_invoice_account_controller.py +++ b/advancedbilling/controllers/subscription_invoice_account_controller.py @@ -86,7 +86,7 @@ def create_prepayment(self, amount will be collected using the default credit card payment profile and applied to the prepayment account balance. This is especially useful for manual replenishment of prepaid subscriptions. - Please note that you **can't** pass `amount_in_cents`. + Note that passing `amount_in_cents` is now allowed. Args: subscription_id (int): The Chargify id of the subscription diff --git a/advancedbilling/controllers/subscription_products_controller.py b/advancedbilling/controllers/subscription_products_controller.py index 380a3244..2324df8e 100644 --- a/advancedbilling/controllers/subscription_products_controller.py +++ b/advancedbilling/controllers/subscription_products_controller.py @@ -52,13 +52,13 @@ def migrate_subscription_product(self, [here](https://maxio.zendesk.com/hc/en-us/articles/24181589372429-Data- Migration-to-Advanced-Billing). ## Failed Migrations - One of the most common ways that a migration can fail is when the - attempt is made to migrate a subscription to it's current product. - Please be aware of this issue! + Importaint note: One of the most common ways that a migration can fail + is when the attempt is made to migrate a subscription to its current + product. ## Migration 3D Secure - Stripe - It may happen that a payment needs 3D Secure Authentication when the - subscription is migrated to a new product; this is referred to in our - help docs as a [post-authentication + When a payment requires 3D Secure Authentication to adhear to Strong + Customer Authentication (SCA) when the subscription is migrated to a + new product, the request enters a [post-authentication flow](https://maxio.zendesk.com/hc/en-us/articles/24176278996493-Testin g-Implementing-3D-Secure#psd2-flows-pre-authentication-and-post-authent ication). The server returns `422 Unprocessable Entity` in this case @@ -109,8 +109,8 @@ def migrate_subscription_product(self, s://yourpage.com` ### Example Redirect Flow You may wish to redirect customers to different pages depending on - whether their SCA was performed successfully. Here's an example flow - to use as a reference: + whether SCA was performed successfully. Here's an example flow to use + as a reference: 1. Create a migration via API; it requires 3DS 2. You receive a `gateway_payment_id` in the `action_link` along other params in the response. diff --git a/advancedbilling/controllers/subscription_status_controller.py b/advancedbilling/controllers/subscription_status_controller.py index d9372b9f..5d7297d2 100644 --- a/advancedbilling/controllers/subscription_status_controller.py +++ b/advancedbilling/controllers/subscription_status_controller.py @@ -182,8 +182,8 @@ def pause_subscription(self, This will place the subscription in the on_hold state and it will not renew. ## Limitations - You may not place a subscription on hold if the `next_billing` date is - within 24 hours. + You may not place a subscription on hold if the `next_billing_at` date + is within 24 hours. Args: subscription_id (int): The Chargify id of the subscription @@ -290,10 +290,9 @@ def reactivate_subscription(self, how to reactivate subscriptions through the application, see [reactivation](https://maxio.zendesk.com/hc/en-us/articles/242521095036 29-Reactivating-and-Resuming). - **Please note: The term - "resume" is used also during another process in Advanced Billing. This - occurs when an on-hold subscription is "resumed". This returns the - subscription to an active state.** + **Note: The term "resume" is used also during another process in + Advanced Billing. This occurs when an on-hold subscription is + "resumed". This returns the subscription to an active state.** + The response returns the subscription object in the `active` or `trialing` state. + The `canceled_at` and `cancellation_message` fields do not have @@ -620,7 +619,7 @@ def preview_renewal(self, of how much your customer will be charged on their next renewal. The "Next Billing" amount and "Next Billing" date are already represented in the UI on each Subscriber's Summary. For more - information, please see our documentation + information, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24252493695757-Subsc riber-Interface-Overview). ## Optional Component Fields diff --git a/advancedbilling/controllers/subscriptions_controller.py b/advancedbilling/controllers/subscriptions_controller.py index 136c4a9f..3298084d 100644 --- a/advancedbilling/controllers/subscriptions_controller.py +++ b/advancedbilling/controllers/subscriptions_controller.py @@ -38,792 +38,40 @@ def create_subscription(self, body=None): """Does a POST request to /subscriptions.json. - Full documentation on how subscriptions operate within Advanced - Billing can be located under the following topics: - + [Subscriptions - Reference](https://maxio.zendesk.com/hc/en-us/articles/24251526991757-S - ubscription-Overview) - + [Subscriptions - Actions](https://maxio.zendesk.com/hc/en-us/articles/24251983024653-Sub - scription-Actions-Overview) - + [Subscription - Cancellation](https://maxio.zendesk.com/hc/en-us/articles/2425195777882 - 9-Cancel-Subscriptions) - + [Subscription - Reactivation](https://maxio.zendesk.com/hc/en-us/articles/2425210950362 - 9-Reactivating-and-Resuming) - + [Subscription - Import](https://maxio.zendesk.com/hc/en-us/articles/24251489107213-Impo - rts) - When creating a subscription, you must specify a product and a - customer. Credit card details may be required, depending on the - options for the Product being subscribed ([see Product - Options](https://maxio.zendesk.com/hc/en-us/articles/24261076617869-Pro - duct-Editing)). - The product may be specified by `product_id` or by `product_handle` - (API Handle). In similar fashion, to pass a particular product price - point, you may either use `product_price_point_handle` or + Creates a Subscription for a customer and product + Specify the product with `product_id` or `product_handle`. To set a + specific product pricepPoint, use `product_price_point_handle` or `product_price_point_id`. - An existing customer may be specified by a `customer_id` (ID within - Advanced Billing) or a `customer_reference` (unique value within your - app that you have shared with Advanced Billing via the reference - attribute on a customer). You may also pass in an existing payment - profile for that customer with `payment_profile_id`. A new customer - may be created by providing `customer_attributes`. - Credit card details may be required, depending on the options for the - product being subscribed. The product can be specified by `product_id` - or by `product_handle` (API Handle). - If you are creating a subscription with a payment profile, the - attribute to send will be `credit_card_attributes` or - `bank_account_attributes` for ACH and Direct Debit. That said, when - you read the subscription after creation, we return the profile - details under `credit_card` or `bank_account`. - ## Bulk creation of subscriptions - Bulk creation of subscriptions is currently not supported. For - scenarios where multiple subscriptions must be added, particularly - when assigning to the same subscription group, it is essential to - switch to a single-threaded approach. - To avoid data conflicts or inaccuracies, incorporate a sleep interval - between requests. - While this single-threaded approach may impact performance, it ensures - data consistency and accuracy in cases where concurrent creation - attempts could otherwise lead to issues with subscription alignment - and integrity. - ## Taxable Subscriptions - If your intent is to charge your subscribers tax via [Avalara - Taxes](https://maxio.zendesk.com/hc/en-us/articles/24287043035661-Avala - ra-VAT-Tax) or [Custom - Taxes](https://maxio.zendesk.com/hc/en-us/articles/24287044212749-Custo - m-Taxes), there are a few considerations to be made regarding - collecting subscription data. - For subscribers to be eligible to be taxed, the following information - for the `customer` object or `payment_profile` object must by supplied: - + A subscription to a [taxable - product](https://maxio.zendesk.com/hc/en-us/articles/24261076617869-Pro - duct-Editing#tax-settings) - + [Full valid billing or shipping - address](https://maxio.zendesk.com/hc/en-us/articles/24287008131853-Adv - anced-Billing-Managed-Sales-Tax#full-address-required-for-taxable-subsc - riptions) to identify the tax locale - + The portion of the address that houses the [state - information](https://maxio.zendesk.com/hc/en-us/articles/24287008131853 - -Advanced-Billing-Managed-Sales-Tax#required-state-format-for-taxable-s - ubscriptions) of either adddress must adhere to the ISO standard of a - 2-3 character limit/format. - + The portion of the address that houses the [country - information](https://maxio.zendesk.com/hc/en-us/articles/24287008131853 - -Advanced-Billing-Managed-Sales-Tax#required-country-format-for-taxable - -subscriptions) must adhere to the ISO standard of a 2 character - limit/format. - ## Subscription Request Examples - The subscription examples below will be split into two sections. - The first section, "Subscription Customization", will focus on passing - different information with a subscription, such as components, - calendar billing, and custom fields. These examples will presume you - are using a secure `chargify_token` generated by Chargify.js. - The second section, "Passing Payment Information", will focus on - passing payment information into Advanced Billing. Please be aware - that collecting and sending Advanced Billing raw card details - requires PCI compliance on your end; these examples are provided - as guidance. If your business is not PCI compliant, we recommend using - Chargify.js to collect credit cards or bank accounts. - # Subscription Customization - ## With Components - Different components require slightly different data. For example, - quantity-based and on/off components accept `allocated_quantity`, - while metered components accept `unit_balance`. - When creating a subscription with a component, a `price_point_id` can - be passed in along with the `component_id` to specify which price - point to use. If not passed in, the default price point will be used. - Note: if an invalid `price_point_id` is used, the subscription will - still proceed but will use the component's default price point. - Components and their price points may be added by ID or by handle. See - the example request body labeled "Components By Handle - (Quantity-Based)"; the format will be the same for other component - types. - ## With Coupon(s) - Pass an array of `coupon_codes`. See the example request body "With - Coupon". - ## With Manual Invoice Collection - The `invoice` collection method works only on legacy Statement - Architecture. - On Relationship Invoicing Architecture use the `remittance` collection - method. - ## Prepaid Subscription - A prepaid subscription can be created with the usual subscription - creation parameters, specifying `prepaid` as the - `payment_collection_method` and including a nested - `prepaid_configuration`. - After a prepaid subscription has been created, additional funds can be - manually added to the prepayment account through the [Create - Prepayment - Endpoint](https://developers.chargify.com/docs/api-docs/7ec482de77ba7-c - reate-prepayment). - Prepaid subscriptions do not work on legacy Statement Architecture. - ## With Metafields - Metafields can either attach to subscriptions or customers. Metafields - are popuplated with the supplied metadata to the resource specified. - If the metafield doesn't exist yet, it will be created on-the-fly. - ## With Custom Pricing - Custom pricing is pricing specific to the subscription in question. - Create a subscription with custom pricing by passing pricing - information instead of a price point. - For a custom priced product, pass the custom_price object in place of - `product_price_point_id`. For a custom priced component, pass the - `custom_price` object within the component object. - Custom prices and price points can exist in harmony on a subscription. - # Passing Payment Information - ## Subscription with Chargify.js token - The `chargify_token` can be obtained using + Identify an existing customer with `customer_id` or + `customer_reference`. Optionally, include an existing payment profile + using `payment_profile_id`. To create a new customer, pass + customer_attributes. + Select an option from the **Request Examples** drop-down on the right + side of the portal to see examples of common scenarios for creating + subscriptions. + Payment information may be required to create a subscription, + depending on the options for the Product being subscribed. See + [product + options](https://docs.maxio.com/hc/en-us/articles/24261076617869-Edit-P + roducts) for more information. See the [Payments + Profile]($e/Payment%20Profiles/createPaymentProfile) endpoint for + details on payment parameters. + Do not use real card information for testing. See the Sites articles + that cover [testing your site + setup](https://docs.maxio.com/hc/en-us/articles/24250712113165-Testing- + Overview#testing-overview-0-0) for more details on testing in your + sandbox. + Note that collecting and sending raw card details in production + requires [PCI + compliance](https://docs.maxio.com/hc/en-us/articles/24183956938381-PCI + -Compliance#pci-compliance-0-0) on your end. If your business is not + PCI compliant, use [Chargify.js](https://docs.maxio.com/hc/en-us/articles/38163190843789-C - hargify-js-Overview#chargify-js-overview-0-0). The token represents - payment profile attributes that were provided by the customer in their - browser and stored at the payment gateway. - The `payment_type` attribute may either be `credit_card` or - `bank_account`, depending on the type of payment method being added. - If a bank account is being passed, the payment attributes should be - changed to `bank_account_attributes`. - ```json - { - "subscription": { - "product_handle": "pro-plan", - "customer_attributes": { - "first_name": "Joe", - "last_name": "Smith", - "email": "j.smith@example.com" - }, - "credit_card_attributes": { - "chargify_token": "tok_cwhvpfcnbtgkd8nfkzf9dnjn", - "payment_type": "credit_card" - } - } - } - ``` - ## Subscription with vault token - If you already have a customer and card stored in your payment - gateway, you may create a subscription with a `vault_token`. - Providing the last_four, card type and expiration date will allow the - card to be displayed properly in the Advanced Billing UI. - ```json - { - "subscription": { - "product_handle": "pro-plan", - "customer_attributes": { - "first_name": "Joe", - "last_name": "Smith", - "email": "j.smith@example.com" - }, - "credit_card_attributes": { - first_name: "Joe, - last_name: "Smith", - card_type: "visa", - expiration_month: "05", - expiration_year: "2025", - last_four: "1234", - vault_token: "12345abc", - current_vault: "braintree_blue" - } - } - ``` - ## Subscription with ACH as Payment Profile - ```json - { - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Joe", - "last_name": "Blow", - "email": "joe@example.com", - "zip": "02120", - "state": "MA", - "reference": "XYZ", - "phone": "(617) 111 - 0000", - "organization": "Acme", - "country": "US", - "city": "Boston", - "address_2": null, - "address": "123 Mass Ave." - }, - "bank_account_attributes": { - "bank_name": "Best Bank", - "bank_routing_number": "021000089", - "bank_account_number": "111111111111", - "bank_account_type": "checking", - "bank_account_holder_type": "business", - "payment_type": "bank_account" - } - } - } - ``` - ## Subscription with PayPal payment profile - ### With the nonce from Braintree JS - ```json - { "subscription": { - "product_handle":"test-product-b", - "customer_attributes": { - "first_name":"Amelia", - "last_name":"Johnson", - "email":"amelia@example.com", - "organization":"My Awesome Company" - }, - "payment_profile_attributes":{ - "paypal_email": "amelia@example.com", - "current_vault": "braintree_blue", - "payment_method_nonce":"abc123", - "payment_type":"paypal_account" - } - } - ``` - ### With the Braintree Customer ID as the vault token: - ```json - { "subscription": { - "product_handle":"test-product-b", - "customer_attributes": { - "first_name":"Amelia", - "last_name":"Johnson", - "email":"amelia@example.com", - "organization":"My Awesome Company" - }, - "payment_profile_attributes":{ - "paypal_email": "amelia@example.com", - "current_vault": "braintree_blue", - "vault_token":"58271347", - "payment_type":"paypal_account" - } - } - ``` - ## Subscription using GoCardless Bank Number - These examples creates a customer, bank account and mandate in - GoCardless. - For more information on GoCardless, please view the following two - resources: - + [Payment Profiles via API for - GoCardless](https://developers.chargify.com/docs/api-docs/1f10a4f170405 - -create-payment-profile#gocardless) - + [Full documentation on - GoCardless](https://maxio.zendesk.com/hc/en-us/articles/24176159136909- - GoCardless) - + [Using Chargify.js with GoCardless - minimal - example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl - es#h_01K0PJ15QQZKCER8CFK40MR6XJ) - + [Using Chargify.js with GoCardless - full - example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl - es#h_01K0PJ15QR09JVHWW0MCA7HVJV) - ```json - { - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "Royal Bank of France", - "bank_account_number": "0000000", - "bank_routing_number": "0003", - "bank_branch_code": "00006", - "payment_type": "bank_account", - "billing_address": "20 Place de la Gare", - "billing_city": "Colombes", - "billing_state": "Île-de-France", - "billing_zip": "92700", - "billing_country": "FR" - } - } - } - ``` - ## Subscription using GoCardless IBAN Number - ```json - { - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "French Bank", - "bank_iban": "FR1420041010050500013M02606", - "payment_type": "bank_account", - "billing_address": "20 Place de la Gare", - "billing_city": "Colombes", - "billing_state": "Île-de-France", - "billing_zip": "92700", - "billing_country": "FR" - } - } - } - ``` - ## Subscription using Stripe SEPA Direct Debit - For more information on Stripe Direct Debit, please view the following - two resources: - + [Payment Profiles via API for Stripe SEPA Direct - Debit](https://developers.chargify.com/docs/api-docs/1f10a4f170405-crea - te-payment-profile#sepa-direct-debit) - + [Full documentation on Stripe Direct - Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Strip - e-SEPA-and-BECS-Direct-Debit) - + [Using Chargify.js with Stripe SEPA or BECS Direct Debit - minimal - example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl - es#h_01K0PJ15QQFKKN8Z7B7DZ9AJS5) - + [Using Chargify.js with Stripe SEPA Direct Debit - full - example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl - es#h_01K0PJ15QR09JVHWW0MCA7HVJV) - ```json - { - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "Test Bank", - "bank_iban": "DE89370400440532013000", - "payment_type": "bank_account" - } - } - } - ``` - ## Subscription using Stripe BECS Direct Debit - For more information on Stripe Direct Debit, please view the following - two resources: - + [Payment Profiles via API for Stripe BECS Direct - Debit]($e/Payment%20Profiles/createPaymentProfile) - + [Full documentation on Stripe Direct - Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Strip - e-SEPA-and-BECS-Direct-Debit) - + [Using Chargify.js with Stripe SEPA, BECS or BACS Direct Debit - - minimal - example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl - es#h_01K0PJ15QQFKKN8Z7B7DZ9AJS5) - + [Using Chargify.js with Stripe BECS Direct Debit - full - example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl - es#h_01K0PJ15QRX4B1TYZKZD8ZND6D) - ```json - { - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "Test Bank", - "bank_branch_code": "000000", - "bank_account_number": "000123456", - "payment_type": "bank_account" - } - } - } - ``` - ## Subscription using Stripe BACS Direct Debit - For more information on Stripe Direct Debit, please view the following - two resources: - + [Payment Profiles via API for Stripe BACS Direct - Debit]($e/Payment%20Profiles/createPaymentProfile) - + [Full documentation on Stripe Direct - Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Strip - e-SEPA-and-BECS-Direct-Debit) - + [Using Chargify.js with Stripe SEPA, BECS or BACS Direct Debit - - minimal - example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl - es#h_01K0PJ15QQFKKN8Z7B7DZ9AJS5) - + [Using Chargify.js with Stripe BACS Direct Debit - full - example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Exampl - es#h_01K0PJ15QR7PA1DJ3XE9MD05FM) - ```json - { - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "Test Bank", - "bank_branch_code": "108800", - "bank_account_number": "00012345", - "payment_type": "bank_account", - "billing_address": "123 Main St.", - "billing_city": "London", - "billing_state": "LND", - "billing_zip": "W1A 1AA", - "billing_country": "GB" - } - } - } - ``` - ## 3D Secure - Stripe - It may happen that a payment needs 3D Secure Authentication when the - subscription is created; this is referred to in our help docs as a - [post-authentication - flow](https://maxio.zendesk.com/hc/en-us/articles/24176278996493-Testin - g-Implementing-3D-Secure#psd2-flows-pre-authentication-and-post-authent - ication). The server returns `422 Unprocessable Entity` in this case - with the following response: - ```json - { - "errors": [ - "Your card was declined. This transaction requires 3D secure - authentication." - ], - "gateway_payment_id": "pi_1F0aGoJ2UDb3Q4av7zU3sHPh", - "description": "This card requires 3D secure authentication. - Redirect the customer to the URL from the action_link attribute to - authenticate. Attach callback_url param to this URL if you want to be - notified about the result of 3D Secure authentication. Attach - redirect_url param to this URL if you want to redirect a customer back - to your page after 3D Secure authentication. Example: - https://mysite.chargify.com/3d-secure/pi_1FCm4RKDeye4C0XfbqquXRYm?one_t - ime_token_id=128&callback_url=https://localhost:4000&redirect_url=https - ://yourpage.com will do a POST request to https://localhost:4000 after - payment is authenticated and will redirect a customer to - https://yourpage.com after 3DS authentication.", - "action_link": - "http://acme.chargify.com/3d-secure/pi_1F0aGoJ2UDb3Q4av7zU3sHPh?one_tim - e_token_id=242" - } - ``` - To let the customer go through 3D Secure Authentication, they need to - be redirected to the URL specified in `action_link`. - Optionally, you can specify `callback_url` parameter in the - `action_link` URL if you’d like to be notified about the result of 3D - Secure Authentication. The `callback_url` will return the following - information: - - whether the authentication was successful (`success`) - - the gateway ID for the payment (`gateway_payment_id`) - - the subscription ID (`subscription_id`) - Lastly, you can also specify a `redirect_url` within the `action_link` - URL if you’d like to redirect a customer back to your site. - It is not possible to use `action_link` in an iframe inside a custom - application. You have to redirect the customer directly to the - `action_link`, then, to be notified about the result, use - `redirect_url` or `callback_url`. - The final URL that you send a customer to to complete 3D Secure may - resemble the following, where the first half is the `action_link` and - the second half contains a `redirect_url` and `callback_url`: - `https://mysite.chargify.com/3d-secure/pi_1FCm4RKDeye4C0XfbqquXRYm?one_ - time_token_id=128&callback_url=https://localhost:4000&redirect_url=http - s://yourpage.com` - ## 3D Secure - Checkout - It may happen that a payment needs 3D Secure Authentication when the - subscription is created; this is referred to in our help docs as a - [post-authentication - flow](https://maxio.zendesk.com/hc/en-us/articles/24176278996493-Testin - g-Implementing-3D-Secure#psd2-flows-pre-authentication-and-post-authent - ication). The server returns `422 Unprocessable Entity` in this case - with the following response: - ```json - { - "errors": [ - "Your card was declined. This transaction requires 3D secure - authentication." - ], - "gateway_payment_id": "pay_6gjofv7dlyrkpizlolsuspvtiu", - "description": "This card requires 3D secure authentication. - Redirect the customer to the URL from the action_link attribute to - authenticate. Attach callback_url param to this URL if you want to be - notified about the result of 3D Secure authentication. Attach - redirect_url param to this URL if you want to redirect a customer back - to your page after 3D Secure authentication. Example: - https://mysite.chargify.com/3d-secure/pay_6gjofv7dlyrkpizlolsuspvtiu?on - e_time_token_id=123&callback_url=https://localhost:4000&redirect_url=ht - tps://yourpage.com will do a POST request to https://localhost:4000 - after payment is authenticated and will redirect a customer to - https://yourpage.com after 3DS authentication.", - "action_link": - "http://mysite.chargify.com/3d-secure/pay_6gjofv7dlyrkpizlolsuspvtiu?on - e_time_token_id=123" - } - ``` - To let the customer go through 3D Secure Authentication, they need to - be redirected to the URL specified in `action_link`. - Optionally, you can specify `callback_url` parameter in the - `action_link` URL if you’d like to be notified about the result of 3D - Secure Authentication. The `callback_url` will return the following - information: - - whether the authentication was successful (`success`) - - the gateway ID for the payment (`gateway_payment_id`) - - the subscription ID (`subscription_id`) - Lastly, you can also specify a `redirect_url` parameter within the - `action_link` URL if you’d like to redirect a customer back to your - site. - It is not possible to use `action_link` in an iframe inside a custom - application. You have to redirect the customer directly to the - `action_link`, then, to be notified about the result, use - `redirect_url` or `callback_url`. - The final URL that you send a customer to complete 3D Secure may - resemble the following, where the first half is the `action_link` and - the second half contains a `redirect_url` and `callback_url`: - `https://mysite.chargify.com/3d-secure/pay_6gjofv7dlyrkpizlolsuspvtiu?o - ne_time_token_id=123&callback_url=https://localhost:4000&redirect_url=h - ttps://yourpage.com` - ### Example Redirect Flow - You may wish to redirect customers to different pages depending on - whether their SCA was performed successfully. Here's an example flow - to use as a reference: - 1. Create a subscription via API; it requires 3DS - 2. You receive a `gateway_payment_id` in the `action_link` along other - params in the response. - 3. Use this `gateway_payment_id` to, for example, connect with your - internal resources or generate a session_id - 4. Include 1 of those attributes inside the `callback_url` and - `redirect_url` to be aware which “session” this applies to - 5. Redirect the customer to the `action_link` with `callback_url` and - `redirect_url` applied - 6. After the customer finishes 3DS authentication, we let you know the - result by making a request to applied `callback_url`. - 7. After that, we redirect the customer to the `redirect_url`; at this - point the result of authentication is known - 8. Optionally, you can use the applied "msg" param in the - `redirect_url` to determine whether it was successful or not - ## Subscriptions Import - Subscriptions can be “imported” via the API to handle the following - scenarios: - + You already have existing subscriptions with specific start and - renewal dates that you would like to import to Advanced Billing - + You already have credit cards stored in your provider’s vault and - you would like to create subscriptions using those tokens - Before importing, you should have already set up your products to - match your offerings. Then, you can create Subscriptions via the API - just like you normally would, but using a few special attributes. - Full documentation on how import Subscriptions using the **import - tool** in the Advanced Billing UI can be located - [here](https://maxio.zendesk.com/hc/en-us/articles/24251489107213-Impor - ts). - ### Important Notices and Disclaimers regarding Imports - Before performing a bulk import of subscriptions via the API, we - suggest reading the [Subscriptions - Import](https://maxio.zendesk.com/hc/en-us/articles/24251489107213-Impo - rts) instructions to understand the repurcussions of a large import. - ### Subscription Input Attributes - The following _additional_ attributes to the subscription input - attributes make imports possible: `next_billing_at`, - `previous_billing_at`, and `import_mrr`. - ### Current Vault - If you are using a Legacy gateway such as "eWAY Rapid (Legacy)" or - "Stripe (Legacy)" then please contact Support for further instructions - on subscription imports. - ### Braintree Blue (Braintree v2) Imports - Braintree Blue is Braintree’s newer (version 2) API. For this gateway, - please provide the `vault_token` parameter with the value from - Braintree’s “Customer ID” rather than the “Payment Profile Token”. At - this time we do not use `current_vault_token` with the Braintree Blue - gateway, and we only support a single payment profile per Braintree - Customer. - When importing PayPal type payment profiles, please set `payment_type` - to `paypal_account`. - ### Stripe ACH Imports - If the bank account has already been verified, currently you will need - to create the customer, create the payment profile in Advanced Billing - - setting verified=true, then create a subscription using the - customer_id and payment_profile_id. - ### Webhooks During Import - If no `next_billing_at` is provided, webhooks will be fired as normal. - If you do set a future `next_billing_at`, only a subset of the - webhooks are fired when the subscription is created. Keep reading for - more information as to what webhooks will be fired under which - scenarios. - #### Successful creation with Billing Date - Scenario: If `next_billing_at` provided - + `signup_success` - + `billing_date_change` - #### Successful creation without Billing Date - Scenario: If no `next_billing_at` provided - + `signup_success` - + `payment_success` - #### Unsuccessful creation - Scenario: If card can’t be charged, and no `next_billing_at` provided - + signup_failure - #### Webhooks fired when next_billing_at is reached: - + `renewal_success or renewal_failure` - + `payment_success or payment_failure` - ### Date and Time Formats - We will attempt to parse any string you send as the value of - next_billing_at in to a date or time. For best results, use a known - format like described in “Date and Time Specification” of RFC 2822 or - ISO 8601 . - The following are all equivalent and will work as input to - `next_billing_at`: - ``` - Aug 06 2030 11:34:00 -0400 - Aug 06 2030 11:34 -0400 - 2030-08-06T11:34:00-04:00 - 8/6/2030 11:34:00 EDT - 8/6/2030 8:34:00 PDT - 2030-08-06T15:34:00Z - ``` - You may also pass just a date, in which case we will assume the time - to be noon - ``` - 2010-08-06 - ``` - ## Subscription Hierarchies & WhoPays - When subscription groups were first added to our Relationship - Invoicing architecture, to group together invoices for related - subscriptions and allow for complex customer hierarchies and WhoPays - scenarios, they were designed to consist of a primary and a collection - of group members. The primary would control many aspects of the group, - such as when the consolidated invoice is generated. As of today, - groups still function this way. - In the future, the concept of a "primary" will be removed in order to - offer more flexibility into group management and reduce confusion - concerning what actions must be done on a primary level, rather than a - member level. - We have introduced a two scheme system as a bridge between these two - group organizations. Scheme 1, which is relevant to all subscription - groups today, marks the group as being "ruled" by a primary. - When reading a subscription via API, they will return a top-level - attribute called `group`, which will denote which scheme is being - used. At this time, the `scheme` attribute will always be 1. - ### Subscription in a Customer Hierarchy - For sites making use of the [Relationship - Billing](https://maxio.zendesk.com/hc/en-us/articles/24252287829645-Adv - anced-Billing-Invoices-Overview) and [Customer - Hierarchy](https://maxio.zendesk.com/hc/en-us/articles/24252185211533-C - ustomer-Hierarchies-WhoPays) features, it is possible to create - subscriptions within a customer hierarchy. This can be achieved - through the API by passing group parameters in the **Create - Subscription** request. - + The `group` parameters are optional and consist of the required - `target` and optional `billing` parameters. - When the `target` parameter specifies a customer that is already part - of a hierarchy, the new subscription will become a member of the - customer hierarchy as well. If the target customer is not part of a - hierarchy, a new customer hierarchy will be created and both the - target customer and the new subscription will become part of the - hierarchy with the specified target customer set as the responsible - payer for the hierarchy's subscriptions. - Rather than specifying a customer, the `target` parameter could - instead simply have a value of `self` which indicates the subscription - will be paid for not by some other customer, but by the subscribing - customer. This will be true whether the customer is being created - new, is already part of a hierarchy, or already exists outside a - hierarchy. A valid payment method must also be specified in the - subscription parameters. - Note that when creating subscriptions in a customer hierarchy, if the - customer hierarchy does not already have a payment method, passing - valid credit card attributes in the subscription parameters will also - result in the payment method being established as the default payment - method for the customer hierarchy irrespective of the responsible - payer. - The optional `billing` parameters specify how some aspects of the - billing for the new subscription should be handled. Rather than - capturing payment immediately, the `accrue` parameter can be included - so that the new subscription charges accrue until the next assessment - date. Regarding the date, the `align_date` parameter can be included - so that the billing date of the new subscription matches up with the - default subscription group in the customer hierarchy. When choosing - to align the dates, the `prorate` parameter can also be specified so - that the new subscription charges are prorated based on the billing - period of the default subscription group in the customer hierarchy - also. - ### Subscription in a Subscription Group - For sites making use of [Relationship - Billing](https://maxio.zendesk.com/hc/en-us/articles/24252287829645-Adv - anced-Billing-Invoices-Overview) it may be desireable to create a - subscription as part of a [subscription - group](https://maxio.zendesk.com/hc/en-us/articles/24252172565005-Subsc - ription-Groups-Overview) in order to rely on [invoice - consolidation](https://maxio.zendesk.com/hc/en-us/articles/242522699093 - 89-Invoice-Consolidation). This can be achieved through the API by - passing group parameters in the Create Subscription request. The - `group` parameters are optional and consist of the required `target` - and optional `billing` parameters. - The `target` parameters specify an existing subscription with which - the newly created subscription should be grouped. If the target - subscription is already part of a group, the new subscription will - become a member of the group as well. If the target subscription is - not part of a group, a new group will be created and both the target - and the new subscription will become part of the group with the target - as the group's primary subscription. - The optional `billing` parameters specify how some aspects of the - billing for the new subscription should be handled. Rather than - capturing payment immediately, the `accrue` parameter can be included - so that the new subscription charges accrue until the next assessment - date. Regarding the date, the `align_date` parameter can be included - so that the billing date of the new subscription matches up with the - target subscription. When choosing to align the dates, the `prorate` - parameter can also be specified so that the new subscription charges - are prorated based on the billing period of the target subscription - also. - ## Providing Agreement Acceptance Params - It is possible to provide a proof of customer's acceptance of terms - and policies. - We will be storing this proof in case it might be required (i.e. - chargeback). - Currently, we already keep it for subscriptions created via Public - Signup Pages. - In order to create a subscription with the proof of agreement - acceptance, you must provide additional parameters `agreement - acceptance` with `ip_address` and at least one url to the policy that - was accepted: `terms_url` or `privacy_policy_url`. Additional urls - that can be provided: `return_refund_policy_url`, - `delivery_policy_url` and - `secure_checkout_policy_url`. - ```json - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "agreement_acceptance": { - "ip_address": "1.2.3.4", - "terms_url": "https://terms.url", - "privacy_policy_url": "https://privacy_policy.url", - "return_refund_policy_url": "https://return_refund_policy.url", - "delivery_policy_url": "https://delivery_policy.url", - "secure_checkout_policy_url": - "https://secure_checkout_policy.url" - } - } - } - ``` - **For Maxio Payments subscriptions, the agreement acceptance params - are required, with at least terms_url provided.** - ## Providing ACH Agreement params - It is also possible to provide a proof that a customer authorized ACH - agreement terms. - The proof will be stored and the email will be sent to the customer - with a copy of the terms (if enabled). - In order to create a subscription with the proof of authorized ACH - agreement terms, you must provide the additional parameter - `ach_agreement` with the following nested parameters: - `agreement_terms`, `authorizer_first_name`, `authorizer_last_name` and - `ip_address`. - Each of them is required. - ```json - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "Test Bank", - "bank_routing_number": "021000089", - "bank_account_number": "111111111111", - "bank_account_type": "checking", - "bank_account_holder_type": "business", - "payment_type": "bank_account" - }, - "ach_agreement": { - "agreement_terms": "ACH agreement terms", - "authorizer_first_name": "Jane", - "authorizer_last_name": "Doe", - "ip_address": "1.2.3.4" - } - } - ``` + hargify-js-Overview#chargify-js-overview-0-0) to collect credit card + or bank account information. + See the [Subscription + Signups](page:introduction/basic-concepts/subscription-signup) article + for more information on working with subscriptions in Advanced Billing. Args: body (CreateSubscriptionRequest, optional): The request body @@ -1032,71 +280,83 @@ def update_subscription(self, body=None): """Does a PUT request to /subscriptions/{subscription_id}.json. - The subscription endpoint allows you to instantly update one or many - attributes about a subscription in a single call. + Updates one or more attributes of a subscription. ## Update Subscription Payment Method - Change the card that your Subscriber uses for their subscription. You - can also use this method to simply change the expiration date of the - card **if your gateway allows**. - Note that partial card updates for **Authorize.Net** are not allowed - via this endpoint. The existing Payment Profile must be directly - updated instead. + Change the card that your subscriber uses for their subscription. You + can also use this method to change the expiration date of the card + **if your gateway allows**. + Do not use real card information for testing. See the Sites articles + that cover [testing your site + setup](https://docs.maxio.com/hc/en-us/articles/24250712113165-Testing- + Overview#testing-overview-0-0) for more details on testing in your + sandbox. + Note that collecting and sending raw card details in production + requires [PCI + compliance](https://docs.maxio.com/hc/en-us/articles/24183956938381-PCI + -Compliance#pci-compliance-0-0) on your end. If your business is not + PCI compliant, use + [Chargify.js](https://docs.maxio.com/hc/en-us/articles/38163190843789-C + hargify-js-Overview#chargify-js-overview-0-0) to collect credit card + or bank account information. + > Note: Partial card updates for **Authorize.Net** are not allowed via + this endpoint. The existing Payment Profile must be directly updated + instead. + ## Update Product You also use this method to change the subscription to a different product by setting a new value for product_handle. A product change can be done in two different ways, **product change** or **delayed product change**. - ## Product Change - This endpoint may be used to change a subscription's product. The new - payment amount is calculated and charged at the normal start of the - next period. If you desire complex product changes or prorated - upgrades and downgrades instead, please see the documentation on - Migrating Subscription Products. - To perform a product change, simply set either the `product_handle` or + ### Product Change + You can change a subscription's product. The new payment amount is + calculated and charged at the normal start of the next period. If you + require complex product changes or prorated upgrades and downgrades + instead, please see the documentation on [Migrating Subscription + Products](https://docs.maxio.com/hc/en-us/articles/24252069837581-Produ + ct-Changes-and-Migrations#product-changes-and-migrations-0-0). + To perform a product change, set either the `product_handle` or `product_id` attribute to that of a different product from the same site as the subscription. You can also change the price point by passing in either `product_price_point_id` or `product_price_point_handle` - otherwise the new product's default - price point will be used. + price point is used. ### Delayed Product Change This method also changes the product and/or price point, and the new payment amount is calculated and charged at the normal start of the next period. This method schedules the product change to happen automatically at - the subscription’s next renewal date. To perform a Delayed Product - Change, set the `product_handle` attribute as you would in a regular + the subscription’s next renewal date. To perform a delayed product + change, set the `product_handle` attribute as you would in a regular product change, but also set the `product_change_delayed` attribute to `true`. No proration applies in this case. You can also perform a delayed change to the price point by passing in either `product_price_point_id` or `product_price_point_handle` - **Note: To cancel a delayed product change, set `next_product_id` to - an empty string.** + > **Note:** To cancel a delayed product change, set `next_product_id` + to an empty string. ## Billing Date Changes + You can update dates for a subscrption. ### Regular Billing Date Changes Send the `next_billing_at` to set the next billing date for the subscription. After that date passes and the subscription is processed, the following billing date will be set according to the subscription's product period. - Note that if you pass an invalid date, we will automatically interpret - and set the correct date. For example, when February 30 is entered, - the next billing will be set to March 2nd in a non-leap year. + > Note: If you pass an invalid date, the correct date is automatically + set to he correct date. For example, if February 30 is passed, the + next billing would be set to March 2nd in a non-leap year. The server response will not return data under the key/value pair of - `next_billing`. Please view the key/value pair of - `current_period_ends_at` to verify that the `next_billing` date has - been changed successfully. - ### Snap Day Changes + `next_billing_at`. View the key/value pair of `current_period_ends_at` + to verify that the `next_billing_at` date has been changed + successfully. + ### Calendar Billing and Snap Day Changes For a subscription using Calendar Billing, setting the next billing date is a bit different. Send the `snap_day` attribute to change the calendar billing date for **a subscription using a product eligible for calendar billing**. - Note: If you change the product associated with a subscription that - contains a `snap_date` and immediately `READ/GET` the subscription - data, it will still contain evidence of the existing `snap_date`. This - is due to the fact that a product change is instantanous and only - affects the product associated with a subscription. After the - `next_billing` date arrives, the `snap_day` associated with the - subscription will return to `null.` Another way of looking at this is - that you willl have to wait for the next billing cycle to arrive - before the `snap_date` will reset to `null`. + > Note: If you change the product associated with a subscription that + contains a `snap_day` and immediately `READ/GET` the subscription + data, it will still contain original `snap_day`. The `snap_day`will + will reset to 'null on the next billing cycle. This is because a + product change is instantanous and only affects the product associated + with a subscription. Args: subscription_id (int): The Chargify id of the subscription @@ -1316,8 +576,8 @@ def purge_subscription(self, the customer record and/or payment profiles by passing `cascade` parameters. For example, to delete just the customer record, the query params would be: `?ack={customer_id}&cascade[]=customer` - If you need to remove subscriptions from a live site, please contact - support to discuss your use case. + If you need to remove subscriptions from a live site, contact support + to discuss your use case. ### Delete customer and payment profile The query params will be: `?ack={customer_id}&cascade[]=customer&cascade[]=payment_profile` @@ -1427,7 +687,7 @@ def preview_subscription(self, each Subscriber's Summary. A subscription will not be created by utilizing this endpoint; it is meant to serve as a prediction. - For more information, please see our documentation + For more information, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24252493695757-Subsc riber-Interface-Overview). ## Taxable Subscriptions @@ -1438,24 +698,24 @@ def preview_subscription(self, component, or combination of the two. + The subscription payload must contain a full billing or shipping address in order to calculate tax - For more information about creating taxable previews, please see our + For more information about creating taxable previews, see our documentation guide on how to create [taxable subscriptions.](https://maxio.zendesk.com/hc/en-us/sections/24287012349 325-Taxes) You do **not** need to include a card number to generate tax - information when you are previewing a subscription. However, please - note that when you actually want to create the subscription, you must - include the credit card information if you want the billing address to - be stored in Advanced Billing. The billing address and the credit card - information are stored together within the payment profile object. - Also, you may not send a billing address to Advanced Billing without - payment profile information, as the address is stored on the card. + information when you are previewing a subscription. However, when you + actually want to create the subscription, you must include the credit + card information if you want the billing address to be stored in + Advanced Billing. The billing address and the credit card information + are stored together within the payment profile object. Also, you may + not send a billing address to Advanced Billing without payment profile + information, as the address is stored on the card. You can pass shipping and billing addresses and still decide not to calculate taxes. To do that, pass `skip_billing_manifest_taxes: true` attribute. ## Non-taxable Subscriptions - If you'd like to calculate subscriptions that do not include tax, - please feel free to leave off the billing information. + If you'd like to calculate subscriptions that do not include tax you + may leave off the billing information. Args: body (CreateSubscriptionRequest, optional): The request body @@ -1566,7 +826,7 @@ def remove_coupon_from_subscription(self, Use this endpoint to remove a coupon from an existing subscription. For more information on the expected behaviour of removing a coupon - from a subscription, please see our documentation + from a subscription, See our documentation [here.](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coup ons-and-Subscriptions#removing-a-coupon) diff --git a/advancedbilling/http/__init__.py b/advancedbilling/http/__init__.py index 7ab8540c..45fcc043 100644 --- a/advancedbilling/http/__init__.py +++ b/advancedbilling/http/__init__.py @@ -5,4 +5,5 @@ 'http_response', 'http_call_back', 'proxy_settings', + 'http_client_provider', ] diff --git a/advancedbilling/http/auth/basic_auth.py b/advancedbilling/http/auth/basic_auth.py index 42edb069..4e89fcbb 100644 --- a/advancedbilling/http/auth/basic_auth.py +++ b/advancedbilling/http/auth/basic_auth.py @@ -7,6 +7,7 @@ https://www.apimatic.io ). """ +import os from apimatic_core.authentication.header_auth import HeaderAuth from apimatic_core.utilities.auth_helper import AuthHelper @@ -51,3 +52,16 @@ def __init__(self, username, password): def clone_with(self, username=None, password=None): return BasicAuthCredentials(username or self.username, password or self.password) + + @classmethod + def from_environment(cls): + username = os.getenv('USERNAME', None) + password = os.getenv('PASSWORD', None) + + if username is None or password is None: + return None + + return cls( + username=username, + password=password + ) \ No newline at end of file diff --git a/advancedbilling/http/http_client_provider.py b/advancedbilling/http/http_client_provider.py new file mode 100644 index 00000000..7a550de8 --- /dev/null +++ b/advancedbilling/http/http_client_provider.py @@ -0,0 +1,26 @@ +""" + advanced_billing + + This file was automatically generated for Maxio by APIMATIC v3.0 ( +https://www.apimatic.io ). +""" + +from abc import ABC + +from apimatic_core_interfaces.client.http_client_provider import ( + HttpClientProvider as CoreHttpClientProvider +) + +class HttpClientProvider(CoreHttpClientProvider, ABC): + """ + Defines a contract for providing HTTP client configuration. + + Classes implementing this interface are expected to supply a configured + HTTP session and timeout value that will be used by the SDK's internal + HTTP layer when making network requests. + + This allows developers to inject their own custom HTTP clients while + maintaining compatibility with the SDK's request/response handling. + """ + + pass diff --git a/advancedbilling/http/proxy_settings.py b/advancedbilling/http/proxy_settings.py index 2dba35bd..0cda245e 100644 --- a/advancedbilling/http/proxy_settings.py +++ b/advancedbilling/http/proxy_settings.py @@ -6,9 +6,30 @@ https://www.apimatic.io ). """ +import os from apimatic_core.http.configurations.proxy_settings import ProxySettings as CoreProxySettings class ProxySettings(CoreProxySettings): """ A simple data model for configuring HTTP(S) proxy settings. """ + + @classmethod + def from_environment(cls): + address = os.getenv('PROXY_ADDRESS', None) + if not address: + return None + + port = os.getenv('PROXY_PORT', None) + if port is not None: + try: + port = int(port) + except (TypeError, ValueError): + port = None + + return cls( + address=address, + port=port, + username=os.getenv('PROXY_USERNAME', None), + password=os.getenv('PROXY_PASSWORD', None), + ) diff --git a/advancedbilling/models/__init__.py b/advancedbilling/models/__init__.py index 81e1e816..d81a1e1d 100644 --- a/advancedbilling/models/__init__.py +++ b/advancedbilling/models/__init__.py @@ -571,6 +571,7 @@ 'subscription_state_filter', 'tax_configuration_kind', 'tax_destination_address', + 'trial_type', 'webhook_order', 'webhook_status', 'webhook_subscription', diff --git a/advancedbilling/models/activate_event_based_component.py b/advancedbilling/models/activate_event_based_component.py index ed5b34fe..04444f39 100644 --- a/advancedbilling/models/activate_event_based_component.py +++ b/advancedbilling/models/activate_event_based_component.py @@ -19,8 +19,8 @@ class ActivateEventBasedComponent(object): price_point_id (int): The Chargify id of the price point billing_schedule (BillingSchedule): This attribute is particularly useful when you need to align billing events for different - components on distinct schedules within a subscription. Please - note this only works for site with Multifrequency enabled + components on distinct schedules within a subscription. This only + works for site with Multifrequency enabled. custom_price (ComponentCustomPrice): Create or update custom pricing unique to the subscription. Used in place of `price_point_id`. additional_properties (Dict[str, object]): The additional properties diff --git a/advancedbilling/models/all_vaults.py b/advancedbilling/models/all_vaults.py index 7714c313..1caa734c 100644 --- a/advancedbilling/models/all_vaults.py +++ b/advancedbilling/models/all_vaults.py @@ -135,4 +135,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/allocation_preview_direction.py b/advancedbilling/models/allocation_preview_direction.py index 423580da..774fb682 100644 --- a/advancedbilling/models/allocation_preview_direction.py +++ b/advancedbilling/models/allocation_preview_direction.py @@ -23,3 +23,25 @@ class AllocationPreviewDirection(object): DOWNGRADE = 'downgrade' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/allocation_preview_line_item_kind.py b/advancedbilling/models/allocation_preview_line_item_kind.py index eac61e0e..c67ffa20 100644 --- a/advancedbilling/models/allocation_preview_line_item_kind.py +++ b/advancedbilling/models/allocation_preview_line_item_kind.py @@ -31,3 +31,25 @@ class AllocationPreviewLineItemKind(object): TAX = 'tax' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/apple_pay_vault.py b/advancedbilling/models/apple_pay_vault.py index 412e450c..2edab1d6 100644 --- a/advancedbilling/models/apple_pay_vault.py +++ b/advancedbilling/models/apple_pay_vault.py @@ -35,4 +35,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/auto_invite.py b/advancedbilling/models/auto_invite.py index 6b5f9ba4..b1de3c95 100644 --- a/advancedbilling/models/auto_invite.py +++ b/advancedbilling/models/auto_invite.py @@ -23,3 +23,25 @@ class AutoInvite(object): YES = 1 + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/bank_account_holder_type.py b/advancedbilling/models/bank_account_holder_type.py index 67fa130d..ce184007 100644 --- a/advancedbilling/models/bank_account_holder_type.py +++ b/advancedbilling/models/bank_account_holder_type.py @@ -38,4 +38,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/bank_account_type.py b/advancedbilling/models/bank_account_type.py index 072b69eb..4ac44387 100644 --- a/advancedbilling/models/bank_account_type.py +++ b/advancedbilling/models/bank_account_type.py @@ -38,4 +38,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/bank_account_vault.py b/advancedbilling/models/bank_account_vault.py index 56f81d75..e396d16c 100644 --- a/advancedbilling/models/bank_account_vault.py +++ b/advancedbilling/models/bank_account_vault.py @@ -57,4 +57,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/basic_date_field.py b/advancedbilling/models/basic_date_field.py index 728f3217..7ec14100 100644 --- a/advancedbilling/models/basic_date_field.py +++ b/advancedbilling/models/basic_date_field.py @@ -25,3 +25,25 @@ class BasicDateField(object): CREATED_AT = 'created_at' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/billing_manifest_line_item_kind.py b/advancedbilling/models/billing_manifest_line_item_kind.py index 8d15c48d..abfb0d50 100644 --- a/advancedbilling/models/billing_manifest_line_item_kind.py +++ b/advancedbilling/models/billing_manifest_line_item_kind.py @@ -37,3 +37,25 @@ class BillingManifestLineItemKind(object): TAX = 'tax' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/billing_schedule.py b/advancedbilling/models/billing_schedule.py index d9479f84..4ca015eb 100644 --- a/advancedbilling/models/billing_schedule.py +++ b/advancedbilling/models/billing_schedule.py @@ -17,8 +17,7 @@ class BillingSchedule(object): This attribute is particularly useful when you need to align billing events for different components on distinct schedules within a - subscription. Please note this only works for site with Multifrequency - enabled + subscription. This only works for site with Multifrequency enabled. Attributes: initial_billing_at (date): The initial_billing_at attribute in Maxio diff --git a/advancedbilling/models/calendar_billing.py b/advancedbilling/models/calendar_billing.py index 01933a82..4a0f08e9 100644 --- a/advancedbilling/models/calendar_billing.py +++ b/advancedbilling/models/calendar_billing.py @@ -16,8 +16,8 @@ class CalendarBilling(object): (Optional). Cannot be used when also specifying next_billing_at Attributes: - snap_day (int | str | None): A day of month that subscription will be - processed on. Can be 1 up to 28 or 'end'. + snap_day (int | SnapDay | None): A day of month that subscription will + be processed on. Can be 1 up to 28 or 'end'. calendar_billing_first_charge (FirstChargeType): The model property of type FirstChargeType. additional_properties (Dict[str, object]): The additional properties @@ -36,6 +36,10 @@ class CalendarBilling(object): 'calendar_billing_first_charge', ] + _nullables = [ + 'snap_day', + ] + def __init__(self, snap_day=APIHelper.SKIP, calendar_billing_first_charge=APIHelper.SKIP, @@ -73,7 +77,10 @@ def from_dictionary(cls, return None # Extract variables from the dictionary - snap_day = APIHelper.deserialize_union_type(UnionTypeLookUp.get('CalendarBillingSnapDay'), dictionary.get('snap_day'), False) if dictionary.get('snap_day') is not None else APIHelper.SKIP + if 'snap_day' in dictionary.keys(): + snap_day = APIHelper.deserialize_union_type(UnionTypeLookUp.get('CalendarBillingSnapDay'), dictionary.get('snap_day'), False) if dictionary.get('snap_day') is not None else None + else: + snap_day = APIHelper.SKIP calendar_billing_first_charge = dictionary.get("calendar_billing_first_charge") if dictionary.get("calendar_billing_first_charge") else APIHelper.SKIP # Clean out expected properties from dictionary additional_properties = {k: v for k, v in dictionary.items() if k not in cls._names.values()} diff --git a/advancedbilling/models/cancellation_method.py b/advancedbilling/models/cancellation_method.py index 3013c9d3..d62fb89a 100644 --- a/advancedbilling/models/cancellation_method.py +++ b/advancedbilling/models/cancellation_method.py @@ -26,6 +26,7 @@ class CancellationMethod(object): for the model. """ + _all_values = ['merchant_ui', 'merchant_api', 'dunning', 'billing_portal', 'unknown', 'imported'] MERCHANT_UI = 'merchant_ui' MERCHANT_API = 'merchant_api' @@ -38,3 +39,38 @@ class CancellationMethod(object): IMPORTED = 'imported' + @classmethod + def validate(cls, value): + """Validates value contains in enum + + Args: + value: the value to be validated + + Returns: + boolean : if value is valid enum values. + + """ + return value in cls._all_values + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/card_type.py b/advancedbilling/models/card_type.py index 33932ec0..569fa2cd 100644 --- a/advancedbilling/models/card_type.py +++ b/advancedbilling/models/card_type.py @@ -140,4 +140,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/chargeback_status.py b/advancedbilling/models/chargeback_status.py index 73032e8e..fc7f2cf8 100644 --- a/advancedbilling/models/chargeback_status.py +++ b/advancedbilling/models/chargeback_status.py @@ -44,4 +44,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/chargify_ebb.py b/advancedbilling/models/chargify_ebb.py index 8019a74b..2bc825fe 100644 --- a/advancedbilling/models/chargify_ebb.py +++ b/advancedbilling/models/chargify_ebb.py @@ -18,13 +18,13 @@ class ChargifyEBB(object): the event will be billed in. If your request payload does not include it, Chargify will add `chargify.timestamp` to the event payload and set the value to `now`. - id (str): A unique ID set by Chargify. Please note that this field is - reserved. If `chargify.id` is present in the request payload, it - will be overwritten. + id (str): A unique ID set by Chargify. This field is reserved. If + `chargify.id` is present in the request payload, it will be + overwritten. created_at (datetime): An ISO-8601 timestamp, set by Chargify at the - time each event is recorded. Please note that this field is - reserved. If `chargify.created_at` is present in the request - payload, it will be overwritten. + time each event is recorded. This field is reserved. If + `chargify.created_at` is present in the request payload, it will + be overwritten. uniqueness_token (str): User-defined string scoped per-stream. Duplicate events within a stream will be silently ignored. Tokens expire after 31 days. diff --git a/advancedbilling/models/cleanup_scope.py b/advancedbilling/models/cleanup_scope.py index 8e70408a..06f62050 100644 --- a/advancedbilling/models/cleanup_scope.py +++ b/advancedbilling/models/cleanup_scope.py @@ -28,3 +28,25 @@ class CleanupScope(object): CUSTOMERS = 'customers' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/collection_method.py b/advancedbilling/models/collection_method.py index 7e164644..814476bb 100644 --- a/advancedbilling/models/collection_method.py +++ b/advancedbilling/models/collection_method.py @@ -47,4 +47,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/component.py b/advancedbilling/models/component.py index 8b9ff202..8856ee3e 100644 --- a/advancedbilling/models/component.py +++ b/advancedbilling/models/component.py @@ -37,8 +37,6 @@ class Component(object): kind (ComponentKind): A handle for the component type archived (bool): Boolean flag describing whether a component is archived or not. - taxable (bool): Boolean flag describing whether a component is taxable - or not. description (str): The description of the component. default_price_point_id (int): The model property of type int. overage_prices (List[ComponentPrice]): Applicable only to prepaid @@ -51,10 +49,12 @@ class Component(object): price_points_url (str): URL that points to the location to read the existing price points via GET request default_price_point_name (str): The model property of type str. + taxable (bool): Boolean flag describing whether a component is taxable + or not. tax_code (str): A string representing the tax code related to the - component type. This is especially important when using the - Avalara service to tax based on locale. This attribute has a max - length of 10 characters. + component type. This is especially important when using AvaTax to + tax based on locale. This attribute has a max length of 25 + characters. recurring (bool): The model property of type bool. upgrade_charge (CreditType): The type of credit to be created when upgrading/downgrading. Defaults to the component and then site @@ -108,7 +108,6 @@ class Component(object): "price_per_unit_in_cents": 'price_per_unit_in_cents', "kind": 'kind', "archived": 'archived', - "taxable": 'taxable', "description": 'description', "default_price_point_id": 'default_price_point_id', "overage_prices": 'overage_prices', @@ -116,6 +115,7 @@ class Component(object): "price_point_count": 'price_point_count', "price_points_url": 'price_points_url', "default_price_point_name": 'default_price_point_name', + "taxable": 'taxable', "tax_code": 'tax_code', "recurring": 'recurring', "upgrade_charge": 'upgrade_charge', @@ -146,7 +146,6 @@ class Component(object): 'price_per_unit_in_cents', 'kind', 'archived', - 'taxable', 'description', 'default_price_point_id', 'overage_prices', @@ -154,6 +153,7 @@ class Component(object): 'price_point_count', 'price_points_url', 'default_price_point_name', + 'taxable', 'tax_code', 'recurring', 'upgrade_charge', @@ -204,7 +204,6 @@ def __init__(self, price_per_unit_in_cents=APIHelper.SKIP, kind=APIHelper.SKIP, archived=APIHelper.SKIP, - taxable=APIHelper.SKIP, description=APIHelper.SKIP, default_price_point_id=APIHelper.SKIP, overage_prices=APIHelper.SKIP, @@ -212,6 +211,7 @@ def __init__(self, price_point_count=APIHelper.SKIP, price_points_url=APIHelper.SKIP, default_price_point_name=APIHelper.SKIP, + taxable=APIHelper.SKIP, tax_code=APIHelper.SKIP, recurring=APIHelper.SKIP, upgrade_charge=APIHelper.SKIP, @@ -255,8 +255,6 @@ def __init__(self, self.kind = kind if archived is not APIHelper.SKIP: self.archived = archived - if taxable is not APIHelper.SKIP: - self.taxable = taxable if description is not APIHelper.SKIP: self.description = description if default_price_point_id is not APIHelper.SKIP: @@ -271,6 +269,8 @@ def __init__(self, self.price_points_url = price_points_url if default_price_point_name is not APIHelper.SKIP: self.default_price_point_name = default_price_point_name + if taxable is not APIHelper.SKIP: + self.taxable = taxable if tax_code is not APIHelper.SKIP: self.tax_code = tax_code if recurring is not APIHelper.SKIP: @@ -338,7 +338,6 @@ def from_dictionary(cls, price_per_unit_in_cents = dictionary.get("price_per_unit_in_cents") if "price_per_unit_in_cents" in dictionary.keys() else APIHelper.SKIP kind = dictionary.get("kind") if dictionary.get("kind") else APIHelper.SKIP archived = dictionary.get("archived") if "archived" in dictionary.keys() else APIHelper.SKIP - taxable = dictionary.get("taxable") if "taxable" in dictionary.keys() else APIHelper.SKIP description = dictionary.get("description") if "description" in dictionary.keys() else APIHelper.SKIP default_price_point_id = dictionary.get("default_price_point_id") if "default_price_point_id" in dictionary.keys() else APIHelper.SKIP if 'overage_prices' in dictionary.keys(): @@ -352,6 +351,7 @@ def from_dictionary(cls, price_point_count = dictionary.get("price_point_count") if dictionary.get("price_point_count") else APIHelper.SKIP price_points_url = dictionary.get("price_points_url") if "price_points_url" in dictionary.keys() else APIHelper.SKIP default_price_point_name = dictionary.get("default_price_point_name") if dictionary.get("default_price_point_name") else APIHelper.SKIP + taxable = dictionary.get("taxable") if "taxable" in dictionary.keys() else APIHelper.SKIP tax_code = dictionary.get("tax_code") if "tax_code" in dictionary.keys() else APIHelper.SKIP recurring = dictionary.get("recurring") if "recurring" in dictionary.keys() else APIHelper.SKIP upgrade_charge = dictionary.get("upgrade_charge") if "upgrade_charge" in dictionary.keys() else APIHelper.SKIP @@ -385,7 +385,6 @@ def from_dictionary(cls, price_per_unit_in_cents, kind, archived, - taxable, description, default_price_point_id, overage_prices, @@ -393,6 +392,7 @@ def from_dictionary(cls, price_point_count, price_points_url, default_price_point_name, + taxable, tax_code, recurring, upgrade_charge, @@ -424,7 +424,6 @@ def __repr__(self): f'price_per_unit_in_cents={(self.price_per_unit_in_cents if hasattr(self, "price_per_unit_in_cents") else None)!r}, ' f'kind={(self.kind if hasattr(self, "kind") else None)!r}, ' f'archived={(self.archived if hasattr(self, "archived") else None)!r}, ' - f'taxable={(self.taxable if hasattr(self, "taxable") else None)!r}, ' f'description={(self.description if hasattr(self, "description") else None)!r}, ' f'default_price_point_id={(self.default_price_point_id if hasattr(self, "default_price_point_id") else None)!r}, ' f'overage_prices={(self.overage_prices if hasattr(self, "overage_prices") else None)!r}, ' @@ -432,6 +431,7 @@ def __repr__(self): f'price_point_count={(self.price_point_count if hasattr(self, "price_point_count") else None)!r}, ' f'price_points_url={(self.price_points_url if hasattr(self, "price_points_url") else None)!r}, ' f'default_price_point_name={(self.default_price_point_name if hasattr(self, "default_price_point_name") else None)!r}, ' + f'taxable={(self.taxable if hasattr(self, "taxable") else None)!r}, ' f'tax_code={(self.tax_code if hasattr(self, "tax_code") else None)!r}, ' f'recurring={(self.recurring if hasattr(self, "recurring") else None)!r}, ' f'upgrade_charge={(self.upgrade_charge if hasattr(self, "upgrade_charge") else None)!r}, ' @@ -463,7 +463,6 @@ def __str__(self): f'price_per_unit_in_cents={(self.price_per_unit_in_cents if hasattr(self, "price_per_unit_in_cents") else None)!s}, ' f'kind={(self.kind if hasattr(self, "kind") else None)!s}, ' f'archived={(self.archived if hasattr(self, "archived") else None)!s}, ' - f'taxable={(self.taxable if hasattr(self, "taxable") else None)!s}, ' f'description={(self.description if hasattr(self, "description") else None)!s}, ' f'default_price_point_id={(self.default_price_point_id if hasattr(self, "default_price_point_id") else None)!s}, ' f'overage_prices={(self.overage_prices if hasattr(self, "overage_prices") else None)!s}, ' @@ -471,6 +470,7 @@ def __str__(self): f'price_point_count={(self.price_point_count if hasattr(self, "price_point_count") else None)!s}, ' f'price_points_url={(self.price_points_url if hasattr(self, "price_points_url") else None)!s}, ' f'default_price_point_name={(self.default_price_point_name if hasattr(self, "default_price_point_name") else None)!s}, ' + f'taxable={(self.taxable if hasattr(self, "taxable") else None)!s}, ' f'tax_code={(self.tax_code if hasattr(self, "tax_code") else None)!s}, ' f'recurring={(self.recurring if hasattr(self, "recurring") else None)!s}, ' f'upgrade_charge={(self.upgrade_charge if hasattr(self, "upgrade_charge") else None)!s}, ' diff --git a/advancedbilling/models/component_custom_price.py b/advancedbilling/models/component_custom_price.py index 868d1808..a5456e4e 100644 --- a/advancedbilling/models/component_custom_price.py +++ b/advancedbilling/models/component_custom_price.py @@ -29,6 +29,18 @@ class ComponentCustomPrice(object): is only available for sites with Multifrequency enabled. prices (List[Price]): On/off components only need one price bracket starting at 1 + renew_prepaid_allocation (bool): Applicable only to prepaid usage + components. Controls whether the allocated quantity renews each + period. + rollover_prepaid_remainder (bool): Applicable only to prepaid usage + components. Controls whether remaining units roll over to the next + period. + expiration_interval (int): Applicable only when rollover is enabled. + Number of `expiration_interval_unit`s after which rollover amounts + expire. + expiration_interval_unit (ExpirationIntervalUnit): Applicable only + when rollover is enabled. Interval unit for rollover expiration + (month or day). additional_properties (Dict[str, object]): The additional properties for the model. @@ -40,7 +52,11 @@ class ComponentCustomPrice(object): "tax_included": 'tax_included', "pricing_scheme": 'pricing_scheme', "interval": 'interval', - "interval_unit": 'interval_unit' + "interval_unit": 'interval_unit', + "renew_prepaid_allocation": 'renew_prepaid_allocation', + "rollover_prepaid_remainder": 'rollover_prepaid_remainder', + "expiration_interval": 'expiration_interval', + "expiration_interval_unit": 'expiration_interval_unit' } _optionals = [ @@ -48,10 +64,16 @@ class ComponentCustomPrice(object): 'pricing_scheme', 'interval', 'interval_unit', + 'renew_prepaid_allocation', + 'rollover_prepaid_remainder', + 'expiration_interval', + 'expiration_interval_unit', ] _nullables = [ 'interval_unit', + 'expiration_interval', + 'expiration_interval_unit', ] def __init__(self, @@ -60,6 +82,10 @@ def __init__(self, pricing_scheme=APIHelper.SKIP, interval=APIHelper.SKIP, interval_unit=APIHelper.SKIP, + renew_prepaid_allocation=APIHelper.SKIP, + rollover_prepaid_remainder=APIHelper.SKIP, + expiration_interval=APIHelper.SKIP, + expiration_interval_unit=APIHelper.SKIP, additional_properties=None): """Constructor for the ComponentCustomPrice class""" @@ -73,6 +99,14 @@ def __init__(self, if interval_unit is not APIHelper.SKIP: self.interval_unit = interval_unit self.prices = prices + if renew_prepaid_allocation is not APIHelper.SKIP: + self.renew_prepaid_allocation = renew_prepaid_allocation + if rollover_prepaid_remainder is not APIHelper.SKIP: + self.rollover_prepaid_remainder = rollover_prepaid_remainder + if expiration_interval is not APIHelper.SKIP: + self.expiration_interval = expiration_interval + if expiration_interval_unit is not APIHelper.SKIP: + self.expiration_interval_unit = expiration_interval_unit # Add additional model properties to the instance if additional_properties is None: @@ -105,6 +139,10 @@ def from_dictionary(cls, pricing_scheme = dictionary.get("pricing_scheme") if dictionary.get("pricing_scheme") else APIHelper.SKIP interval = dictionary.get("interval") if dictionary.get("interval") else APIHelper.SKIP interval_unit = dictionary.get("interval_unit") if "interval_unit" in dictionary.keys() else APIHelper.SKIP + renew_prepaid_allocation = dictionary.get("renew_prepaid_allocation") if "renew_prepaid_allocation" in dictionary.keys() else APIHelper.SKIP + rollover_prepaid_remainder = dictionary.get("rollover_prepaid_remainder") if "rollover_prepaid_remainder" in dictionary.keys() else APIHelper.SKIP + expiration_interval = dictionary.get("expiration_interval") if "expiration_interval" in dictionary.keys() else APIHelper.SKIP + expiration_interval_unit = dictionary.get("expiration_interval_unit") if "expiration_interval_unit" in dictionary.keys() else APIHelper.SKIP # Clean out expected properties from dictionary additional_properties = {k: v for k, v in dictionary.items() if k not in cls._names.values()} # Return an object of this model @@ -113,6 +151,10 @@ def from_dictionary(cls, pricing_scheme, interval, interval_unit, + renew_prepaid_allocation, + rollover_prepaid_remainder, + expiration_interval, + expiration_interval_unit, additional_properties) @classmethod @@ -150,6 +192,10 @@ def __repr__(self): f'interval={(self.interval if hasattr(self, "interval") else None)!r}, ' f'interval_unit={(self.interval_unit if hasattr(self, "interval_unit") else None)!r}, ' f'prices={self.prices!r}, ' + f'renew_prepaid_allocation={(self.renew_prepaid_allocation if hasattr(self, "renew_prepaid_allocation") else None)!r}, ' + f'rollover_prepaid_remainder={(self.rollover_prepaid_remainder if hasattr(self, "rollover_prepaid_remainder") else None)!r}, ' + f'expiration_interval={(self.expiration_interval if hasattr(self, "expiration_interval") else None)!r}, ' + f'expiration_interval_unit={(self.expiration_interval_unit if hasattr(self, "expiration_interval_unit") else None)!r}, ' f'additional_properties={self.additional_properties!r})') def __str__(self): @@ -159,4 +205,8 @@ def __str__(self): f'interval={(self.interval if hasattr(self, "interval") else None)!s}, ' f'interval_unit={(self.interval_unit if hasattr(self, "interval_unit") else None)!s}, ' f'prices={self.prices!s}, ' + f'renew_prepaid_allocation={(self.renew_prepaid_allocation if hasattr(self, "renew_prepaid_allocation") else None)!s}, ' + f'rollover_prepaid_remainder={(self.rollover_prepaid_remainder if hasattr(self, "rollover_prepaid_remainder") else None)!s}, ' + f'expiration_interval={(self.expiration_interval if hasattr(self, "expiration_interval") else None)!s}, ' + f'expiration_interval_unit={(self.expiration_interval_unit if hasattr(self, "expiration_interval_unit") else None)!s}, ' f'additional_properties={self.additional_properties!s})') diff --git a/advancedbilling/models/component_kind.py b/advancedbilling/models/component_kind.py index 7ed9569d..e2470e13 100644 --- a/advancedbilling/models/component_kind.py +++ b/advancedbilling/models/component_kind.py @@ -47,4 +47,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/compounding_strategy.py b/advancedbilling/models/compounding_strategy.py index c1cf6c8b..9d9955b0 100644 --- a/advancedbilling/models/compounding_strategy.py +++ b/advancedbilling/models/compounding_strategy.py @@ -42,4 +42,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/create_allocation.py b/advancedbilling/models/create_allocation.py index ba93e11c..dc9f7bd3 100644 --- a/advancedbilling/models/create_allocation.py +++ b/advancedbilling/models/create_allocation.py @@ -49,8 +49,8 @@ class CreateAllocation(object): price point will be used. billing_schedule (BillingSchedule): This attribute is particularly useful when you need to align billing events for different - components on distinct schedules within a subscription. Please - note this only works for site with Multifrequency enabled + components on distinct schedules within a subscription. This only + works for site with Multifrequency enabled. additional_properties (Dict[str, object]): The additional properties for the model. diff --git a/advancedbilling/models/create_invoice_coupon.py b/advancedbilling/models/create_invoice_coupon.py index 02add895..123aeeb2 100644 --- a/advancedbilling/models/create_invoice_coupon.py +++ b/advancedbilling/models/create_invoice_coupon.py @@ -15,6 +15,7 @@ class CreateInvoiceCoupon(object): Attributes: code (str): The model property of type str. + subcode (str): The model property of type str. percentage (str | float | None): The model property of type str | float | None. amount (str | float | None): The model property of type str | float | @@ -36,6 +37,7 @@ class CreateInvoiceCoupon(object): # Create a mapping from Model property names to API property names _names = { "code": 'code', + "subcode": 'subcode', "percentage": 'percentage', "amount": 'amount', "description": 'description', @@ -45,6 +47,7 @@ class CreateInvoiceCoupon(object): _optionals = [ 'code', + 'subcode', 'percentage', 'amount', 'description', @@ -54,6 +57,7 @@ class CreateInvoiceCoupon(object): def __init__(self, code=APIHelper.SKIP, + subcode=APIHelper.SKIP, percentage=APIHelper.SKIP, amount=APIHelper.SKIP, description=APIHelper.SKIP, @@ -65,6 +69,8 @@ def __init__(self, # Initialize members of the class if code is not APIHelper.SKIP: self.code = code + if subcode is not APIHelper.SKIP: + self.subcode = subcode if percentage is not APIHelper.SKIP: self.percentage = percentage if amount is not APIHelper.SKIP: @@ -102,6 +108,7 @@ def from_dictionary(cls, # Extract variables from the dictionary code = dictionary.get("code") if dictionary.get("code") else APIHelper.SKIP + subcode = dictionary.get("subcode") if dictionary.get("subcode") else APIHelper.SKIP percentage = APIHelper.deserialize_union_type(UnionTypeLookUp.get('CreateInvoiceCouponPercentage'), dictionary.get('percentage'), False) if dictionary.get('percentage') is not None else APIHelper.SKIP amount = APIHelper.deserialize_union_type(UnionTypeLookUp.get('CreateInvoiceCouponAmount'), dictionary.get('amount'), False) if dictionary.get('amount') is not None else APIHelper.SKIP description = dictionary.get("description") if dictionary.get("description") else APIHelper.SKIP @@ -111,6 +118,7 @@ def from_dictionary(cls, additional_properties = {k: v for k, v in dictionary.items() if k not in cls._names.values()} # Return an object of this model return cls(code, + subcode, percentage, amount, description, @@ -121,6 +129,7 @@ def from_dictionary(cls, def __repr__(self): return (f'{self.__class__.__name__}(' f'code={(self.code if hasattr(self, "code") else None)!r}, ' + f'subcode={(self.subcode if hasattr(self, "subcode") else None)!r}, ' f'percentage={(self.percentage if hasattr(self, "percentage") else None)!r}, ' f'amount={(self.amount if hasattr(self, "amount") else None)!r}, ' f'description={(self.description if hasattr(self, "description") else None)!r}, ' @@ -131,6 +140,7 @@ def __repr__(self): def __str__(self): return (f'{self.__class__.__name__}(' f'code={(self.code if hasattr(self, "code") else None)!s}, ' + f'subcode={(self.subcode if hasattr(self, "subcode") else None)!s}, ' f'percentage={(self.percentage if hasattr(self, "percentage") else None)!s}, ' f'amount={(self.amount if hasattr(self, "amount") else None)!s}, ' f'description={(self.description if hasattr(self, "description") else None)!s}, ' diff --git a/advancedbilling/models/create_invoice_item.py b/advancedbilling/models/create_invoice_item.py index 89fef6b0..4eae59c4 100644 --- a/advancedbilling/models/create_invoice_item.py +++ b/advancedbilling/models/create_invoice_item.py @@ -24,9 +24,12 @@ class CreateInvoiceItem(object): value with more than 8 decimal places, we will round it down to the 8th decimal place. taxable (bool): Set to true to automatically calculate taxes. Site - must be configured to use and calculate taxes. If using Avalara, - a tax_code parameter must also be sent. - tax_code (str): The model property of type str. + must be configured to use and calculate taxes. If using AvaTax, a + tax_code parameter must also be sent. + tax_code (str): A string representing the tax code related to the + product type. This is especially important when using AvaTax to + tax based on locale. This attribute has a max length of 25 + characters. period_range_start (str): YYYY-MM-DD period_range_end (str): YYYY-MM-DD product_id (str | int | None): Product handle or product id. diff --git a/advancedbilling/models/create_invoice_status.py b/advancedbilling/models/create_invoice_status.py index fde5ae49..fb1cb82d 100644 --- a/advancedbilling/models/create_invoice_status.py +++ b/advancedbilling/models/create_invoice_status.py @@ -23,3 +23,25 @@ class CreateInvoiceStatus(object): OPEN = 'open' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/create_metafield.py b/advancedbilling/models/create_metafield.py index 005544ef..d12e7829 100644 --- a/advancedbilling/models/create_metafield.py +++ b/advancedbilling/models/create_metafield.py @@ -19,12 +19,9 @@ class CreateMetafield(object): scope (MetafieldScope): Warning: When updating a metafield's scope attribute, all scope attributes must be passed. Partially complete scope attributes will override the existing settings. - input_type (MetafieldInput): Indicates how data should be added to the - metafield. For example, a text type is just a string, so a given - metafield of this type can have any value attached. On the other - hand, dropdown and radio have a set of allowed values that can be - input, and appear differently on a Public Signup Page. Defaults to - 'text' + input_type (MetafieldInput): Indicates the type of metafield. A text + metafield allows any string value. Dropdown and radio metafields + have a set of values that can be selected. Defaults to 'text'. enum (List[str]): Only applicable when input_type is radio or dropdown. Empty strings will not be submitted. additional_properties (Dict[str, object]): The additional properties diff --git a/advancedbilling/models/create_or_update_product.py b/advancedbilling/models/create_or_update_product.py index a11f8d94..0880ca72 100644 --- a/advancedbilling/models/create_or_update_product.py +++ b/advancedbilling/models/create_or_update_product.py @@ -20,7 +20,7 @@ class CreateOrUpdateProduct(object): accounting_code (str): E.g. Internal ID or SKU Number require_credit_card (bool): Deprecated value that can be ignored unless you have legacy hosted pages. For Public Signup Page users, - please read this attribute from under the signup page. + read this attribute from under the signup page. price_in_cents (int): The product price, in integer cents interval (int): The numerical interval. i.e. an interval of ‘30’ coupled with an interval_unit of day would mean this product would @@ -33,7 +33,13 @@ class CreateOrUpdateProduct(object): product trial would last 30 days. trial_interval_unit (IntervalUnit): A string representing the trial interval unit for this product, either month or day - trial_type (str): The model property of type str. + trial_type (TrialType): Indicates how a trial is handled when the + trail period ends and there is no credit card on file. For + `no_obligation`, the subscription transitions to a Trial Ended + state. Maxio will not send any emails or statements. For + `payment_expected`, the subscription transitions to a Past Due + state. Maxio will send normal dunning emails and statements + according to your other settings. expiration_interval (int): The numerical expiration interval. i.e. an expiration_interval of ‘30’ coupled with an expiration_interval_unit of day would mean this product would @@ -43,9 +49,9 @@ class CreateOrUpdateProduct(object): month, day or never auto_create_signup_page (bool): The model property of type bool. tax_code (str): A string representing the tax code related to the - product type. This is especially important when using the Avalara - service to tax based on locale. This attribute has a max length of - 10 characters. + product type. This is especially important when using AvaTax to + tax based on locale. This attribute has a max length of 25 + characters. additional_properties (Dict[str, object]): The additional properties for the model. @@ -87,6 +93,7 @@ class CreateOrUpdateProduct(object): _nullables = [ 'trial_interval_unit', + 'trial_type', 'expiration_interval_unit', ] @@ -174,7 +181,7 @@ def from_dictionary(cls, trial_price_in_cents = dictionary.get("trial_price_in_cents") if dictionary.get("trial_price_in_cents") else APIHelper.SKIP trial_interval = dictionary.get("trial_interval") if dictionary.get("trial_interval") else APIHelper.SKIP trial_interval_unit = dictionary.get("trial_interval_unit") if "trial_interval_unit" in dictionary.keys() else APIHelper.SKIP - trial_type = dictionary.get("trial_type") if dictionary.get("trial_type") else APIHelper.SKIP + trial_type = dictionary.get("trial_type") if "trial_type" in dictionary.keys() else APIHelper.SKIP expiration_interval = dictionary.get("expiration_interval") if dictionary.get("expiration_interval") else APIHelper.SKIP expiration_interval_unit = dictionary.get("expiration_interval_unit") if "expiration_interval_unit" in dictionary.keys() else APIHelper.SKIP auto_create_signup_page = dictionary.get("auto_create_signup_page") if "auto_create_signup_page" in dictionary.keys() else APIHelper.SKIP diff --git a/advancedbilling/models/create_payment_profile.py b/advancedbilling/models/create_payment_profile.py index 947d9f7c..c1dd44a8 100644 --- a/advancedbilling/models/create_payment_profile.py +++ b/advancedbilling/models/create_payment_profile.py @@ -14,8 +14,8 @@ class CreatePaymentProfile(object): """Implementation of the 'Create Payment Profile' model. Attributes: - chargify_token (str): Token received after sending billing - informations using chargify.js. + chargify_token (str): Token received after sending billing information + using chargify.js. id (int): The model property of type int. payment_type (PaymentType): The model property of type PaymentType. first_name (str): First name on card or bank account. If omitted, the @@ -49,7 +49,7 @@ class CreatePaymentProfile(object): alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) format (i.e. “US”). This value is merely passed through to the payment gateway. Some gateways require country codes in a specific format. - Please check your gateway’s documentation. If creating an ACH + Check your gateway’s documentation. If creating an ACH subscription, only US is supported at this time. billing_zip (str): The credit card or bank account billing address zip code (i.e. 12345). This value is merely passed through to the diff --git a/advancedbilling/models/create_prepayment_method.py b/advancedbilling/models/create_prepayment_method.py index ae664168..24611c3c 100644 --- a/advancedbilling/models/create_prepayment_method.py +++ b/advancedbilling/models/create_prepayment_method.py @@ -46,3 +46,25 @@ class CreatePrepaymentMethod(object): OTHER = 'other' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/create_product_price_point.py b/advancedbilling/models/create_product_price_point.py index 0ab9a807..252bf101 100644 --- a/advancedbilling/models/create_product_price_point.py +++ b/advancedbilling/models/create_product_price_point.py @@ -29,7 +29,13 @@ class CreateProductPricePoint(object): product price point trial would last 30 days. trial_interval_unit (IntervalUnit): A string representing the trial interval unit for this product price point, either month or day - trial_type (str): The model property of type str. + trial_type (TrialType): Indicates how a trial is handled when the + trail period ends and there is no credit card on file. For + `no_obligation`, the subscription transitions to a Trial Ended + state. Maxio will not send any emails or statements. For + `payment_expected`, the subscription transitions to a Past Due + state. Maxio will send normal dunning emails and statements + according to your other settings. initial_charge_in_cents (int): The product price point initial charge, in integer cents initial_charge_after_trial (bool): The model property of type bool. @@ -80,6 +86,7 @@ class CreateProductPricePoint(object): ] _nullables = [ + 'trial_type', 'expiration_interval_unit', ] @@ -158,7 +165,7 @@ def from_dictionary(cls, trial_price_in_cents = dictionary.get("trial_price_in_cents") if dictionary.get("trial_price_in_cents") else APIHelper.SKIP trial_interval = dictionary.get("trial_interval") if dictionary.get("trial_interval") else APIHelper.SKIP trial_interval_unit = dictionary.get("trial_interval_unit") if dictionary.get("trial_interval_unit") else APIHelper.SKIP - trial_type = dictionary.get("trial_type") if dictionary.get("trial_type") else APIHelper.SKIP + trial_type = dictionary.get("trial_type") if "trial_type" in dictionary.keys() else APIHelper.SKIP initial_charge_in_cents = dictionary.get("initial_charge_in_cents") if dictionary.get("initial_charge_in_cents") else APIHelper.SKIP initial_charge_after_trial = dictionary.get("initial_charge_after_trial") if "initial_charge_after_trial" in dictionary.keys() else APIHelper.SKIP expiration_interval = dictionary.get("expiration_interval") if dictionary.get("expiration_interval") else APIHelper.SKIP diff --git a/advancedbilling/models/create_signup_proforma_preview_include.py b/advancedbilling/models/create_signup_proforma_preview_include.py index a6ec7961..3ab3459b 100644 --- a/advancedbilling/models/create_signup_proforma_preview_include.py +++ b/advancedbilling/models/create_signup_proforma_preview_include.py @@ -20,3 +20,25 @@ class CreateSignupProformaPreviewInclude(object): """ NEXT_PROFORMA_INVOICE = 'next_proforma_invoice' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/create_usage.py b/advancedbilling/models/create_usage.py index f4710a48..255e5968 100644 --- a/advancedbilling/models/create_usage.py +++ b/advancedbilling/models/create_usage.py @@ -8,6 +8,7 @@ """ from advancedbilling.api_helper import APIHelper from advancedbilling.models.billing_schedule import BillingSchedule +from advancedbilling.models.component_custom_price import ComponentCustomPrice class CreateUsage(object): @@ -21,8 +22,10 @@ class CreateUsage(object): memo (str): The model property of type str. billing_schedule (BillingSchedule): This attribute is particularly useful when you need to align billing events for different - components on distinct schedules within a subscription. Please - note this only works for site with Multifrequency enabled + components on distinct schedules within a subscription. This only + works for site with Multifrequency enabled. + custom_price (ComponentCustomPrice): Create or update custom pricing + unique to the subscription. Used in place of `price_point_id`. additional_properties (Dict[str, object]): The additional properties for the model. @@ -33,7 +36,8 @@ class CreateUsage(object): "quantity": 'quantity', "price_point_id": 'price_point_id', "memo": 'memo', - "billing_schedule": 'billing_schedule' + "billing_schedule": 'billing_schedule', + "custom_price": 'custom_price' } _optionals = [ @@ -41,6 +45,7 @@ class CreateUsage(object): 'price_point_id', 'memo', 'billing_schedule', + 'custom_price', ] def __init__(self, @@ -48,6 +53,7 @@ def __init__(self, price_point_id=APIHelper.SKIP, memo=APIHelper.SKIP, billing_schedule=APIHelper.SKIP, + custom_price=APIHelper.SKIP, additional_properties=None): """Constructor for the CreateUsage class""" @@ -60,6 +66,8 @@ def __init__(self, self.memo = memo if billing_schedule is not APIHelper.SKIP: self.billing_schedule = billing_schedule + if custom_price is not APIHelper.SKIP: + self.custom_price = custom_price # Add additional model properties to the instance if additional_properties is None: @@ -89,6 +97,7 @@ def from_dictionary(cls, price_point_id = dictionary.get("price_point_id") if dictionary.get("price_point_id") else APIHelper.SKIP memo = dictionary.get("memo") if dictionary.get("memo") else APIHelper.SKIP billing_schedule = BillingSchedule.from_dictionary(dictionary.get('billing_schedule')) if 'billing_schedule' in dictionary.keys() else APIHelper.SKIP + custom_price = ComponentCustomPrice.from_dictionary(dictionary.get('custom_price')) if 'custom_price' in dictionary.keys() else APIHelper.SKIP # Clean out expected properties from dictionary additional_properties = {k: v for k, v in dictionary.items() if k not in cls._names.values()} # Return an object of this model @@ -96,6 +105,7 @@ def from_dictionary(cls, price_point_id, memo, billing_schedule, + custom_price, additional_properties) def __repr__(self): @@ -104,6 +114,7 @@ def __repr__(self): f'price_point_id={(self.price_point_id if hasattr(self, "price_point_id") else None)!r}, ' f'memo={(self.memo if hasattr(self, "memo") else None)!r}, ' f'billing_schedule={(self.billing_schedule if hasattr(self, "billing_schedule") else None)!r}, ' + f'custom_price={(self.custom_price if hasattr(self, "custom_price") else None)!r}, ' f'additional_properties={self.additional_properties!r})') def __str__(self): @@ -112,4 +123,5 @@ def __str__(self): f'price_point_id={(self.price_point_id if hasattr(self, "price_point_id") else None)!s}, ' f'memo={(self.memo if hasattr(self, "memo") else None)!s}, ' f'billing_schedule={(self.billing_schedule if hasattr(self, "billing_schedule") else None)!s}, ' + f'custom_price={(self.custom_price if hasattr(self, "custom_price") else None)!s}, ' f'additional_properties={self.additional_properties!s})') diff --git a/advancedbilling/models/credit_card_vault.py b/advancedbilling/models/credit_card_vault.py index 92e37209..613b5646 100644 --- a/advancedbilling/models/credit_card_vault.py +++ b/advancedbilling/models/credit_card_vault.py @@ -132,4 +132,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/credit_note_status.py b/advancedbilling/models/credit_note_status.py index 0e1748cb..a5cb89d9 100644 --- a/advancedbilling/models/credit_note_status.py +++ b/advancedbilling/models/credit_note_status.py @@ -38,4 +38,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/credit_scheme.py b/advancedbilling/models/credit_scheme.py index 00c716dc..b545d775 100644 --- a/advancedbilling/models/credit_scheme.py +++ b/advancedbilling/models/credit_scheme.py @@ -26,3 +26,25 @@ class CreditScheme(object): REFUND = 'refund' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/credit_type.py b/advancedbilling/models/credit_type.py index e8d2d3d6..fa9169f9 100644 --- a/advancedbilling/models/credit_type.py +++ b/advancedbilling/models/credit_type.py @@ -43,4 +43,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/currency_price_role.py b/advancedbilling/models/currency_price_role.py index 2adf8d54..8a9efb36 100644 --- a/advancedbilling/models/currency_price_role.py +++ b/advancedbilling/models/currency_price_role.py @@ -28,3 +28,25 @@ class CurrencyPriceRole(object): INITIAL = 'initial' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/custom_field_owner.py b/advancedbilling/models/custom_field_owner.py index ef8fd65c..7bbfba7b 100644 --- a/advancedbilling/models/custom_field_owner.py +++ b/advancedbilling/models/custom_field_owner.py @@ -36,4 +36,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/debit_note_role.py b/advancedbilling/models/debit_note_role.py index 28fbe5a9..d2eeca5a 100644 --- a/advancedbilling/models/debit_note_role.py +++ b/advancedbilling/models/debit_note_role.py @@ -38,4 +38,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/debit_note_status.py b/advancedbilling/models/debit_note_status.py index 0e4e033b..e5cc7ef5 100644 --- a/advancedbilling/models/debit_note_status.py +++ b/advancedbilling/models/debit_note_status.py @@ -44,4 +44,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/direction.py b/advancedbilling/models/direction.py index 89107e2f..447d5c5c 100644 --- a/advancedbilling/models/direction.py +++ b/advancedbilling/models/direction.py @@ -23,3 +23,25 @@ class Direction(object): DESC = 'desc' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/discount_type.py b/advancedbilling/models/discount_type.py index 49d8084a..a30af6e8 100644 --- a/advancedbilling/models/discount_type.py +++ b/advancedbilling/models/discount_type.py @@ -23,3 +23,25 @@ class DiscountType(object): PERCENT = 'percent' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/ebb_component.py b/advancedbilling/models/ebb_component.py index a5ff63e7..dccfd7e0 100644 --- a/advancedbilling/models/ebb_component.py +++ b/advancedbilling/models/ebb_component.py @@ -46,9 +46,9 @@ class EBBComponent(object): can contain up to 8 decimal places. i.e. 1.00 or 0.0012 or 0.00000065 tax_code (str): A string representing the tax code related to the - component type. This is especially important when using the - Avalara service to tax based on locale. This attribute has a max - length of 10 characters. + component type. This is especially important when using AvaTax to + tax based on locale. This attribute has a max length of 25 + characters. hide_date_range_on_invoice (bool): (Only available on Relationship Invoicing sites) Boolean flag describing if the service date range should show for the component on generated invoices. diff --git a/advancedbilling/models/event_key.py b/advancedbilling/models/event_key.py index 50531755..38bb640e 100644 --- a/advancedbilling/models/event_key.py +++ b/advancedbilling/models/event_key.py @@ -275,4 +275,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/expiration_interval_unit.py b/advancedbilling/models/expiration_interval_unit.py index 8dd4d06a..3f3bf45b 100644 --- a/advancedbilling/models/expiration_interval_unit.py +++ b/advancedbilling/models/expiration_interval_unit.py @@ -39,4 +39,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/failed_payment_action.py b/advancedbilling/models/failed_payment_action.py index 010ba9c7..a25202f4 100644 --- a/advancedbilling/models/failed_payment_action.py +++ b/advancedbilling/models/failed_payment_action.py @@ -40,3 +40,25 @@ class FailedPaymentAction(object): INITIATE_DUNNING = 'initiate_dunning' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/first_charge_type.py b/advancedbilling/models/first_charge_type.py index eb0135e6..0fa8679a 100644 --- a/advancedbilling/models/first_charge_type.py +++ b/advancedbilling/models/first_charge_type.py @@ -39,4 +39,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/group_target_type.py b/advancedbilling/models/group_target_type.py index ef56f371..129e6079 100644 --- a/advancedbilling/models/group_target_type.py +++ b/advancedbilling/models/group_target_type.py @@ -47,4 +47,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/group_type.py b/advancedbilling/models/group_type.py index f8dde8fe..e499f428 100644 --- a/advancedbilling/models/group_type.py +++ b/advancedbilling/models/group_type.py @@ -23,3 +23,25 @@ class GroupType(object): MULTIPLE_CUSTOMERS = 'multiple_customers' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/include_not_null.py b/advancedbilling/models/include_not_null.py index 1b38859c..7cf17be9 100644 --- a/advancedbilling/models/include_not_null.py +++ b/advancedbilling/models/include_not_null.py @@ -22,3 +22,25 @@ class IncludeNotNull(object): """ NOT_NULL = 'not_null' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/include_null_or_not_null.py b/advancedbilling/models/include_null_or_not_null.py index 29e8e3a6..814bb746 100644 --- a/advancedbilling/models/include_null_or_not_null.py +++ b/advancedbilling/models/include_null_or_not_null.py @@ -25,3 +25,25 @@ class IncludeNullOrNotNull(object): NULL = 'null' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/include_option.py b/advancedbilling/models/include_option.py index 5560c31d..700e500c 100644 --- a/advancedbilling/models/include_option.py +++ b/advancedbilling/models/include_option.py @@ -36,4 +36,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/interval_unit.py b/advancedbilling/models/interval_unit.py index 0ae2f2cd..ddeecd49 100644 --- a/advancedbilling/models/interval_unit.py +++ b/advancedbilling/models/interval_unit.py @@ -36,4 +36,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/invoice_consolidation_level.py b/advancedbilling/models/invoice_consolidation_level.py index bdc6299e..02931210 100644 --- a/advancedbilling/models/invoice_consolidation_level.py +++ b/advancedbilling/models/invoice_consolidation_level.py @@ -52,4 +52,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/invoice_date_field.py b/advancedbilling/models/invoice_date_field.py index 52364f34..24d22c74 100644 --- a/advancedbilling/models/invoice_date_field.py +++ b/advancedbilling/models/invoice_date_field.py @@ -32,3 +32,25 @@ class InvoiceDateField(object): PAID_DATE = 'paid_date' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/invoice_discount_source_type.py b/advancedbilling/models/invoice_discount_source_type.py index 9e2c854a..07b3d7dd 100644 --- a/advancedbilling/models/invoice_discount_source_type.py +++ b/advancedbilling/models/invoice_discount_source_type.py @@ -39,4 +39,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/invoice_discount_type.py b/advancedbilling/models/invoice_discount_type.py index 88b6f0d8..8e64b21d 100644 --- a/advancedbilling/models/invoice_discount_type.py +++ b/advancedbilling/models/invoice_discount_type.py @@ -39,4 +39,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/invoice_event_payment_method.py b/advancedbilling/models/invoice_event_payment_method.py index b964a9c6..57c17875 100644 --- a/advancedbilling/models/invoice_event_payment_method.py +++ b/advancedbilling/models/invoice_event_payment_method.py @@ -45,4 +45,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/invoice_event_type.py b/advancedbilling/models/invoice_event_type.py index 152aa492..aaca4b41 100644 --- a/advancedbilling/models/invoice_event_type.py +++ b/advancedbilling/models/invoice_event_type.py @@ -77,4 +77,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/invoice_payment_method_type.py b/advancedbilling/models/invoice_payment_method_type.py index 5d9e3821..abacc239 100644 --- a/advancedbilling/models/invoice_payment_method_type.py +++ b/advancedbilling/models/invoice_payment_method_type.py @@ -50,4 +50,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/invoice_payment_type.py b/advancedbilling/models/invoice_payment_type.py index 93ec0214..76f10249 100644 --- a/advancedbilling/models/invoice_payment_type.py +++ b/advancedbilling/models/invoice_payment_type.py @@ -31,3 +31,25 @@ class InvoicePaymentType(object): PAYMENT = 'payment' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/invoice_role.py b/advancedbilling/models/invoice_role.py index 49389aaf..a6a86960 100644 --- a/advancedbilling/models/invoice_role.py +++ b/advancedbilling/models/invoice_role.py @@ -60,4 +60,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/invoice_sort_field.py b/advancedbilling/models/invoice_sort_field.py index 1c05f3f1..0f049138 100644 --- a/advancedbilling/models/invoice_sort_field.py +++ b/advancedbilling/models/invoice_sort_field.py @@ -41,3 +41,25 @@ class InvoiceSortField(object): NUMBER = 'number' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/invoice_status.py b/advancedbilling/models/invoice_status.py index 65e23a93..38c5a6fd 100644 --- a/advancedbilling/models/invoice_status.py +++ b/advancedbilling/models/invoice_status.py @@ -55,4 +55,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/item_category.py b/advancedbilling/models/item_category.py index 204c6fa5..61e77d80 100644 --- a/advancedbilling/models/item_category.py +++ b/advancedbilling/models/item_category.py @@ -35,3 +35,25 @@ class ItemCategory(object): OTHER = 'Other' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/line_item_kind.py b/advancedbilling/models/line_item_kind.py index 6f203596..1d71d6b2 100644 --- a/advancedbilling/models/line_item_kind.py +++ b/advancedbilling/models/line_item_kind.py @@ -49,3 +49,25 @@ class LineItemKind(object): TAX = 'tax' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/line_item_transaction_type.py b/advancedbilling/models/line_item_transaction_type.py index f70ea700..ce11870c 100644 --- a/advancedbilling/models/line_item_transaction_type.py +++ b/advancedbilling/models/line_item_transaction_type.py @@ -40,3 +40,25 @@ class LineItemTransactionType(object): PAYMENT_AUTHORIZATION = 'payment_authorization' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/list_components_price_points_include.py b/advancedbilling/models/list_components_price_points_include.py index f836e396..b3b3a062 100644 --- a/advancedbilling/models/list_components_price_points_include.py +++ b/advancedbilling/models/list_components_price_points_include.py @@ -20,3 +20,25 @@ class ListComponentsPricePointsInclude(object): """ CURRENCY_PRICES = 'currency_prices' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/list_coupons_filter.py b/advancedbilling/models/list_coupons_filter.py index 0dd0a494..15b58ecf 100644 --- a/advancedbilling/models/list_coupons_filter.py +++ b/advancedbilling/models/list_coupons_filter.py @@ -44,9 +44,15 @@ class ListCouponsFilter(object): provided values. Use in query `filter[ids]=1,2,3`. codes (List[str]): Allows fetching coupons with matching codes based on provided values. Use in query `filter[codes]=free,free_trial`. - use_site_exchange_rate (bool): Allows fetching coupons with matching - use_site_exchange_rate based on provided value. Use in query + use_site_exchange_rate (bool): If true, restricts the list to coupons + whose pricing is recalculated from the site’s current exchange + rates, so their currency_prices array contains on-the-fly + conversions rather than stored price records. If false, restricts + the list to coupons that have manually defined amounts for each + currency, ensuring the response includes the saved currency_prices + entries instead of exchange-rate-derived values. Use in query `filter[use_site_exchange_rate]=true`. + include_archived (bool): Controls returning archived coupons. additional_properties (Dict[str, object]): The additional properties for the model. @@ -61,7 +67,8 @@ class ListCouponsFilter(object): "end_datetime": 'end_datetime', "ids": 'ids', "codes": 'codes', - "use_site_exchange_rate": 'use_site_exchange_rate' + "use_site_exchange_rate": 'use_site_exchange_rate', + "include_archived": 'include_archived' } _optionals = [ @@ -73,6 +80,7 @@ class ListCouponsFilter(object): 'ids', 'codes', 'use_site_exchange_rate', + 'include_archived', ] def __init__(self, @@ -84,6 +92,7 @@ def __init__(self, ids=APIHelper.SKIP, codes=APIHelper.SKIP, use_site_exchange_rate=APIHelper.SKIP, + include_archived=APIHelper.SKIP, additional_properties=None): """Constructor for the ListCouponsFilter class""" @@ -104,6 +113,8 @@ def __init__(self, self.codes = codes if use_site_exchange_rate is not APIHelper.SKIP: self.use_site_exchange_rate = use_site_exchange_rate + if include_archived is not APIHelper.SKIP: + self.include_archived = include_archived # Add additional model properties to the instance if additional_properties is None: @@ -137,6 +148,7 @@ def from_dictionary(cls, ids = dictionary.get("ids") if dictionary.get("ids") else APIHelper.SKIP codes = dictionary.get("codes") if dictionary.get("codes") else APIHelper.SKIP use_site_exchange_rate = dictionary.get("use_site_exchange_rate") if "use_site_exchange_rate" in dictionary.keys() else APIHelper.SKIP + include_archived = dictionary.get("include_archived") if "include_archived" in dictionary.keys() else APIHelper.SKIP # Clean out expected properties from dictionary additional_properties = {k: v for k, v in dictionary.items() if k not in cls._names.values()} # Return an object of this model @@ -148,6 +160,7 @@ def from_dictionary(cls, ids, codes, use_site_exchange_rate, + include_archived, additional_properties) def __repr__(self): @@ -160,6 +173,7 @@ def __repr__(self): f'ids={(self.ids if hasattr(self, "ids") else None)!r}, ' f'codes={(self.codes if hasattr(self, "codes") else None)!r}, ' f'use_site_exchange_rate={(self.use_site_exchange_rate if hasattr(self, "use_site_exchange_rate") else None)!r}, ' + f'include_archived={(self.include_archived if hasattr(self, "include_archived") else None)!r}, ' f'additional_properties={self.additional_properties!r})') def __str__(self): @@ -172,4 +186,5 @@ def __str__(self): f'ids={(self.ids if hasattr(self, "ids") else None)!s}, ' f'codes={(self.codes if hasattr(self, "codes") else None)!s}, ' f'use_site_exchange_rate={(self.use_site_exchange_rate if hasattr(self, "use_site_exchange_rate") else None)!s}, ' + f'include_archived={(self.include_archived if hasattr(self, "include_archived") else None)!s}, ' f'additional_properties={self.additional_properties!s})') diff --git a/advancedbilling/models/list_events_date_field.py b/advancedbilling/models/list_events_date_field.py index c42029ef..ae627323 100644 --- a/advancedbilling/models/list_events_date_field.py +++ b/advancedbilling/models/list_events_date_field.py @@ -20,3 +20,25 @@ class ListEventsDateField(object): """ CREATED_AT = 'created_at' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/list_prepayment_date_field.py b/advancedbilling/models/list_prepayment_date_field.py index ee87de58..085f5a5e 100644 --- a/advancedbilling/models/list_prepayment_date_field.py +++ b/advancedbilling/models/list_prepayment_date_field.py @@ -23,3 +23,25 @@ class ListPrepaymentDateField(object): APPLICATION_AT = 'application_at' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/list_products_include.py b/advancedbilling/models/list_products_include.py index 32b25d76..405a5c1c 100644 --- a/advancedbilling/models/list_products_include.py +++ b/advancedbilling/models/list_products_include.py @@ -20,3 +20,25 @@ class ListProductsInclude(object): """ PREPAID_PRODUCT_PRICE_POINT = 'prepaid_product_price_point' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/list_products_price_points_include.py b/advancedbilling/models/list_products_price_points_include.py index af67a74b..5434c550 100644 --- a/advancedbilling/models/list_products_price_points_include.py +++ b/advancedbilling/models/list_products_price_points_include.py @@ -20,3 +20,25 @@ class ListProductsPricePointsInclude(object): """ CURRENCY_PRICES = 'currency_prices' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/list_subscription_components_include.py b/advancedbilling/models/list_subscription_components_include.py index a1c42d02..752d9caa 100644 --- a/advancedbilling/models/list_subscription_components_include.py +++ b/advancedbilling/models/list_subscription_components_include.py @@ -23,3 +23,25 @@ class ListSubscriptionComponentsInclude(object): HISTORIC_USAGES = 'historic_usages' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/list_subscription_components_sort.py b/advancedbilling/models/list_subscription_components_sort.py index ae42e130..83605e01 100644 --- a/advancedbilling/models/list_subscription_components_sort.py +++ b/advancedbilling/models/list_subscription_components_sort.py @@ -23,3 +23,25 @@ class ListSubscriptionComponentsSort(object): UPDATED_AT = 'updated_at' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/metafield.py b/advancedbilling/models/metafield.py index 3e4b00d4..6b5c60d6 100644 --- a/advancedbilling/models/metafield.py +++ b/advancedbilling/models/metafield.py @@ -20,14 +20,11 @@ class Metafield(object): scope (MetafieldScope): Warning: When updating a metafield's scope attribute, all scope attributes must be passed. Partially complete scope attributes will override the existing settings. - data_count (int): the amount of subscriptions this metafield has been - applied to in Chargify - input_type (MetafieldInput): Indicates how data should be added to the - metafield. For example, a text type is just a string, so a given - metafield of this type can have any value attached. On the other - hand, dropdown and radio have a set of allowed values that can be - input, and appear differently on a Public Signup Page. Defaults to - 'text' + data_count (int): The amount of subscriptions this metafield has been + applied to in Advanced Billing. + input_type (MetafieldInput): Indicates the type of metafield. A text + metafield allows any string value. Dropdown and radio metafields + have a set of values that can be selected. Defaults to 'text'. enum (str | List[str] | None): The model property of type str | List[str] | None. additional_properties (Dict[str, object]): The additional properties diff --git a/advancedbilling/models/metafield_input.py b/advancedbilling/models/metafield_input.py index 93bf6159..7de4a54b 100644 --- a/advancedbilling/models/metafield_input.py +++ b/advancedbilling/models/metafield_input.py @@ -12,11 +12,9 @@ class MetafieldInput(object): """Implementation of the 'Metafield Input' enum. - Indicates how data should be added to the metafield. For example, a text - type is just a string, so a given metafield of this type can have any - value attached. On the other hand, dropdown and radio have a set of - allowed values that can be input, and appear differently on a Public - Signup Page. Defaults to 'text' + Indicates the type of metafield. A text metafield allows any string value. + Dropdown and radio metafields have a set of values that can be selected. + Defaults to 'text'. Attributes: BALANCE_TRACKER: The enum member of type str. @@ -48,4 +46,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/metafield_scope.py b/advancedbilling/models/metafield_scope.py index f78fbc76..0108c9b2 100644 --- a/advancedbilling/models/metafield_scope.py +++ b/advancedbilling/models/metafield_scope.py @@ -27,9 +27,13 @@ class MetafieldScope(object): portal (IncludeOption): Include (1) or exclude (0) metafields from the portal. public_show (IncludeOption): Include (1) or exclude (0) metafields + used in [Embeddable + Components](page:development-tools/embeddable-components/overview) from being viewable by your ecosystem. public_edit (IncludeOption): Include (1) or exclude (0) metafields - from being edited by your ecosystem. + used in [Embeddable + Components](page:development-tools/embeddable-components/overview) + from being editable by your ecosystem. hosted (List[str]): The model property of type List[str]. additional_properties (Dict[str, object]): The additional properties for the model. diff --git a/advancedbilling/models/metered_component.py b/advancedbilling/models/metered_component.py index e3a254c1..3df342e1 100644 --- a/advancedbilling/models/metered_component.py +++ b/advancedbilling/models/metered_component.py @@ -48,9 +48,9 @@ class MeteredComponent(object): can contain up to 8 decimal places. i.e. 1.00 or 0.0012 or 0.00000065 tax_code (str): A string representing the tax code related to the - component type. This is especially important when using the - Avalara service to tax based on locale. This attribute has a max - length of 10 characters. + component type. This is especially important when using AvaTax to + tax based on locale. This attribute has a max length of 25 + characters. hide_date_range_on_invoice (bool): (Only available on Relationship Invoicing sites) Boolean flag describing if the service date range should show for the component on generated invoices. diff --git a/advancedbilling/models/nested_subscription_group.py b/advancedbilling/models/nested_subscription_group.py index 6a7c2738..9919bae2 100644 --- a/advancedbilling/models/nested_subscription_group.py +++ b/advancedbilling/models/nested_subscription_group.py @@ -96,6 +96,28 @@ def from_dictionary(cls, primary, additional_properties) + @classmethod + def validate(cls, dictionary): + """Validates dictionary against class required properties + + Args: + dictionary (dictionary): A dictionary representation of the object + as obtained from the deserialization of the server's response. The + keys MUST match property names in the API description. + + Returns: + boolean : if dictionary is valid contains required properties. + + """ + + if isinstance(dictionary, cls): + return True + + if not isinstance(dictionary, dict): + return False + + return True + def __repr__(self): return (f'{self.__class__.__name__}(' f'uid={(self.uid if hasattr(self, "uid") else None)!r}, ' diff --git a/advancedbilling/models/on_off_component.py b/advancedbilling/models/on_off_component.py index 5d324c09..f96a56d4 100644 --- a/advancedbilling/models/on_off_component.py +++ b/advancedbilling/models/on_off_component.py @@ -40,9 +40,9 @@ class OnOffComponent(object): price can contain up to 8 decimal places. i.e. 1.00 or 0.0012 or 0.00000065 tax_code (str): A string representing the tax code related to the - component type. This is especially important when using the - Avalara service to tax based on locale. This attribute has a max - length of 10 characters. + component type. This is especially important when using AvaTax to + tax based on locale. This attribute has a max length of 25 + characters. hide_date_range_on_invoice (bool): (Only available on Relationship Invoicing sites) Boolean flag describing if the service date range should show for the component on generated invoices. diff --git a/advancedbilling/models/pay_pal_vault.py b/advancedbilling/models/pay_pal_vault.py index 3cbc8db5..af80553d 100644 --- a/advancedbilling/models/pay_pal_vault.py +++ b/advancedbilling/models/pay_pal_vault.py @@ -44,4 +44,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/payment_profile_attributes.py b/advancedbilling/models/payment_profile_attributes.py index e0e5af34..a0188e95 100644 --- a/advancedbilling/models/payment_profile_attributes.py +++ b/advancedbilling/models/payment_profile_attributes.py @@ -62,7 +62,7 @@ class PaymentProfileAttributes(object): alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) format (i.e. “US”). This value is merely passed through to the payment gateway. Some gateways require country codes in a specific format. - Please check your gateway’s documentation. If creating an ACH + Check your gateway’s documentation. If creating an ACH subscription, only US is supported at this time. billing_zip (str): (Optional, may be required by your product configuration or gateway settings) The credit card or bank account diff --git a/advancedbilling/models/payment_type.py b/advancedbilling/models/payment_type.py index 76937f25..225197ab 100644 --- a/advancedbilling/models/payment_type.py +++ b/advancedbilling/models/payment_type.py @@ -42,4 +42,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/prepaid_configuration.py b/advancedbilling/models/prepaid_configuration.py index 44766638..145c7021 100644 --- a/advancedbilling/models/prepaid_configuration.py +++ b/advancedbilling/models/prepaid_configuration.py @@ -102,6 +102,28 @@ def from_dictionary(cls, replenish_threshold_amount_in_cents, additional_properties) + @classmethod + def validate(cls, dictionary): + """Validates dictionary against class required properties + + Args: + dictionary (dictionary): A dictionary representation of the object + as obtained from the deserialization of the server's response. The + keys MUST match property names in the API description. + + Returns: + boolean : if dictionary is valid contains required properties. + + """ + + if isinstance(dictionary, cls): + return True + + if not isinstance(dictionary, dict): + return False + + return True + def __repr__(self): return (f'{self.__class__.__name__}(' f'id={(self.id if hasattr(self, "id") else None)!r}, ' diff --git a/advancedbilling/models/prepaid_usage_component.py b/advancedbilling/models/prepaid_usage_component.py index ef474d3b..17b66818 100644 --- a/advancedbilling/models/prepaid_usage_component.py +++ b/advancedbilling/models/prepaid_usage_component.py @@ -57,9 +57,9 @@ class PrepaidUsageComponent(object): can contain up to 8 decimal places. i.e. 1.00 or 0.0012 or 0.00000065 tax_code (str): A string representing the tax code related to the - component type. This is especially important when using the - Avalara service to tax based on locale. This attribute has a max - length of 10 characters. + component type. This is especially important when using AvaTax to + tax based on locale. This attribute has a max length of 25 + characters. hide_date_range_on_invoice (bool): (Only available on Relationship Invoicing sites) Boolean flag describing if the service date range should show for the component on generated invoices. diff --git a/advancedbilling/models/prepayment_method.py b/advancedbilling/models/prepayment_method.py index 7d7244c7..ea625ac0 100644 --- a/advancedbilling/models/prepayment_method.py +++ b/advancedbilling/models/prepayment_method.py @@ -38,3 +38,25 @@ class PrepaymentMethod(object): OTHER = 'other' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/price_point_type.py b/advancedbilling/models/price_point_type.py index 4ec4657b..1638edbc 100644 --- a/advancedbilling/models/price_point_type.py +++ b/advancedbilling/models/price_point_type.py @@ -46,4 +46,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/pricing_scheme.py b/advancedbilling/models/pricing_scheme.py index 43d555fb..5add8653 100644 --- a/advancedbilling/models/pricing_scheme.py +++ b/advancedbilling/models/pricing_scheme.py @@ -46,4 +46,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/product.py b/advancedbilling/models/product.py index ac450752..948f5875 100644 --- a/advancedbilling/models/product.py +++ b/advancedbilling/models/product.py @@ -23,7 +23,7 @@ class Product(object): accounting_code (str): E.g. Internal ID or SKU Number request_credit_card (bool): Deprecated value that can be ignored unless you have legacy hosted pages. For Public Signup Page users, - please read this attribute from under the signup page. + read this attribute from under the signup page. expiration_interval (int): A numerical interval for the length a subscription to this product will run before it expires. See the description of interval for a description of how this value is @@ -79,9 +79,9 @@ class Product(object): shipping address is required for the customer, especially at signup. tax_code (str): A string representing the tax code related to the - product type. This is especially important when using the Avalara - service to tax based on locale. This attribute has a max length of - 10 characters. + product type. This is especially important when using AvaTax to + tax based on locale. This attribute has a max length of 25 + characters. default_product_price_point_id (int): The model property of type int. use_site_exchange_rate (bool): The model property of type bool. item_category (str): One of the following: Business Software, Consumer @@ -422,6 +422,28 @@ def from_dictionary(cls, product_price_point_handle, additional_properties) + @classmethod + def validate(cls, dictionary): + """Validates dictionary against class required properties + + Args: + dictionary (dictionary): A dictionary representation of the object + as obtained from the deserialization of the server's response. The + keys MUST match property names in the API description. + + Returns: + boolean : if dictionary is valid contains required properties. + + """ + + if isinstance(dictionary, cls): + return True + + if not isinstance(dictionary, dict): + return False + + return True + def __repr__(self): return (f'{self.__class__.__name__}(' f'id={(self.id if hasattr(self, "id") else None)!r}, ' diff --git a/advancedbilling/models/product_family.py b/advancedbilling/models/product_family.py index a5749095..523041ea 100644 --- a/advancedbilling/models/product_family.py +++ b/advancedbilling/models/product_family.py @@ -122,6 +122,28 @@ def from_dictionary(cls, updated_at, additional_properties) + @classmethod + def validate(cls, dictionary): + """Validates dictionary against class required properties + + Args: + dictionary (dictionary): A dictionary representation of the object + as obtained from the deserialization of the server's response. The + keys MUST match property names in the API description. + + Returns: + boolean : if dictionary is valid contains required properties. + + """ + + if isinstance(dictionary, cls): + return True + + if not isinstance(dictionary, dict): + return False + + return True + def __repr__(self): return (f'{self.__class__.__name__}(' f'id={(self.id if hasattr(self, "id") else None)!r}, ' diff --git a/advancedbilling/models/product_price_point.py b/advancedbilling/models/product_price_point.py index 19c43ad7..23f673d3 100644 --- a/advancedbilling/models/product_price_point.py +++ b/advancedbilling/models/product_price_point.py @@ -31,7 +31,13 @@ class ProductPricePoint(object): product price point trial would last 30 days trial_interval_unit (IntervalUnit): A string representing the trial interval unit for this product price point, either month or day - trial_type (str): The model property of type str. + trial_type (TrialType): Indicates how a trial is handled when the + trail period ends and there is no credit card on file. For + `no_obligation`, the subscription transitions to a Trial Ended + state. Maxio will not send any emails or statements. For + `payment_expected`, the subscription transitions to a Past Due + state. Maxio will send normal dunning emails and statements + according to your other settings. introductory_offer (bool): reserved for future use initial_charge_in_cents (int): The product price point initial charge, in integer cents @@ -126,6 +132,7 @@ class ProductPricePoint(object): 'trial_price_in_cents', 'trial_interval', 'trial_interval_unit', + 'trial_type', 'introductory_offer', 'initial_charge_in_cents', 'initial_charge_after_trial', @@ -246,7 +253,7 @@ def from_dictionary(cls, trial_price_in_cents = dictionary.get("trial_price_in_cents") if "trial_price_in_cents" in dictionary.keys() else APIHelper.SKIP trial_interval = dictionary.get("trial_interval") if "trial_interval" in dictionary.keys() else APIHelper.SKIP trial_interval_unit = dictionary.get("trial_interval_unit") if "trial_interval_unit" in dictionary.keys() else APIHelper.SKIP - trial_type = dictionary.get("trial_type") if dictionary.get("trial_type") else APIHelper.SKIP + trial_type = dictionary.get("trial_type") if "trial_type" in dictionary.keys() else APIHelper.SKIP introductory_offer = dictionary.get("introductory_offer") if "introductory_offer" in dictionary.keys() else APIHelper.SKIP initial_charge_in_cents = dictionary.get("initial_charge_in_cents") if "initial_charge_in_cents" in dictionary.keys() else APIHelper.SKIP initial_charge_after_trial = dictionary.get("initial_charge_after_trial") if "initial_charge_after_trial" in dictionary.keys() else APIHelper.SKIP diff --git a/advancedbilling/models/proforma_invoice_discount_source_type.py b/advancedbilling/models/proforma_invoice_discount_source_type.py index e127697e..4a99f9ab 100644 --- a/advancedbilling/models/proforma_invoice_discount_source_type.py +++ b/advancedbilling/models/proforma_invoice_discount_source_type.py @@ -23,3 +23,25 @@ class ProformaInvoiceDiscountSourceType(object): REFERRAL = 'Referral' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/proforma_invoice_role.py b/advancedbilling/models/proforma_invoice_role.py index 1d8f72c6..27cf496d 100644 --- a/advancedbilling/models/proforma_invoice_role.py +++ b/advancedbilling/models/proforma_invoice_role.py @@ -32,3 +32,25 @@ class ProformaInvoiceRole(object): PROFORMA_AUTOMATIC = 'proforma_automatic' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/proforma_invoice_status.py b/advancedbilling/models/proforma_invoice_status.py index ff5dc06b..502b5a8d 100644 --- a/advancedbilling/models/proforma_invoice_status.py +++ b/advancedbilling/models/proforma_invoice_status.py @@ -26,3 +26,25 @@ class ProformaInvoiceStatus(object): ARCHIVED = 'archived' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/proforma_invoice_tax_source_type.py b/advancedbilling/models/proforma_invoice_tax_source_type.py index bddbd3c9..09a696db 100644 --- a/advancedbilling/models/proforma_invoice_tax_source_type.py +++ b/advancedbilling/models/proforma_invoice_tax_source_type.py @@ -36,4 +36,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/public_signup_page.py b/advancedbilling/models/public_signup_page.py index 1dd53b6a..a6326e40 100644 --- a/advancedbilling/models/public_signup_page.py +++ b/advancedbilling/models/public_signup_page.py @@ -101,6 +101,28 @@ def from_dictionary(cls, url, additional_properties) + @classmethod + def validate(cls, dictionary): + """Validates dictionary against class required properties + + Args: + dictionary (dictionary): A dictionary representation of the object + as obtained from the deserialization of the server's response. The + keys MUST match property names in the API description. + + Returns: + boolean : if dictionary is valid contains required properties. + + """ + + if isinstance(dictionary, cls): + return True + + if not isinstance(dictionary, dict): + return False + + return True + def __repr__(self): return (f'{self.__class__.__name__}(' f'id={(self.id if hasattr(self, "id") else None)!r}, ' diff --git a/advancedbilling/models/quantity_based_component.py b/advancedbilling/models/quantity_based_component.py index 49b703f3..aa026302 100644 --- a/advancedbilling/models/quantity_based_component.py +++ b/advancedbilling/models/quantity_based_component.py @@ -56,9 +56,9 @@ class QuantityBasedComponent(object): can contain up to 8 decimal places. i.e. 1.00 or 0.0012 or 0.00000065 tax_code (str): A string representing the tax code related to the - component type. This is especially important when using the - Avalara service to tax based on locale. This attribute has a max - length of 10 characters. + component type. This is especially important when using AvaTax to + tax based on locale. This attribute has a max length of 25 + characters. hide_date_range_on_invoice (bool): (Only available on Relationship Invoicing sites) Boolean flag describing if the service date range should show for the component on generated invoices. diff --git a/advancedbilling/models/reactivation_charge.py b/advancedbilling/models/reactivation_charge.py index dff86e7c..2258f372 100644 --- a/advancedbilling/models/reactivation_charge.py +++ b/advancedbilling/models/reactivation_charge.py @@ -46,4 +46,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/recurring_scheme.py b/advancedbilling/models/recurring_scheme.py index 2689fc31..6dfe1cd0 100644 --- a/advancedbilling/models/recurring_scheme.py +++ b/advancedbilling/models/recurring_scheme.py @@ -26,3 +26,25 @@ class RecurringScheme(object): RECUR_WITH_DURATION = 'recur_with_duration' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/resource_type.py b/advancedbilling/models/resource_type.py index 69942d60..f0a7e159 100644 --- a/advancedbilling/models/resource_type.py +++ b/advancedbilling/models/resource_type.py @@ -23,3 +23,25 @@ class ResourceType(object): CUSTOMERS = 'customers' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/restriction_type.py b/advancedbilling/models/restriction_type.py index ce52db59..78aec690 100644 --- a/advancedbilling/models/restriction_type.py +++ b/advancedbilling/models/restriction_type.py @@ -23,3 +23,25 @@ class RestrictionType(object): PRODUCT = 'Product' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/resume_options.py b/advancedbilling/models/resume_options.py index 96313adb..cb93fb9d 100644 --- a/advancedbilling/models/resume_options.py +++ b/advancedbilling/models/resume_options.py @@ -16,7 +16,7 @@ class ResumeOptions(object): Attributes: require_resume (bool): Chargify will only attempt to resume the subscription's billing period. If not resumable, the subscription - will be left in it's current state. + will be left in its current state. forgive_balance (bool): Indicates whether or not Chargify should clear the subscription's existing balance before attempting to resume the subscription. If subscription cannot be resumed, the balance diff --git a/advancedbilling/models/resumption_charge.py b/advancedbilling/models/resumption_charge.py index 68ea0277..2d38e496 100644 --- a/advancedbilling/models/resumption_charge.py +++ b/advancedbilling/models/resumption_charge.py @@ -42,4 +42,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/service_credit_type.py b/advancedbilling/models/service_credit_type.py index 51b39f2a..4b6fba08 100644 --- a/advancedbilling/models/service_credit_type.py +++ b/advancedbilling/models/service_credit_type.py @@ -25,3 +25,25 @@ class ServiceCreditType(object): DEBIT = 'Debit' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/snap_day.py b/advancedbilling/models/snap_day.py index 337af0cf..16f3f01b 100644 --- a/advancedbilling/models/snap_day.py +++ b/advancedbilling/models/snap_day.py @@ -12,9 +12,6 @@ class SnapDay(object): """Implementation of the 'SnapDay' enum. - Use for subscriptions with product eligible for calendar billing only. - Value can be 1-28 or 'end'. - Attributes: END: The enum member of type str. additional_properties (Dict[str, object]): The additional properties @@ -36,4 +33,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/sorting_direction.py b/advancedbilling/models/sorting_direction.py index b27858b9..2f223fad 100644 --- a/advancedbilling/models/sorting_direction.py +++ b/advancedbilling/models/sorting_direction.py @@ -25,3 +25,25 @@ class SortingDirection(object): DESC = 'desc' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/subscription.py b/advancedbilling/models/subscription.py index 343a7a5b..d1dd9e45 100644 --- a/advancedbilling/models/subscription.py +++ b/advancedbilling/models/subscription.py @@ -145,8 +145,9 @@ class Subscription(object): coupon_code (str): (deprecated) The coupon code of the single coupon currently applied to the subscription. See coupon_codes instead as subscriptions can now have more than one coupon. - snap_day (str): The day of the month that the subscription will charge - according to calendar billing rules, if used. + snap_day (int | SnapDay | None): The day of the month that the + subscription will charge according to calendar billing rules, if + used. payment_collection_method (CollectionMethod): The type of payment collection to be used in the subscription. For legacy Statements Architecture valid options are - `invoice`, `automatic`. For @@ -187,8 +188,8 @@ class Subscription(object): paying for the subscription. Defaults to the Customer ID unless the 'Customer Hierarchies & WhoPays' feature is enabled. current_billing_amount_in_cents (int): The balance in cents plus the - estimated renewal amount in cents. Returned ONLY for - readSubscription operation as it's compute intensive operation. + estimated renewal amount in cents. Returned ONLY for the + readSubscription operation as it's a compute intensive operation. product_price_point_id (int): The product price point currently subscribed to. product_price_point_type (PricePointType): Price point type. We expose @@ -618,6 +619,7 @@ def from_dictionary(cls, object: An instance of this structure class. """ + from advancedbilling.utilities.union_type_lookup import UnionTypeLookUp if not isinstance(dictionary, dict) or dictionary is None: return None @@ -674,7 +676,10 @@ def from_dictionary(cls, else: delayed_cancel_at = APIHelper.SKIP coupon_code = dictionary.get("coupon_code") if "coupon_code" in dictionary.keys() else APIHelper.SKIP - snap_day = dictionary.get("snap_day") if "snap_day" in dictionary.keys() else APIHelper.SKIP + if 'snap_day' in dictionary.keys(): + snap_day = APIHelper.deserialize_union_type(UnionTypeLookUp.get('SubscriptionSnapDay'), dictionary.get('snap_day'), False) if dictionary.get('snap_day') is not None else None + else: + snap_day = APIHelper.SKIP payment_collection_method = dictionary.get("payment_collection_method") if dictionary.get("payment_collection_method") else APIHelper.SKIP customer = Customer.from_dictionary(dictionary.get('customer')) if 'customer' in dictionary.keys() else APIHelper.SKIP product = Product.from_dictionary(dictionary.get('product')) if 'product' in dictionary.keys() else APIHelper.SKIP diff --git a/advancedbilling/models/subscription_custom_price.py b/advancedbilling/models/subscription_custom_price.py index 4406252f..024a8d0f 100644 --- a/advancedbilling/models/subscription_custom_price.py +++ b/advancedbilling/models/subscription_custom_price.py @@ -27,6 +27,13 @@ class SubscriptionCustomPrice(object): trial_price_in_cents (str | int | None): (Optional) trial_interval (str | int | None): (Optional) trial_interval_unit (IntervalUnit): (Optional) + trial_type (TrialType): Indicates how a trial is handled when the + trail period ends and there is no credit card on file. For + `no_obligation`, the subscription transitions to a Trial Ended + state. Maxio will not send any emails or statements. For + `payment_expected`, the subscription transitions to a Past Due + state. Maxio will send normal dunning emails and statements + according to your other settings. initial_charge_in_cents (str | int | None): (Optional) initial_charge_after_trial (bool): (Optional) expiration_interval (str | int | None): (Optional) @@ -47,6 +54,7 @@ class SubscriptionCustomPrice(object): "trial_price_in_cents": 'trial_price_in_cents', "trial_interval": 'trial_interval', "trial_interval_unit": 'trial_interval_unit', + "trial_type": 'trial_type', "initial_charge_in_cents": 'initial_charge_in_cents', "initial_charge_after_trial": 'initial_charge_after_trial', "expiration_interval": 'expiration_interval', @@ -60,6 +68,7 @@ class SubscriptionCustomPrice(object): 'trial_price_in_cents', 'trial_interval', 'trial_interval_unit', + 'trial_type', 'initial_charge_in_cents', 'initial_charge_after_trial', 'expiration_interval', @@ -69,6 +78,7 @@ class SubscriptionCustomPrice(object): _nullables = [ 'interval_unit', + 'trial_type', 'expiration_interval_unit', ] @@ -81,6 +91,7 @@ def __init__(self, trial_price_in_cents=APIHelper.SKIP, trial_interval=APIHelper.SKIP, trial_interval_unit=APIHelper.SKIP, + trial_type=APIHelper.SKIP, initial_charge_in_cents=APIHelper.SKIP, initial_charge_after_trial=APIHelper.SKIP, expiration_interval=APIHelper.SKIP, @@ -103,6 +114,8 @@ def __init__(self, self.trial_interval = trial_interval if trial_interval_unit is not APIHelper.SKIP: self.trial_interval_unit = trial_interval_unit + if trial_type is not APIHelper.SKIP: + self.trial_type = trial_type if initial_charge_in_cents is not APIHelper.SKIP: self.initial_charge_in_cents = initial_charge_in_cents if initial_charge_after_trial is not APIHelper.SKIP: @@ -147,6 +160,7 @@ def from_dictionary(cls, trial_price_in_cents = APIHelper.deserialize_union_type(UnionTypeLookUp.get('SubscriptionCustomPriceTrialPriceInCents'), dictionary.get('trial_price_in_cents'), False) if dictionary.get('trial_price_in_cents') is not None else APIHelper.SKIP trial_interval = APIHelper.deserialize_union_type(UnionTypeLookUp.get('SubscriptionCustomPriceTrialInterval'), dictionary.get('trial_interval'), False) if dictionary.get('trial_interval') is not None else APIHelper.SKIP trial_interval_unit = dictionary.get("trial_interval_unit") if dictionary.get("trial_interval_unit") else APIHelper.SKIP + trial_type = dictionary.get("trial_type") if "trial_type" in dictionary.keys() else APIHelper.SKIP initial_charge_in_cents = APIHelper.deserialize_union_type(UnionTypeLookUp.get('SubscriptionCustomPriceInitialChargeInCents'), dictionary.get('initial_charge_in_cents'), False) if dictionary.get('initial_charge_in_cents') is not None else APIHelper.SKIP initial_charge_after_trial = dictionary.get("initial_charge_after_trial") if "initial_charge_after_trial" in dictionary.keys() else APIHelper.SKIP expiration_interval = APIHelper.deserialize_union_type(UnionTypeLookUp.get('SubscriptionCustomPriceExpirationInterval'), dictionary.get('expiration_interval'), False) if dictionary.get('expiration_interval') is not None else APIHelper.SKIP @@ -163,6 +177,7 @@ def from_dictionary(cls, trial_price_in_cents, trial_interval, trial_interval_unit, + trial_type, initial_charge_in_cents, initial_charge_after_trial, expiration_interval, @@ -211,6 +226,7 @@ def __repr__(self): f'trial_price_in_cents={(self.trial_price_in_cents if hasattr(self, "trial_price_in_cents") else None)!r}, ' f'trial_interval={(self.trial_interval if hasattr(self, "trial_interval") else None)!r}, ' f'trial_interval_unit={(self.trial_interval_unit if hasattr(self, "trial_interval_unit") else None)!r}, ' + f'trial_type={(self.trial_type if hasattr(self, "trial_type") else None)!r}, ' f'initial_charge_in_cents={(self.initial_charge_in_cents if hasattr(self, "initial_charge_in_cents") else None)!r}, ' f'initial_charge_after_trial={(self.initial_charge_after_trial if hasattr(self, "initial_charge_after_trial") else None)!r}, ' f'expiration_interval={(self.expiration_interval if hasattr(self, "expiration_interval") else None)!r}, ' @@ -228,6 +244,7 @@ def __str__(self): f'trial_price_in_cents={(self.trial_price_in_cents if hasattr(self, "trial_price_in_cents") else None)!s}, ' f'trial_interval={(self.trial_interval if hasattr(self, "trial_interval") else None)!s}, ' f'trial_interval_unit={(self.trial_interval_unit if hasattr(self, "trial_interval_unit") else None)!s}, ' + f'trial_type={(self.trial_type if hasattr(self, "trial_type") else None)!s}, ' f'initial_charge_in_cents={(self.initial_charge_in_cents if hasattr(self, "initial_charge_in_cents") else None)!s}, ' f'initial_charge_after_trial={(self.initial_charge_after_trial if hasattr(self, "initial_charge_after_trial") else None)!s}, ' f'expiration_interval={(self.expiration_interval if hasattr(self, "expiration_interval") else None)!s}, ' diff --git a/advancedbilling/models/subscription_date_field.py b/advancedbilling/models/subscription_date_field.py index ab525149..e17d3d8e 100644 --- a/advancedbilling/models/subscription_date_field.py +++ b/advancedbilling/models/subscription_date_field.py @@ -44,3 +44,25 @@ class SubscriptionDateField(object): UPDATED_AT = 'updated_at' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/subscription_group_include.py b/advancedbilling/models/subscription_group_include.py index 6f358cf7..6d156e08 100644 --- a/advancedbilling/models/subscription_group_include.py +++ b/advancedbilling/models/subscription_group_include.py @@ -20,3 +20,25 @@ class SubscriptionGroupInclude(object): """ CURRENT_BILLING_AMOUNT_IN_CENTS = 'current_billing_amount_in_cents' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/subscription_group_prepayment_method.py b/advancedbilling/models/subscription_group_prepayment_method.py index 246002c0..ab68c38d 100644 --- a/advancedbilling/models/subscription_group_prepayment_method.py +++ b/advancedbilling/models/subscription_group_prepayment_method.py @@ -35,3 +35,25 @@ class SubscriptionGroupPrepaymentMethod(object): OTHER = 'other' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/subscription_groups_list_include.py b/advancedbilling/models/subscription_groups_list_include.py index 7a964727..c2c94928 100644 --- a/advancedbilling/models/subscription_groups_list_include.py +++ b/advancedbilling/models/subscription_groups_list_include.py @@ -20,3 +20,25 @@ class SubscriptionGroupsListInclude(object): """ ACCOUNT_BALANCES = 'account_balances' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/subscription_include.py b/advancedbilling/models/subscription_include.py index ea494b9b..3940e483 100644 --- a/advancedbilling/models/subscription_include.py +++ b/advancedbilling/models/subscription_include.py @@ -23,3 +23,25 @@ class SubscriptionInclude(object): SELF_SERVICE_PAGE_TOKEN = 'self_service_page_token' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/subscription_included_coupon.py b/advancedbilling/models/subscription_included_coupon.py index 09b947c5..b8a86beb 100644 --- a/advancedbilling/models/subscription_included_coupon.py +++ b/advancedbilling/models/subscription_included_coupon.py @@ -123,6 +123,28 @@ def from_dictionary(cls, percentage, additional_properties) + @classmethod + def validate(cls, dictionary): + """Validates dictionary against class required properties + + Args: + dictionary (dictionary): A dictionary representation of the object + as obtained from the deserialization of the server's response. The + keys MUST match property names in the API description. + + Returns: + boolean : if dictionary is valid contains required properties. + + """ + + if isinstance(dictionary, cls): + return True + + if not isinstance(dictionary, dict): + return False + + return True + def __repr__(self): return (f'{self.__class__.__name__}(' f'code={(self.code if hasattr(self, "code") else None)!r}, ' diff --git a/advancedbilling/models/subscription_list_date_field.py b/advancedbilling/models/subscription_list_date_field.py index 836f91c6..a1d4b9ce 100644 --- a/advancedbilling/models/subscription_list_date_field.py +++ b/advancedbilling/models/subscription_list_date_field.py @@ -20,3 +20,25 @@ class SubscriptionListDateField(object): """ UPDATED_AT = 'updated_at' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/subscription_list_include.py b/advancedbilling/models/subscription_list_include.py index 3883a552..a21de968 100644 --- a/advancedbilling/models/subscription_list_include.py +++ b/advancedbilling/models/subscription_list_include.py @@ -20,3 +20,25 @@ class SubscriptionListInclude(object): """ SELF_SERVICE_PAGE_TOKEN = 'self_service_page_token' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/subscription_purge_type.py b/advancedbilling/models/subscription_purge_type.py index 4f88038d..6d08bae9 100644 --- a/advancedbilling/models/subscription_purge_type.py +++ b/advancedbilling/models/subscription_purge_type.py @@ -23,3 +23,25 @@ class SubscriptionPurgeType(object): PAYMENT_PROFILE = 'payment_profile' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/subscription_sort.py b/advancedbilling/models/subscription_sort.py index e0786afd..83b9c941 100644 --- a/advancedbilling/models/subscription_sort.py +++ b/advancedbilling/models/subscription_sort.py @@ -35,3 +35,25 @@ class SubscriptionSort(object): CREATED_AT = 'created_at' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/subscription_state.py b/advancedbilling/models/subscription_state.py index d7065485..dbfbb479 100644 --- a/advancedbilling/models/subscription_state.py +++ b/advancedbilling/models/subscription_state.py @@ -147,4 +147,26 @@ def validate(cls, value): """ return value in cls._all_values - \ No newline at end of file + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/subscription_state_filter.py b/advancedbilling/models/subscription_state_filter.py index 481b22ea..aeaa25c0 100644 --- a/advancedbilling/models/subscription_state_filter.py +++ b/advancedbilling/models/subscription_state_filter.py @@ -55,3 +55,25 @@ class SubscriptionStateFilter(object): UNPAID = 'unpaid' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/tax_configuration_kind.py b/advancedbilling/models/tax_configuration_kind.py index abb4af56..9d8eaded 100644 --- a/advancedbilling/models/tax_configuration_kind.py +++ b/advancedbilling/models/tax_configuration_kind.py @@ -29,3 +29,25 @@ class TaxConfigurationKind(object): ENUM_DIGITAL_RIVER = 'digital river' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/tax_destination_address.py b/advancedbilling/models/tax_destination_address.py index 1cb04bb9..2777c6e1 100644 --- a/advancedbilling/models/tax_destination_address.py +++ b/advancedbilling/models/tax_destination_address.py @@ -29,3 +29,25 @@ class TaxDestinationAddress(object): BILLING_ONLY = 'billing_only' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/trial_type.py b/advancedbilling/models/trial_type.py new file mode 100644 index 00000000..728b6605 --- /dev/null +++ b/advancedbilling/models/trial_type.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +""" +advanced_billing + +This file was automatically generated for Maxio by APIMATIC v3.0 ( + https://www.apimatic.io ). +""" + + +class TrialType(object): + + """Implementation of the 'Trial Type' enum. + + Indicates how a trial is handled when the trail period ends and there is + no credit card on file. For `no_obligation`, the subscription transitions + to a Trial Ended state. Maxio will not send any emails or statements. For + `payment_expected`, the subscription transitions to a Past Due state. + Maxio will send normal dunning emails and statements according to your + other settings. + + Attributes: + NO_OBLIGATION: The enum member of type str. + PAYMENT_EXPECTED: The enum member of type str. + additional_properties (Dict[str, object]): The additional properties + for the model. + + """ + _all_values = ['no_obligation', 'payment_expected'] + NO_OBLIGATION = 'no_obligation' + + PAYMENT_EXPECTED = 'payment_expected' + + @classmethod + def validate(cls, value): + """Validates value contains in enum + + Args: + value: the value to be validated + + Returns: + boolean : if value is valid enum values. + + """ + return value in cls._all_values + + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/update_component.py b/advancedbilling/models/update_component.py index b4e79891..799d6a2c 100644 --- a/advancedbilling/models/update_component.py +++ b/advancedbilling/models/update_component.py @@ -22,9 +22,9 @@ class UpdateComponent(object): taxable (bool): Boolean flag describing whether a component is taxable or not. tax_code (str): A string representing the tax code related to the - component type. This is especially important when using the - Avalara service to tax based on locale. This attribute has a max - length of 10 characters. + component type. This is especially important when using AvaTax to + tax based on locale. This attribute has a max length of 25 + characters. item_category (ItemCategory): One of the following: Business Software, Consumer Software, Digital Services, Physical Goods, Other display_on_hosted_page (bool): The model property of type bool. diff --git a/advancedbilling/models/update_metafield.py b/advancedbilling/models/update_metafield.py index 4c6f7ced..51d4a8f8 100644 --- a/advancedbilling/models/update_metafield.py +++ b/advancedbilling/models/update_metafield.py @@ -20,13 +20,10 @@ class UpdateMetafield(object): scope (MetafieldScope): Warning: When updating a metafield's scope attribute, all scope attributes must be passed. Partially complete scope attributes will override the existing settings. - input_type (MetafieldInput): Indicates how data should be added to the - metafield. For example, a text type is just a string, so a given - metafield of this type can have any value attached. On the other - hand, dropdown and radio have a set of allowed values that can be - input, and appear differently on a Public Signup Page. Defaults to - 'text' - enum (List[str]): Only applicable when input_type is radio or dropdown + input_type (MetafieldInput): Indicates the type of metafield. A text + metafield allows any string value. Dropdown and radio metafields + have a set of values that can be selected. Defaults to 'text'. + enum (List[str]): Only applicable when input_type is radio or dropdown. additional_properties (Dict[str, object]): The additional properties for the model. diff --git a/advancedbilling/models/update_payment_profile.py b/advancedbilling/models/update_payment_profile.py index 06f796db..ff8fdb34 100644 --- a/advancedbilling/models/update_payment_profile.py +++ b/advancedbilling/models/update_payment_profile.py @@ -45,7 +45,7 @@ class UpdatePaymentProfile(object): alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) format (i.e. “US”). This value is merely passed through to the payment gateway. Some gateways require country codes in a specific format. - Please check your gateway’s documentation. If creating an ACH + Check your gateway’s documentation. If creating an ACH subscription, only US is supported at this time. billing_address_2 (str): Second line of the customer’s billing address i.e. Apt. 100 diff --git a/advancedbilling/models/update_subscription.py b/advancedbilling/models/update_subscription.py index a22d64a6..df3ab622 100644 --- a/advancedbilling/models/update_subscription.py +++ b/advancedbilling/models/update_subscription.py @@ -27,7 +27,7 @@ class UpdateSubscription(object): next_product_id (str): Set to an empty string to cancel a delayed product change. next_product_price_point_id (str): The model property of type str. - snap_day (SnapDay | int | None): Use for subscriptions with product + snap_day (int | SnapDay | None): Use for subscriptions with product eligible for calendar billing only. Value can be 1-28 or 'end'. initial_billing_at (datetime): (Optional) Set this attribute to a future date/time to update a subscription in the Awaiting Signup @@ -137,6 +137,7 @@ class UpdateSubscription(object): ] _nullables = [ + 'snap_day', 'dunning_communication_delay_time_zone', ] @@ -242,7 +243,10 @@ def from_dictionary(cls, product_change_delayed = dictionary.get("product_change_delayed") if "product_change_delayed" in dictionary.keys() else APIHelper.SKIP next_product_id = dictionary.get("next_product_id") if dictionary.get("next_product_id") else APIHelper.SKIP next_product_price_point_id = dictionary.get("next_product_price_point_id") if dictionary.get("next_product_price_point_id") else APIHelper.SKIP - snap_day = APIHelper.deserialize_union_type(UnionTypeLookUp.get('UpdateSubscriptionSnapDay'), dictionary.get('snap_day'), False) if dictionary.get('snap_day') is not None else APIHelper.SKIP + if 'snap_day' in dictionary.keys(): + snap_day = APIHelper.deserialize_union_type(UnionTypeLookUp.get('UpdateSubscriptionSnapDay'), dictionary.get('snap_day'), False) if dictionary.get('snap_day') is not None else None + else: + snap_day = APIHelper.SKIP initial_billing_at = APIHelper.RFC3339DateTime.from_value(dictionary.get("initial_billing_at")).datetime if dictionary.get("initial_billing_at") else APIHelper.SKIP defer_signup = dictionary.get("defer_signup") if dictionary.get("defer_signup") else False next_billing_at = APIHelper.RFC3339DateTime.from_value(dictionary.get("next_billing_at")).datetime if dictionary.get("next_billing_at") else APIHelper.SKIP diff --git a/advancedbilling/models/webhook_order.py b/advancedbilling/models/webhook_order.py index c446516c..3909d1c5 100644 --- a/advancedbilling/models/webhook_order.py +++ b/advancedbilling/models/webhook_order.py @@ -23,3 +23,25 @@ class WebhookOrder(object): OLDEST_FIRST = 'oldest_first' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/webhook_status.py b/advancedbilling/models/webhook_status.py index 9ceceabd..7f4cf448 100644 --- a/advancedbilling/models/webhook_status.py +++ b/advancedbilling/models/webhook_status.py @@ -29,3 +29,25 @@ class WebhookStatus(object): PAUSED = 'paused' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/models/webhook_subscription.py b/advancedbilling/models/webhook_subscription.py index 0a1ec188..b562491d 100644 --- a/advancedbilling/models/webhook_subscription.py +++ b/advancedbilling/models/webhook_subscription.py @@ -124,3 +124,25 @@ class WebhookSubscription(object): SUBSCRIPTION_SERVICE_CREDIT_ACCOUNT_BALANCE_CHANGED = 'subscription_service_credit_account_balance_changed' + @classmethod + def from_value(cls, value, default=None): + if value is None: + return default + + # If numeric and matches directly + if isinstance(value, int): + for name, val in cls.__dict__.items(): + if not name.startswith("_") and val == value: + return val + + # If string, perform case-insensitive match + if isinstance(value, str): + value_lower = value.lower() + for name, val in cls.__dict__.items(): + if not name.startswith("_") and ( + name.lower() == value_lower or str(val).lower() == value_lower + ): + return val + + # Fallback to default + return default diff --git a/advancedbilling/utilities/union_type_lookup.py b/advancedbilling/utilities/union_type_lookup.py index ff869665..cb31cfde 100644 --- a/advancedbilling/utilities/union_type_lookup.py +++ b/advancedbilling/utilities/union_type_lookup.py @@ -74,115 +74,115 @@ class UnionTypeLookUp: """ _templates = { - 'UpdateComponentPricePointComponentId': OneOf( + 'UpdateComponentPricePointComponentId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'UpdateComponentPricePointPricePointId': OneOf( + 'UpdateComponentPricePointPricePointId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'ReadComponentPricePointComponentId': OneOf( + 'ReadComponentPricePointComponentId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'ReadComponentPricePointPricePointId': OneOf( + 'ReadComponentPricePointPricePointId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'ArchiveComponentPricePointComponentId': OneOf( + 'ArchiveComponentPricePointComponentId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'ArchiveComponentPricePointPricePointId': OneOf( + 'ArchiveComponentPricePointPricePointId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'CreateProductPricePointProductId': OneOf( + 'CreateProductPricePointProductId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'ListProductPricePointsInputProductId': OneOf( + 'ListProductPricePointsInputProductId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'UpdateProductPricePointProductId': OneOf( + 'UpdateProductPricePointProductId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'UpdateProductPricePointPricePointId': OneOf( + 'UpdateProductPricePointPricePointId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'ReadProductPricePointProductId': OneOf( + 'ReadProductPricePointProductId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'ReadProductPricePointPricePointId': OneOf( + 'ReadProductPricePointPricePointId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'ArchiveProductPricePointProductId': OneOf( + 'ArchiveProductPricePointProductId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'ArchiveProductPricePointPricePointId': OneOf( + 'ArchiveProductPricePointPricePointId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'CreateUsageSubscriptionIdOrReference': OneOf( + 'CreateUsageSubscriptionIdOrReference': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'CreateUsageComponentId': OneOf( + 'CreateUsageComponentId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'ListUsagesInputSubscriptionIdOrReference': OneOf( + 'ListUsagesInputSubscriptionIdOrReference': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'ListUsagesInputComponentId': OneOf( + 'ListUsagesInputComponentId': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'Invoice-Event': AnyOf( + 'Invoice-Event': lambda: AnyOf( [ LeafType(ApplyCreditNoteEvent, Context.create( @@ -265,7 +265,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'AllocationQuantity': OneOf( + 'AllocationQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -274,7 +274,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'AllocationPreviousQuantity': OneOf( + 'AllocationPreviousQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -283,7 +283,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'AllocationPreviewItemQuantity': OneOf( + 'AllocationPreviewItemQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -292,7 +292,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'AllocationPreviewItemPreviousQuantity': OneOf( + 'AllocationPreviewItemPreviousQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -301,7 +301,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'Invoice-Event-Payment': AnyOf( + 'Invoice-Event-Payment': lambda: AnyOf( [ LeafType(PaymentMethodApplePay, Context.create( @@ -330,16 +330,17 @@ class UnionTypeLookUp: )) ] ), - 'CalendarBillingSnapDay': OneOf( + 'CalendarBillingSnapDay': lambda: OneOf( [ LeafType(int), - LeafType(str) + LeafType(SnapDay) ], Context.create( - is_optional=True + is_optional=True, + is_nullable=True ) ), - 'ComponentAllocationChangeAllocatedQuantity': OneOf( + 'ComponentAllocationChangeAllocatedQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -348,7 +349,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'ComponentPricePointAssignmentPricePoint': OneOf( + 'ComponentPricePointAssignmentPricePoint': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -357,7 +358,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CouponPayloadPercentage': OneOf( + 'CouponPayloadPercentage': lambda: OneOf( [ LeafType(str), LeafType(float) @@ -366,7 +367,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateAllocationPricePointId': OneOf( + 'CreateAllocationPricePointId': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -376,13 +377,13 @@ class UnionTypeLookUp: is_nullable=True ) ), - 'CreateComponentPricePointRequestPricePoint': AnyOf( + 'CreateComponentPricePointRequestPricePoint': lambda: AnyOf( [ LeafType(CreateComponentPricePoint), LeafType(CreatePrepaidUsageComponentPricePoint) ] ), - 'CreateComponentPricePointsRequestPricePoints': AnyOf( + 'CreateComponentPricePointsRequestPricePoints': lambda: AnyOf( [ LeafType(CreateComponentPricePoint), LeafType(CreatePrepaidUsageComponentPricePoint) @@ -391,7 +392,7 @@ class UnionTypeLookUp: is_array=True ) ), - 'CreateInvoiceCouponPercentage': OneOf( + 'CreateInvoiceCouponPercentage': lambda: OneOf( [ LeafType(str), LeafType(float) @@ -400,7 +401,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateInvoiceCouponAmount': OneOf( + 'CreateInvoiceCouponAmount': lambda: OneOf( [ LeafType(str), LeafType(float) @@ -409,7 +410,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateInvoiceCouponProductFamilyId': OneOf( + 'CreateInvoiceCouponProductFamilyId': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -418,7 +419,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateInvoiceItemQuantity': OneOf( + 'CreateInvoiceItemQuantity': lambda: OneOf( [ LeafType(float), LeafType(str) @@ -427,7 +428,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateInvoiceItemUnitPrice': OneOf( + 'CreateInvoiceItemUnitPrice': lambda: OneOf( [ LeafType(float), LeafType(str) @@ -436,7 +437,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateInvoiceItemProductId': OneOf( + 'CreateInvoiceItemProductId': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -445,7 +446,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateInvoiceItemComponentId': OneOf( + 'CreateInvoiceItemComponentId': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -454,7 +455,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateInvoiceItemPricePointId': OneOf( + 'CreateInvoiceItemPricePointId': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -463,7 +464,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateInvoiceItemProductPricePointId': OneOf( + 'CreateInvoiceItemProductPricePointId': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -472,7 +473,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateInvoicePaymentAmount': OneOf( + 'CreateInvoicePaymentAmount': lambda: OneOf( [ LeafType(str), LeafType(float) @@ -481,7 +482,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateMetafieldsRequestMetafields': OneOf( + 'CreateMetafieldsRequestMetafields': lambda: OneOf( [ LeafType(CreateMetafield), LeafType(CreateMetafield, @@ -490,19 +491,19 @@ class UnionTypeLookUp: )) ] ), - 'CreateMultiInvoicePaymentAmount': OneOf( + 'CreateMultiInvoicePaymentAmount': lambda: OneOf( [ LeafType(str), LeafType(float) ] ), - 'CreateOrUpdateSegmentPriceUnitPrice': OneOf( + 'CreateOrUpdateSegmentPriceUnitPrice': lambda: OneOf( [ LeafType(str), LeafType(float) ] ), - 'CreatePaymentProfileExpirationMonth': OneOf( + 'CreatePaymentProfileExpirationMonth': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -511,7 +512,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreatePaymentProfileExpirationYear': OneOf( + 'CreatePaymentProfileExpirationYear': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -520,7 +521,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateSegmentSegmentProperty1Value': OneOf( + 'CreateSegmentSegmentProperty1Value': lambda: OneOf( [ LeafType(str), LeafType(float), @@ -531,7 +532,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateSegmentSegmentProperty2Value': OneOf( + 'CreateSegmentSegmentProperty2Value': lambda: OneOf( [ LeafType(str), LeafType(float), @@ -542,7 +543,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateSegmentSegmentProperty3Value': OneOf( + 'CreateSegmentSegmentProperty3Value': lambda: OneOf( [ LeafType(str), LeafType(float), @@ -553,7 +554,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateSegmentSegmentProperty4Value': OneOf( + 'CreateSegmentSegmentProperty4Value': lambda: OneOf( [ LeafType(str), LeafType(float), @@ -564,7 +565,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateSubscriptionOfferId': OneOf( + 'CreateSubscriptionOfferId': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -573,7 +574,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateSubscriptionComponentComponentId': OneOf( + 'CreateSubscriptionComponentComponentId': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -582,7 +583,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateSubscriptionComponentAllocatedQuantity': OneOf( + 'CreateSubscriptionComponentAllocatedQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -591,7 +592,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateSubscriptionComponentPricePointId': OneOf( + 'CreateSubscriptionComponentPricePointId': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -600,7 +601,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CustomerErrorResponseErrors': OneOf( + 'CustomerErrorResponseErrors': lambda: OneOf( [ LeafType(CustomerError), LeafType(str, @@ -612,13 +613,13 @@ class UnionTypeLookUp: is_optional=True ) ), - 'DeductServiceCreditAmount': OneOf( + 'DeductServiceCreditAmount': lambda: OneOf( [ LeafType(str), LeafType(float) ] ), - 'EBBComponentUnitPrice': OneOf( + 'EBBComponentUnitPrice': lambda: OneOf( [ LeafType(str), LeafType(float) @@ -627,7 +628,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'EventEventSpecificData': OneOf( + 'EventEventSpecificData': lambda: OneOf( [ LeafType(SubscriptionProductChange), LeafType(SubscriptionStateChange), @@ -652,13 +653,13 @@ class UnionTypeLookUp: is_nullable=True ) ), - 'IssueServiceCreditAmount': OneOf( + 'IssueServiceCreditAmount': lambda: OneOf( [ LeafType(float), LeafType(str) ] ), - 'MetafieldEnum': OneOf( + 'MetafieldEnum': lambda: OneOf( [ LeafType(str), LeafType(str, @@ -671,7 +672,7 @@ class UnionTypeLookUp: is_nullable=True ) ), - 'MeteredComponentUnitPrice': OneOf( + 'MeteredComponentUnitPrice': lambda: OneOf( [ LeafType(str), LeafType(float) @@ -680,13 +681,13 @@ class UnionTypeLookUp: is_optional=True ) ), - 'OnOffComponentUnitPrice': OneOf( + 'OnOffComponentUnitPrice': lambda: OneOf( [ LeafType(str), LeafType(float) ] ), - 'PaymentProfileAttributesExpirationMonth': OneOf( + 'PaymentProfileAttributesExpirationMonth': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -695,7 +696,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'PaymentProfileAttributesExpirationYear': OneOf( + 'PaymentProfileAttributesExpirationYear': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -704,7 +705,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'Payment-Profile': AnyOf( + 'Payment-Profile': lambda: AnyOf( [ LeafType(ApplePayPaymentProfile, Context.create( @@ -728,7 +729,7 @@ class UnionTypeLookUp: )) ] ), - 'PrepaidUsageComponentUnitPrice': OneOf( + 'PrepaidUsageComponentUnitPrice': lambda: OneOf( [ LeafType(str), LeafType(float) @@ -737,13 +738,13 @@ class UnionTypeLookUp: is_optional=True ) ), - 'PriceStartingQuantity': OneOf( + 'PriceStartingQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) ] ), - 'PriceEndingQuantity': OneOf( + 'PriceEndingQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -753,13 +754,13 @@ class UnionTypeLookUp: is_nullable=True ) ), - 'PriceUnitPrice': OneOf( + 'PriceUnitPrice': lambda: OneOf( [ LeafType(float), LeafType(str) ] ), - 'QuantityBasedComponentUnitPrice': OneOf( + 'QuantityBasedComponentUnitPrice': lambda: OneOf( [ LeafType(str), LeafType(float) @@ -768,7 +769,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'ReactivateSubscriptionRequestResume': OneOf( + 'ReactivateSubscriptionRequestResume': lambda: OneOf( [ LeafType(bool), LeafType(ResumeOptions) @@ -777,7 +778,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'RefundConsolidatedInvoiceSegmentUids': OneOf( + 'RefundConsolidatedInvoiceSegmentUids': lambda: OneOf( [ LeafType(str, Context.create( @@ -786,19 +787,19 @@ class UnionTypeLookUp: LeafType(str) ] ), - 'RefundInvoiceRequestRefund': AnyOf( + 'RefundInvoiceRequestRefund': lambda: AnyOf( [ LeafType(RefundInvoice), LeafType(RefundConsolidatedInvoice) ] ), - 'RefundPrepaymentAmount': OneOf( + 'RefundPrepaymentAmount': lambda: OneOf( [ LeafType(str), LeafType(float) ] ), - 'RenewalPreviewComponentComponentId': OneOf( + 'RenewalPreviewComponentComponentId': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -807,7 +808,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'RenewalPreviewComponentPricePointId': OneOf( + 'RenewalPreviewComponentPricePointId': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -816,7 +817,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SegmentSegmentProperty1Value': OneOf( + 'SegmentSegmentProperty1Value': lambda: OneOf( [ LeafType(str), LeafType(float), @@ -827,7 +828,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SegmentSegmentProperty2Value': OneOf( + 'SegmentSegmentProperty2Value': lambda: OneOf( [ LeafType(str), LeafType(float), @@ -838,7 +839,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SegmentSegmentProperty3Value': OneOf( + 'SegmentSegmentProperty3Value': lambda: OneOf( [ LeafType(str), LeafType(float), @@ -849,7 +850,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SegmentSegmentProperty4Value': OneOf( + 'SegmentSegmentProperty4Value': lambda: OneOf( [ LeafType(str), LeafType(float), @@ -860,7 +861,17 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionComponentAllocatedQuantity': OneOf( + 'SubscriptionSnapDay': lambda: OneOf( + [ + LeafType(int), + LeafType(SnapDay) + ], + Context.create( + is_optional=True, + is_nullable=True + ) + ), + 'SubscriptionComponentAllocatedQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -869,19 +880,19 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionCustomPricePriceInCents': OneOf( + 'SubscriptionCustomPricePriceInCents': lambda: OneOf( [ LeafType(str), LeafType(int) ] ), - 'SubscriptionCustomPriceInterval': OneOf( + 'SubscriptionCustomPriceInterval': lambda: OneOf( [ LeafType(str), LeafType(int) ] ), - 'SubscriptionCustomPriceTrialPriceInCents': OneOf( + 'SubscriptionCustomPriceTrialPriceInCents': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -890,7 +901,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionCustomPriceTrialInterval': OneOf( + 'SubscriptionCustomPriceTrialInterval': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -899,7 +910,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionCustomPriceInitialChargeInCents': OneOf( + 'SubscriptionCustomPriceInitialChargeInCents': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -908,7 +919,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionCustomPriceExpirationInterval': OneOf( + 'SubscriptionCustomPriceExpirationInterval': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -917,14 +928,14 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionGroupCreateErrorResponseErrors': OneOf( + 'SubscriptionGroupCreateErrorResponseErrors': lambda: OneOf( [ LeafType(SubscriptionGroupMembersArrayError), LeafType(SubscriptionGroupSingleError), LeafType(str) ] ), - 'SubscriptionGroupCreditCardFullNumber': OneOf( + 'SubscriptionGroupCreditCardFullNumber': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -933,7 +944,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionGroupCreditCardExpirationMonth': OneOf( + 'SubscriptionGroupCreditCardExpirationMonth': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -942,7 +953,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionGroupCreditCardExpirationYear': OneOf( + 'SubscriptionGroupCreditCardExpirationYear': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -951,7 +962,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionGroupSignupComponentComponentId': OneOf( + 'SubscriptionGroupSignupComponentComponentId': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -960,7 +971,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionGroupSignupComponentAllocatedQuantity': OneOf( + 'SubscriptionGroupSignupComponentAllocatedQuantity': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -969,7 +980,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionGroupSignupComponentUnitBalance': OneOf( + 'SubscriptionGroupSignupComponentUnitBalance': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -978,7 +989,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionGroupSignupComponentPricePointId': OneOf( + 'SubscriptionGroupSignupComponentPricePointId': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -987,7 +998,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'UpdateMetafieldsRequestMetafields': OneOf( + 'UpdateMetafieldsRequestMetafields': lambda: OneOf( [ LeafType(UpdateMetafield), LeafType(UpdateMetafield, @@ -999,7 +1010,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'UpdatePriceEndingQuantity': OneOf( + 'UpdatePriceEndingQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -1008,7 +1019,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'UpdatePriceUnitPrice': OneOf( + 'UpdatePriceUnitPrice': lambda: OneOf( [ LeafType(float), LeafType(str) @@ -1017,7 +1028,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'UpdatePriceStartingQuantity': OneOf( + 'UpdatePriceStartingQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -1026,16 +1037,17 @@ class UnionTypeLookUp: is_optional=True ) ), - 'UpdateSubscriptionSnapDay': OneOf( + 'UpdateSubscriptionSnapDay': lambda: OneOf( [ - LeafType(SnapDay), - LeafType(int) + LeafType(int), + LeafType(SnapDay) ], Context.create( - is_optional=True + is_optional=True, + is_nullable=True ) ), - 'UpdateSubscriptionNetTerms': OneOf( + 'UpdateSubscriptionNetTerms': lambda: OneOf( [ LeafType(str), LeafType(int) @@ -1044,7 +1056,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'UsageQuantity': OneOf( + 'UsageQuantity': lambda: OneOf( [ LeafType(int), LeafType(str) @@ -1057,5 +1069,5 @@ class UnionTypeLookUp: @staticmethod def get(name): - return UnionTypeLookUp._templates[name] + return UnionTypeLookUp._templates[name]() diff --git a/doc/client.md b/doc/client.md index fb4eb6b5..214fa1c4 100644 --- a/doc/client.md +++ b/doc/client.md @@ -7,7 +7,7 @@ The following parameters are configurable for the API Client: | --- | --- | --- | | site | `str` | The subdomain for your Advanced Billing site.
*Default*: `'subdomain'` | | environment | `Environment` | The API environment.
**Default: `Environment.US`** | -| http_client_instance | `HttpClient` | The Http Client passed from the sdk user for making requests | +| http_client_instance | `Union[Session, HttpClientProvider]` | The Http Client passed from the sdk user for making requests | | override_http_client_configuration | `bool` | The value which determines to override properties of the passed Http Client from the sdk user | | http_call_back | `HttpCallBack` | The callback value that is invoked before and after an HTTP call is made to an endpoint | | timeout | `float` | The value to use for connection timeout.
**Default: 120** | @@ -20,6 +20,8 @@ The following parameters are configurable for the API Client: The API client can be initialized as follows: +## Code-Based Client Initialization + ```python from advancedbilling.advanced_billing_client import AdvancedBillingClient from advancedbilling.configuration import Environment @@ -35,6 +37,17 @@ client = AdvancedBillingClient( ) ``` +## Environment-Based Client Initialization + +```python +from advancedbilling.advanced_billing_client import AdvancedBillingClient + +# Specify the path to your .env file if it’s located outside the project’s root directory. +client = AdvancedBillingClient.from_environment(dotenv_path='/path/to/.env') +``` + +See the [Environment-Based Client Initialization](../doc/environment-based-client-initialization.md) section for details. + ## Maxio Advanced Billing Client The gateway for the SDK. This class acts as a factory for the Controllers and also holds the configuration of the SDK. diff --git a/doc/controllers/advance-invoice.md b/doc/controllers/advance-invoice.md index 4a9e98bd..fd1138fe 100644 --- a/doc/controllers/advance-invoice.md +++ b/doc/controllers/advance-invoice.md @@ -17,7 +17,7 @@ advance_invoice_controller = client.advance_invoice # Issue Advance Invoice -Generate an invoice in advance for a subscription's next renewal date. [Please see our docs](https://maxio.zendesk.com/hc/en-us/articles/24252026404749-Issue-Invoice-In-Advance) for more information on advance invoices, including eligibility on generating one; for the most part, they function like any other invoice, except they are issued early and have special behavior upon being voided. +Generate an invoice in advance for a subscription's next renewal date. [See our docs](https://maxio.zendesk.com/hc/en-us/articles/24252026404749-Issue-Invoice-In-Advance) for more information on advance invoices, including eligibility on generating one; for the most part, they function like any other invoice, except they are issued early and have special behavior upon being voided. A subscription may only have one advance invoice per billing period. Attempting to issue an advance invoice when one already exists will return an error. That said, regeneration of the invoice may be forced with the params `force: true`, which will void an advance invoice if one exists and generate a new one. If no advance invoice exists, a new one will be generated. We recommend using either the create or preview endpoints for proforma invoices to preview this advance invoice before using this endpoint to generate it. @@ -101,7 +101,7 @@ print(result) # Void Advance Invoice Void a subscription's existing advance invoice. Once voided, it can later be regenerated if desired. -A `reason` is required in order to void, and the invoice must have an open status. Voiding will cause any prepayments and credits that were applied to the invoice to be returned to the subscription. For a full overview of the impact of voiding, please [see our help docs](../../doc/models/invoice.md). +A `reason` is required in order to void, and the invoice must have an open status. Voiding will cause any prepayments and credits that were applied to the invoice to be returned to the subscription. For a full overview of the impact of voiding, [see our help docs](../../doc/models/invoice.md). ```python def void_advance_invoice(self, diff --git a/doc/controllers/api-exports.md b/doc/controllers/api-exports.md index 41286cc7..5251b006 100644 --- a/doc/controllers/api-exports.md +++ b/doc/controllers/api-exports.md @@ -50,7 +50,7 @@ def list_exported_proforma_invoices(self, collect = { 'batch_id': 'batch_id8', 'per_page': 100, - 'page': 2 + 'page': 1 } result = api_exports_controller.list_exported_proforma_invoices(collect) print(result) @@ -92,7 +92,7 @@ def list_exported_invoices(self, collect = { 'batch_id': 'batch_id8', 'per_page': 100, - 'page': 2 + 'page': 1 } result = api_exports_controller.list_exported_invoices(collect) print(result) @@ -134,7 +134,7 @@ def list_exported_subscriptions(self, collect = { 'batch_id': 'batch_id8', 'per_page': 100, - 'page': 2 + 'page': 1 } result = api_exports_controller.list_exported_subscriptions(collect) print(result) diff --git a/doc/controllers/billing-portal.md b/doc/controllers/billing-portal.md index 25cfb344..7029fa9b 100644 --- a/doc/controllers/billing-portal.md +++ b/doc/controllers/billing-portal.md @@ -32,7 +32,7 @@ If your customer has been invited to the Billing Portal, then they will receive If you need to provide your customer their Management URL through other means, you can retrieve it via the API. Because the URL is cryptographically signed with a timestamp, it is not possible for merchants to generate the URL without requesting it from Advanced Billing. -In order to prevent abuse & overuse, we ask that you request a new URL only when absolutely necessary. Management URLs are good for 65 days, so you should re-use a previously generated one as much as possible. If you use the URL frequently (such as to display on your website), please **do not** make an API request to Advanced Billing every time. +In order to prevent abuse & overuse, we ask that you request a new URL only when absolutely necessary. Management URLs are good for 65 days, so you should re-use a previously generated one as much as possible. If you use the URL frequently (such as to display on your website), **do not** make an API request to Advanced Billing every time. ```python def enable_billing_portal_for_customer(self, diff --git a/doc/controllers/component-price-points.md b/doc/controllers/component-price-points.md index 434c5cc8..7edfec09 100644 --- a/doc/controllers/component-price-points.md +++ b/doc/controllers/component-price-points.md @@ -191,7 +191,7 @@ def list_component_price_points(self, ```python collect = { 'component_id': 222, - 'page': 2, + 'page': 1, 'per_page': 50, 'filter_type': Liquid error: Value cannot be null. (Parameter 'key') } @@ -378,7 +378,7 @@ print(result) # Update Component Price Point -When updating a price point, it's prices can be updated as well by creating new prices or editing / removing existing ones. +When updating a price point, prices can be updated as well by creating new prices or editing / removing existing ones. Passing in a price bracket without an `id` will attempt to create a new price. @@ -808,7 +808,7 @@ def list_all_component_price_points(self, ```python collect = { 'include': ListComponentsPricePointsInclude.CURRENCY_PRICES, - 'page': 2, + 'page': 1, 'per_page': 50, 'filter': ListPricePointsFilter( start_date=dateutil.parser.parse('2011-12-17').date(), diff --git a/doc/controllers/components.md b/doc/controllers/components.md index 15c203fc..22defde8 100644 --- a/doc/controllers/components.md +++ b/doc/controllers/components.md @@ -32,7 +32,7 @@ Metered components are used to bill for any type of unit that resets to 0 at the Note that this is different from recurring quantity-based components, which DO NOT reset to zero at the start of every billing period. If you want to bill for a quantity of something that does not change unless you change it, then you want quantity components, instead. -For more information on components, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Components-Overview). +For more information on components, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Components-Overview). ```python def create_metered_component(self, @@ -152,7 +152,7 @@ One-time quantity-based components are used to create ad hoc usage charges that The allocated quantity for one-time quantity-based components immediately gets reset back to zero after the allocation is made. -For more information on components, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Components-Overview). +For more information on components, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Components-Overview). ```python def create_quantity_based_component(self, @@ -263,7 +263,7 @@ This request will create a component definition of kind **on_off_component** und On/off components are used for any flat fee, recurring add on (think $99/month for tech support or a flat add on shipping fee). -For more information on components, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Components-Overview). +For more information on components, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Components-Overview). ```python def create_on_off_component(self, @@ -359,7 +359,7 @@ This request will create a component definition of kind **prepaid_usage_componen Prepaid components allow customers to pre-purchase units that can be used up over time on their subscription. In a sense, they are the mirror image of metered components; while metered components charge at the end of the period for the amount of units used, prepaid components are charged for at the time of purchase, and we subsequently keep track of the usage against the amount purchased. -For more information on components, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Components-Overview). +For more information on components, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Components-Overview). ```python def create_prepaid_usage_component(self, @@ -495,7 +495,7 @@ Event-based components are similar to other component types, in that you define So, instead of reporting usage directly for each component (as you would with metered components), the usage is derived from analysis of your events. -For more information on components, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Components-Overview). +For more information on components, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261141522189-Components-Overview). ```python def create_event_based_component(self, @@ -902,7 +902,7 @@ def list_components(self, ```python collect = { 'date_field': BasicDateField.UPDATED_AT, - 'page': 2, + 'page': 1, 'per_page': 50, 'filter': ListComponentsFilter( ids=[ @@ -1127,7 +1127,7 @@ def list_components_for_product_family(self, ```python collect = { 'product_family_id': 140, - 'page': 2, + 'page': 1, 'per_page': 50, 'filter': ListComponentsFilter( ids=[ diff --git a/doc/controllers/coupons.md b/doc/controllers/coupons.md index 466d4b4b..08bc1d80 100644 --- a/doc/controllers/coupons.md +++ b/doc/controllers/coupons.md @@ -30,9 +30,9 @@ coupons_controller = client.coupons ## Coupons Documentation -Coupons can be administered in the Advanced Billing application or created via API. Please view our section on [creating coupons](https://maxio.zendesk.com/hc/en-us/articles/24261212433165-Creating-Editing-Deleting-Coupons) for more information. +Coupons can be administered in the Advanced Billing application or created via API. View our section on [creating coupons](https://maxio.zendesk.com/hc/en-us/articles/24261212433165-Creating-Editing-Deleting-Coupons) for more information. -Additionally, for documentation on how to apply a coupon to a subscription within the Advanced Billing UI, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupons-and-Subscriptions). +Additionally, for documentation on how to apply a coupon to a subscription within the Advanced Billing UI, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupons-and-Subscriptions). ## Create Coupon @@ -107,8 +107,6 @@ print(result) List coupons for a specific Product Family in a Site. -If the coupon is set to `use_site_exchange_rate: true`, it will return pricing based on the current exchange rate. If the flag is set to false, it will return all of the defined prices for each currency. - ```python def list_coupons_for_product_family(self, options=dict()) @@ -133,7 +131,7 @@ def list_coupons_for_product_family(self, ```python collect = { 'product_family_id': 140, - 'page': 2, + 'page': 1, 'per_page': 50, 'filter': ListCouponsFilter( start_date=dateutil.parser.parse('2011-12-17').date(), @@ -532,8 +530,6 @@ print(result) You can retrieve a list of coupons. -If the coupon is set to `use_site_exchange_rate: true`, it will return pricing based on the current exchange rate. If the flag is set to false, it will return all of the defined prices for each currency. - ```python def list_coupons(self, options=dict()) @@ -556,7 +552,7 @@ def list_coupons(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50, 'filter': ListCouponsFilter( start_date=dateutil.parser.parse('2011-12-17').date(), @@ -642,8 +638,8 @@ def read_coupon_usage(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `product_family_id` | `int` | Template, Required | The Advanced Billing id of the product family to which the coupon belongs | -| `coupon_id` | `int` | Template, Required | The Advanced Billing id of the coupon | +| `product_family_id` | `int` | Template, Required | The Advanced Billing id of the product family to which the coupon belongs. | +| `coupon_id` | `int` | Template, Required | The Advanced Billing id of the coupon. | ## Response Type @@ -865,7 +861,7 @@ When creating a coupon subcode, you must specify a coupon to attach it to using Full documentation on how to create coupon subcodes in the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24261208729229-Coupon-Codes). -Additionally, for documentation on how to apply a coupon to a Subscription within the Advanced Billing UI, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupons-and-Subscriptions). +Additionally, for documentation on how to apply a coupon to a Subscription within the Advanced Billing UI, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupons-and-Subscriptions). ## Create Coupon Subcode @@ -958,7 +954,7 @@ def list_coupon_subcodes(self, ```python collect = { 'coupon_id': 162, - 'page': 2, + 'page': 1, 'per_page': 50 } result = coupons_controller.list_coupon_subcodes(collect) diff --git a/doc/controllers/custom-fields.md b/doc/controllers/custom-fields.md index 96eefd0a..21c068cb 100644 --- a/doc/controllers/custom-fields.md +++ b/doc/controllers/custom-fields.md @@ -23,30 +23,20 @@ custom_fields_controller = client.custom_fields # Create Metafields -## Custom Fields: Metafield Intro +Creates metafields on a Site for either the Subscriptions or Customers resource. -**Advanced Billing refers to Custom Fields in the API documentation as metafields and metadata.** Within the Advanced Billing UI, metadata and metafields are grouped together under the umbrella of "Custom Fields." All of our UI-based documentation that references custom fields will not cite the terminology metafields or metadata. +Metafields and their metadata are created in the Custom Fields configuration page on your Site. Metafields can be populated with metadata when you create them or later with the [Update Metafield](../../doc/controllers/custom-fields.md#update-metafield), [Create Metadata](../../doc/controllers/custom-fields.md#create-metadata), or [Update Metadata](../../doc/controllers/custom-fields.md#update-metadata) endpoints. The Create Metadata and Update Metadata endpoints allow you to add metafields and metadata values to a specific subscription or customer. -+ **Metafield is the custom field** -+ **Metadata is the data populating the custom field.** +Each site is limited to 100 unique metafields per resource. This means you can have 100 metafields for Subscriptions and another 100 for Customers. -Advanced Billing Metafields are used to add meaningful attributes to subscription and customer resources. Full documentation on how to create Custom Fields in the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/sections/24266118312589-Custom-Fields). For additional documentation on how to record data within custom fields, please see our subscription-based documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24251701302925-Subscription-Summary-Custom-Fields-Tab). +> Note: After creating a metafield, the resource type cannot be modified. -Metafield are the place where you will set up your resource to accept additional data. It is scoped to the site instead of a specific customer or subscription. Think of it as the key, and Metadata as the value on every record. +In the UI and product documentation, metafields and metadata are called Custom Fields. -## Create Metafields +- Metafield is the custom field +- Metadata is the data populating the custom field. -Use this endpoint to create metafields for your Site. Metafields can be populated with metadata after the fact. - -Each site is limited to 100 unique Metafields (i.e. keys, or names) per resource. This means you can have 100 Metafields for Subscription and another 100 for Customer. - -### Metafields "On-the-Fly" - -It is possible to create Metafields “on the fly” when you create your Metadata – if a non-existent name is passed when creating Metadata, a Metafield for that key will be automatically created. The Metafield API, however, gives you more control over your “keys”. - -### Metafield Scope Warning - -If configuring metafields in the Admin UI or via the API, be careful sending updates to metafields with the scope attribute – **if a partial update is sent it will overwrite the current configuration**. +See [Custom Fields Reference](https://docs.maxio.com/hc/en-us/articles/24266140850573-Custom-Fields-Reference) and [Custom Fields Tab](https://maxio.zendesk.com/hc/en-us/articles/24251701302925-Subscription-Summary-Custom-Fields-Tab) for information on using Custom Fields in the Advanced Billing UI. ```python def create_metafields(self, @@ -58,7 +48,7 @@ def create_metafields(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | the resource type to which the metafields belong | +| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | The resource type to which the metafields belong. | | `body` | [`CreateMetafieldsRequest`](../../doc/models/create-metafields-request.md) | Body, Optional | - | ## Response Type @@ -74,8 +64,10 @@ body = CreateMetafieldsRequest( metafields=CreateMetafield( name='Dropdown field', scope=MetafieldScope( - public_show=IncludeOption.INCLUDE, - public_edit=IncludeOption.INCLUDE + csv=IncludeOption.EXCLUDE, + invoices=IncludeOption.EXCLUDE, + statements=IncludeOption.EXCLUDE, + portal=IncludeOption.INCLUDE ), input_type=MetafieldInput.DROPDOWN, enum=[ @@ -132,7 +124,7 @@ print(result) # List Metafields -This endpoint lists metafields associated with a site. The metafield description and usage is contained in the response. +Lists the metafields and their associated details for a Site and resource type. You can filter the request to a specific metafield. ```python def list_metafields(self, @@ -143,8 +135,8 @@ def list_metafields(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | the resource type to which the metafields belong | -| `name` | `str` | Query, Optional | filter by the name of the metafield | +| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | The resource type to which the metafields belong. | +| `name` | `str` | Query, Optional | Filter by the name of the metafield. | | `page` | `int` | Query, Optional | Result records are organized in pages. By default, the first page of results is displayed. The page parameter specifies a page number of results to fetch. You can start navigating through the pages to consume the results. You do this by passing in a page parameter. Retrieve the next page by adding ?page=2 to the query string. If there are no results to return, then an empty result set will be returned.
Use in query `page=1`.

**Default**: `1`

**Constraints**: `>= 1` | | `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request. Default value is 20. The maximum allowed values is 200; any per_page value over 200 will be changed to 200.
Use in query `per_page=200`.

**Default**: `20`

**Constraints**: `<= 200` | | `direction` | [`SortingDirection`](../../doc/models/sorting-direction.md) | Query, Optional | Controls the order in which results are returned.
Use in query `direction=asc`. | @@ -158,7 +150,7 @@ def list_metafields(self, ```python collect = { 'resource_type': ResourceType.SUBSCRIPTIONS, - 'page': 2, + 'page': 1, 'per_page': 50 } result = custom_fields_controller.list_metafields(collect) @@ -169,10 +161,10 @@ print(result) ```json { - "total_count": 0, - "current_page": 0, + "total_count": 1, + "current_page": 1, "total_pages": 0, - "per_page": 0, + "per_page": 50, "metafields": [ { "id": 0, @@ -196,7 +188,33 @@ print(result) # Update Metafield -Use the following method to update metafields for your Site. Metafields can be populated with metadata after the fact. +Updates metafields on your Site for a resource type. Depending on the request structure, you can update or add metafields and metadata to the Subscriptions or Customers resource. + +With this endpoint, you can: + +- Add metafields. If the metafield specified in current_name does not exist, a new metafield is added. + + > Note: Each site is limited to 100 unique metafields per resource. This means you can have 100 metafields for Subscriptions and another 100 for Customers. + +- Change the name of a metafield. + + > Note: To keep the metafield name the same and only update the metadata for the metafield, you must use the current metafield name in both the `current_name` and `name` parameters. + +- Change the input type for the metafield. For example, you can change a metafield input type from text to a dropdown. If you change the input type from text to a dropdown or radio, you must update the specific subscriptions or customers where the metafield was used to reflect the updated metafield and metadata. + +- Add metadata values to the existing metadata for a dropdown or radio metafield. + + > Note: Updates to metadata overwrite. To add one or more values, you must specify all metadata values including the new value you want to add. + +- Add new metadata to a dropdown or radio for a metafield that was created without metadata. + +- Remove metadata for a dropdown or radio for a metafield. + + > Note: Updates to metadata overwrite existing values. To remove one or more values, specify all metadata values except those you want to remove. + +- Add or update scope settings for a metafield. + + > Note: Scope changes overwrite existing settings. You must specify the complete scope, including the changes you want to make. ```python def update_metafield(self, @@ -208,7 +226,7 @@ def update_metafield(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | the resource type to which the metafields belong | +| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | The resource type to which the metafields belong. | | `body` | [`UpdateMetafieldsRequest`](../../doc/models/update-metafields-request.md) | Body, Optional | - | ## Response Type @@ -233,9 +251,7 @@ print(result) # Delete Metafield -Use the following method to delete a metafield. This will remove the metafield from the Site. - -Additionally, this will remove the metafield and associated metadata with all Subscriptions on the Site. +Deletes a metafield from your Site. Removes the metafield and associated metadata from all Subscriptions or Customers resources on the Site. ```python def delete_metafield(self, @@ -247,7 +263,7 @@ def delete_metafield(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | the resource type to which the metafields belong | +| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | The resource type to which the metafields belong. | | `name` | `str` | Query, Optional | The name of the metafield to be deleted | ## Response Type @@ -271,28 +287,11 @@ custom_fields_controller.delete_metafield(resource_type) # Create Metadata -## Custom Fields: Metadata Intro +Creates metadata and metafields for a specific subscription or customer, or updates metadata values of existing metafields for a subscription or customer. Metadata values are limited to 2 KB in size. -**Advanced Billing refers to Custom Fields in the API documentation as metafields and metadata.** Within the Advanced Billing UI, metadata and metafields are grouped together under the umbrella of "Custom Fields." All of our UI-based documentation that references custom fields will not cite the terminology metafields or metadata. +If you create metadata on a subscription or customer with a metafield that does not already exist, the metafield is created with the metadata you specify and it is always added as a text field. You can update the input_type for the metafield with the [Update Metafield](../../doc/controllers/custom-fields.md#update-metafield) endpoint. -+ **Metafield is the custom field** -+ **Metadata is the data populating the custom field.** - -Advanced Billing Metafields are used to add meaningful attributes to subscription and customer resources. Full documentation on how to create Custom Fields in the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24266164865677-Custom-Fields-Overview). For additional documentation on how to record data within custom fields, please see our subscription-based documentation [here.](https://maxio.zendesk.com/hc/en-us/articles/24251701302925-Subscription-Summary-Custom-Fields-Tab) - -Metadata is associated to a customer or subscription, and corresponds to a Metafield. When creating a new metadata object for a given record, **if the metafield is not present it will be created**. - -## Metadata limits - -Metadata values are limited to 2kB in size. Additonally, there are limits on the number of unique metafields available per resource. - -## Create Metadata - -This method will create a metafield for the site on the fly if it does not already exist, and populate the metadata value. - -### Subscription or Customer Resource - -Please pay special attention to the resource you use when creating metadata. +> Note: Each site is limited to 100 unique metafields per resource. This means you can have 100 metafields for Subscriptions and another 100 for Customers. ```python def create_metadata(self, @@ -305,7 +304,7 @@ def create_metadata(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | the resource type to which the metafields belong | +| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | The resource type to which the metafields belong. | | `resource_id` | `int` | Template, Required | The Advanced Billing id of the customer or the subscription for which the metadata applies | | `body` | [`CreateMetadataRequest`](../../doc/models/create-metadata-request.md) | Body, Optional | - | @@ -350,11 +349,7 @@ print(result) # List Metadata -This request will list all of the metadata belonging to a particular resource (ie. subscription, customer) that is specified. - -## Metadata Data - -This endpoint will also display the current stats of your metadata to use as a tool for pagination. +Lists metadata and metafields for a specific customer or subscription. ```python def list_metadata(self, @@ -365,7 +360,7 @@ def list_metadata(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | the resource type to which the metafields belong | +| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | The resource type to which the metafields belong. | | `resource_id` | `int` | Template, Required | The Advanced Billing id of the customer or the subscription for which the metadata applies | | `page` | `int` | Query, Optional | Result records are organized in pages. By default, the first page of results is displayed. The page parameter specifies a page number of results to fetch. You can start navigating through the pages to consume the results. You do this by passing in a page parameter. Retrieve the next page by adding ?page=2 to the query string. If there are no results to return, then an empty result set will be returned.
Use in query `page=1`.

**Default**: `1`

**Constraints**: `>= 1` | | `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request. Default value is 20. The maximum allowed values is 200; any per_page value over 200 will be changed to 200.
Use in query `per_page=200`.

**Default**: `20`

**Constraints**: `<= 200` | @@ -380,17 +375,42 @@ def list_metadata(self, collect = { 'resource_type': ResourceType.SUBSCRIPTIONS, 'resource_id': 60, - 'page': 2, + 'page': 1, 'per_page': 50 } result = custom_fields_controller.list_metadata(collect) print(result) ``` +## Example Response *(as JSON)* + +```json +{ + "total_count": 1, + "current_page": 1, + "total_pages": 1, + "per_page": 50, + "metadata": [ + { + "id": 77889911, + "value": "green", + "resource_id": 1234567, + "metafield_id": 112233, + "deleted_at": null, + "name": "Color" + } + ] +} +``` + # Update Metadata -This method allows you to update the existing metadata associated with a subscription or customer. +Updates metadata and metafields on the Site and the customer or subscription specified, and updates the metadata value on a subscription or customer. + +If you update metadata on a subscription or customer with a metafield that does not already exist, the metafield is created with the metadata you specify and it is always added as a text field to the Site and to the subscription or customer you specify. You can update the input_type for the metafield with the Update Metafield endpoint. + +Each site is limited to 100 unique metafields per resource. This means you can have 100 metafields for Subscription and another 100 for Customer. ```python def update_metadata(self, @@ -403,7 +423,7 @@ def update_metadata(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | the resource type to which the metafields belong | +| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | The resource type to which the metafields belong. | | `resource_id` | `int` | Template, Required | The Advanced Billing id of the customer or the subscription for which the metadata applies | | `body` | [`UpdateMetadataRequest`](../../doc/models/update-metadata-request.md) | Body, Optional | - | @@ -434,29 +454,7 @@ print(result) # Delete Metadata -This method removes the metadata from the subscriber/customer cited. - -## Query String Usage - -For instance if you wanted to delete the metadata for customer 99 named weight you would request: - -``` -https://acme.chargify.com/customers/99/metadata.json?name=weight -``` - -If you want to delete multiple metadata fields for a customer 99 named: `weight` and `age` you wrould request: - -``` -https://acme.chargify.com/customers/99/metadata.json?names[]=weight&names[]=age -``` - -## Successful Response - -For a success, there will be a code `200` and the plain text response `true`. - -## Unsuccessful Response - -When a failed response is encountered, you will receive a `404` response and the plain text response of `true`. +Deletes one or more metafields (and associated metadata) from the specified subscription or customer. ```python def delete_metadata(self, @@ -470,7 +468,7 @@ def delete_metadata(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | the resource type to which the metafields belong | +| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | The resource type to which the metafields belong. | | `resource_id` | `int` | Template, Required | The Advanced Billing id of the customer or the subscription for which the metadata applies | | `name` | `str` | Query, Optional | Name of field to be removed. | | `names` | `List[str]` | Query, Optional | Names of fields to be removed. Use in query: `names[]=field1&names[]=my-field&names[]=another-field`. | @@ -501,19 +499,7 @@ custom_fields_controller.delete_metadata( # List Metadata for Resource Type -This method will provide you information on usage of metadata across your selected resource (ie. subscriptions, customers) - -## Metadata Data - -This endpoint will also display the current stats of your metadata to use as a tool for pagination. - -### Metadata for multiple records - -`https://acme.chargify.com/subscriptions/metadata.json?resource_ids[]=1&resource_ids[]=2` - -## Read Metadata for a Site - -This endpoint will list the number of pages of metadata information that are contained within a site. +Lists metadata for a specified array of subscriptions or customers. ```python def list_metadata_for_resource_type(self, @@ -524,7 +510,7 @@ def list_metadata_for_resource_type(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | the resource type to which the metafields belong | +| `resource_type` | [`ResourceType`](../../doc/models/resource-type.md) | Template, Required | The resource type to which the metafields belong. | | `page` | `int` | Query, Optional | Result records are organized in pages. By default, the first page of results is displayed. The page parameter specifies a page number of results to fetch. You can start navigating through the pages to consume the results. You do this by passing in a page parameter. Retrieve the next page by adding ?page=2 to the query string. If there are no results to return, then an empty result set will be returned.
Use in query `page=1`.

**Default**: `1`

**Constraints**: `>= 1` | | `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request. Default value is 20. The maximum allowed values is 200; any per_page value over 200 will be changed to 200.
Use in query `per_page=200`.

**Default**: `20`

**Constraints**: `<= 200` | | `date_field` | [`BasicDateField`](../../doc/models/basic-date-field.md) | Query, Optional | The type of filter you would like to apply to your search. | @@ -545,7 +531,7 @@ def list_metadata_for_resource_type(self, ```python collect = { 'resource_type': ResourceType.SUBSCRIPTIONS, - 'page': 2, + 'page': 1, 'per_page': 50, 'date_field': BasicDateField.UPDATED_AT } diff --git a/doc/controllers/customers.md b/doc/controllers/customers.md index 99d6f050..4de05f3f 100644 --- a/doc/controllers/customers.md +++ b/doc/controllers/customers.md @@ -31,7 +31,7 @@ Full documentation on how to locate, create and edit Customers in the Advanced B Advanced Billing requires that you use the ISO Standard Country codes when formatting country attribute of the customer. -Countries should be formatted as 2 characters. For more information, please see the following wikipedia article on [ISO_3166-1.](http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) +Countries should be formatted as 2 characters. For more information, see the following wikipedia article on [ISO_3166-1.](http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) ## Required State Format @@ -39,7 +39,7 @@ Advanced Billing requires that you use the ISO Standard State codes when formatt + US States (2 characters): [ISO_3166-2](https://en.wikipedia.org/wiki/ISO_3166-2:US) -+ States Outside the US (2-3 characters): To find the correct state codes outside of the US, please go to [ISO_3166-1](http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) and click on the link in the “ISO 3166-2 codes” column next to country you wish to populate. ++ States Outside the US (2-3 characters): To find the correct state codes outside of the US, go to [ISO_3166-1](http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) and click on the link in the “ISO 3166-2 codes” column next to country you wish to populate. ## Locale @@ -147,7 +147,7 @@ Common use cases are: + Search by a reference value from your application + Search by a first or last name -To retrieve a single, exact match by reference, please use the [lookup endpoint](https://developers.chargify.com/docs/api-docs/b710d8fbef104-read-customer-by-reference). +To retrieve a single, exact match by reference, use the [lookup endpoint](https://developers.chargify.com/docs/api-docs/b710d8fbef104-read-customer-by-reference). ```python def list_customers(self, @@ -176,7 +176,7 @@ def list_customers(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 30, 'date_field': BasicDateField.UPDATED_AT } diff --git a/doc/controllers/events-based-billing-segments.md b/doc/controllers/events-based-billing-segments.md index cc2a2b53..64132114 100644 --- a/doc/controllers/events-based-billing-segments.md +++ b/doc/controllers/events-based-billing-segments.md @@ -118,7 +118,7 @@ def list_segments_for_price_point(self, collect = { 'component_id': 'component_id8', 'price_point_id': 'price_point_id8', - 'page': 2, + 'page': 1, 'per_page': 50, 'filter': ListSegmentsFilter( segment_property_1_value='EU' diff --git a/doc/controllers/events.md b/doc/controllers/events.md index dbcc8e54..6a642ad2 100644 --- a/doc/controllers/events.md +++ b/doc/controllers/events.md @@ -115,7 +115,7 @@ def list_events(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50, 'direction': Direction.DESC, 'filter': [ @@ -231,7 +231,7 @@ def list_subscription_events(self, ```python collect = { 'subscription_id': 222, - 'page': 2, + 'page': 1, 'per_page': 50, 'direction': Direction.DESC, 'filter': [ @@ -315,7 +315,7 @@ def read_events_count(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50, 'direction': Direction.DESC, 'filter': [ diff --git a/doc/controllers/insights.md b/doc/controllers/insights.md index 94862066..b271dbfb 100644 --- a/doc/controllers/insights.md +++ b/doc/controllers/insights.md @@ -165,7 +165,7 @@ def list_mrr_movements(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 20 } result = insights_controller.list_mrr_movements(collect) @@ -262,7 +262,7 @@ collect = { ] ), 'at_time': 'at_time=2022-01-10T10:00:00-05:00', - 'page': 2, + 'page': 1, 'per_page': 50, 'direction': Direction.DESC } diff --git a/doc/controllers/invoices.md b/doc/controllers/invoices.md index 1f341a12..2cce6324 100644 --- a/doc/controllers/invoices.md +++ b/doc/controllers/invoices.md @@ -131,7 +131,7 @@ def list_invoices(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50, 'direction': Direction.DESC, 'line_items': False, @@ -205,7 +205,7 @@ print(result) "organization": "", "email": "meg@example.com" }, - "memo": "Please pay within 15 days.", + "memo": "Payment due within 15 days of receipt.", "billing_address": { "street": "123 I Love Cats Way", "line2": "", @@ -271,7 +271,7 @@ print(result) "organization": "", "email": "food@example.com" }, - "memo": "Please pay within 15 days.", + "memo": "Payment due within 15 days of receipt.", "billing_address": { "street": "", "line2": "", @@ -337,7 +337,7 @@ print(result) "organization": "123", "email": "example@example.com" }, - "memo": "Please pay within 15 days.", + "memo": "Payment due within 15 days of receipt.", "billing_address": { "street": "123 Anywhere Street", "line2": "", @@ -403,7 +403,7 @@ print(result) "organization": "", "email": "example@example.com" }, - "memo": "Please pay within 15 days.", + "memo": "Payment due within 15 days of receipt.", "billing_address": { "street": "123 I Love Cats Way", "line2": "", @@ -518,7 +518,7 @@ print(result) "organization": null, "email": "joe@example.com" }, - "memo": "Please pay within 15 days.", + "memo": "Payment due within 15 days of receipt.", "billing_address": { "street": null, "line2": null, @@ -638,7 +638,7 @@ def list_invoice_events(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 100 } result = invoices_controller.list_invoice_events(collect) @@ -1213,7 +1213,7 @@ def list_credit_notes(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50, 'line_items': False, 'discounts': False, @@ -2063,7 +2063,7 @@ def list_consolidated_invoice_segments(self, ```python collect = { 'invoice_uid': 'invoice_uid0', - 'page': 2, + 'page': 1, 'per_page': 50, 'direction': Direction.ASC } @@ -2115,7 +2115,7 @@ print(result) "organization": "", "email": "meg@example.com" }, - "memo": "Please pay within 15 days.", + "memo": "Payment due within 15 days of receipt.", "billing_address": { "street": "123 I Love Cats Way", "line2": "", @@ -2181,7 +2181,7 @@ print(result) "organization": "", "email": "food@example.com" }, - "memo": "Please pay within 15 days.", + "memo": "Payment due within 15 days of receipt.", "billing_address": { "street": "", "line2": "", @@ -2247,7 +2247,7 @@ print(result) "organization": "123", "email": "example@example.com" }, - "memo": "Please pay within 15 days.", + "memo": "Payment due within 15 days of receipt.", "billing_address": { "street": "123 Anywhere Street", "line2": "", @@ -2313,7 +2313,7 @@ print(result) "organization": "", "email": "example@example.com" }, - "memo": "Please pay within 15 days.", + "memo": "Payment due within 15 days of receipt.", "billing_address": { "street": "123 I Love Cats Way", "line2": "", @@ -2438,6 +2438,42 @@ If You want to use existing coupon for discount creation, only `code` and option ... ``` +#### Using Coupon Subcodes + +You can also use coupon subcodes to apply existing coupons with specific subcodes: + +```json +... + "coupons": [ + { + "subcode": "SUB1", + "product_family_id": 1 + } + ] +... +``` + +**Important:** You cannot specify both `code` and `subcode` for the same coupon. Use either: + +- `code` to apply a main coupon +- `subcode` to apply a specific coupon subcode + +The API response will include both the main coupon code and the subcode used: + +```json +... + "coupons": [ + { + "code": "MAIN123", + "subcode": "SUB1", + "product_family_id": 1, + "percentage": 10, + "description": "Special discount" + } + ] +... +``` + ### Coupon options #### Code @@ -2446,6 +2482,10 @@ Coupon `code` will be displayed on invoice discount section. Coupon code can only contain uppercase letters, numbers, and allowed special characters. Lowercase letters will be converted to uppercase. It can be used to select an existing coupon from the catalog, or as an ad hoc coupon when passed with `percentage` or `amount`. +#### Subcode + +Coupon `subcode` allows you to apply existing coupons using their subcodes. When a subcode is used, the API response will include both the main coupon code and the specific subcode that was applied. Subcodes are case-insensitive and will be converted to uppercase automatically. + #### Percentage Coupon `percentage` can take values from 0 to 100 and up to 4 decimal places. It cannot be used with `amount`. Only for ad hoc coupons, will be ignored if `code` is used to select an existing coupon from the catalog. @@ -2505,7 +2545,7 @@ By default, invoices will be created with a due date matching the date of invoic #### Addresses -The seller, shipping and billing addresses can be sent to override the site's defaults. Each address requires to send a `first_name` at a minimum in order to work. Please see below for the details on which parameters can be sent for each address object. +The seller, shipping and billing addresses can be sent to override the site's defaults. Each address requires to send a `first_name` at a minimum in order to work. See below for the details on which parameters can be sent for each address object. #### Memo and Payment Instructions @@ -2664,9 +2704,9 @@ print(result) This endpoint allows for invoices to be programmatically delivered via email. This endpoint supports the delivery of both ad-hoc and automatically generated invoices. Additionally, this endpoint supports email delivery to direct recipients, carbon-copy (cc) recipients, and blind carbon-copy (bcc) recipients. -Please note that if no recipient email addresses are specified in the request, then the subscription's default email configuration will be used. For example, if `recipient_emails` is left blank, then the invoice will be delivered to the subscription's customer email address. +If no recipient email addresses are specified in the request, then the subscription's default email configuration will be used. For example, if `recipient_emails` is left blank, then the invoice will be delivered to the subscription's customer email address. -On success, a 204 no-content response will be returned. Please note that this does not indicate that email(s) have been delivered, but instead indicates that emails have been successfully queued for delivery. If _any_ invalid or malformed email address is found in the request body, the entire request will be rejected and a 422 response will be returned. +On success, a 204 no-content response will be returned. The response does not indicate that email(s) have been delivered, but instead indicates that emails have been successfully queued for delivery. If _any_ invalid or malformed email address is found in the request body, the entire request will be rejected and a 422 response will be returned. ```python def send_invoice(self, diff --git a/doc/controllers/offers.md b/doc/controllers/offers.md index a6e95e3a..b4f9ce69 100644 --- a/doc/controllers/offers.md +++ b/doc/controllers/offers.md @@ -150,7 +150,7 @@ def list_offers(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50, 'include_archived': True } diff --git a/doc/controllers/payment-profiles.md b/doc/controllers/payment-profiles.md index 8fa27208..7293701b 100644 --- a/doc/controllers/payment-profiles.md +++ b/doc/controllers/payment-profiles.md @@ -26,236 +26,37 @@ payment_profiles_controller = client.payment_profiles # Create Payment Profile -Use this endpoint to create a payment profile for a customer. +Creates a payment profile for a customer. -Payment Profiles house the credit card, ACH (Authorize.Net or Stripe only,) or PayPal (Braintree only,) data for a customer. The payment information is attached to the customer within Advanced Billing, as opposed to the Subscription itself. +When you create a new payment profile for a customer via the API, it does not automatically make the profile current for any of the customer’s subscriptions. To use the payment profile as the default, you must set it explicitly for the subscription or subscription group. -You must include a customer_id so that Advanced Billing will attach it to the customer entry. If no customer_id is included the API will return a 404. +Select an option from the **Request Examples** drop-down on the right side of the portal to see examples of common scenarios for creating payment profiles. -## Create a Payment Profile for ACH usage +Do not use real card information for testing. See the Sites articles that cover [testing your site setup](https://docs.maxio.com/hc/en-us/articles/24250712113165-Testing-Overview#testing-overview-0-0) for more details on testing in your sandbox. -If you would like to create a payment method that is a Bank Account applicable for ACH payments use the following: +Note that collecting and sending raw card details in production requires [PCI compliance](https://docs.maxio.com/hc/en-us/articles/24183956938381-PCI-Compliance#pci-compliance-0-0) on your end. If your business is not PCI compliant, use [Chargify.js](https://docs.maxio.com/hc/en-us/articles/38163190843789-Chargify-js-Overview#chargify-js-overview-0-0) to collect credit card or bank account information. -```json -{ -"payment_profile": { - "customer_id": [Valid-Customer-ID], - "bank_name": "Best Bank", - "bank_routing_number": "021000089", - "bank_account_number": "111111111111", - "bank_account_type": "checking", - "bank_account_holder_type": "business", - "payment_type": "bank_account" - } -} -``` - -## Taxable Subscriptions - -If your subscriber pays taxes on their purchased product, and you are attempting to create or update the `payment_profile`, complete address information is required. For information on required address formatting to allow your subscriber to be taxed, please see our documentation [here](https://developers.chargify.com/docs/developer-docs/d2e9e34db740e-signups#taxes) - -## Payment Profile Documentation - -Full documentation on how Payment Profiles operate within Advanced Billing can be located under the following links: +See the following articles to learn more about subscriptions and payments: + [Subscriber Payment Details](https://maxio.zendesk.com/hc/en-us/articles/24251599929613-Subscription-Summary-Payment-Details-Tab) + [Self Service Pages](https://maxio.zendesk.com/hc/en-us/articles/24261425318541-Self-Service-Pages) (Allows credit card updates by Subscriber) + [Public Signup Pages payment settings](https://maxio.zendesk.com/hc/en-us/articles/24261368332557-Individual-Page-Settings) - -## Create a Payment Profile with a Chargify.js token - -```json -{ - "payment_profile": { - "customer_id": 1036, - "chargify_token": "tok_w68qcpnftyv53jk33jv6wk3w" - } -} -``` - -## Active Payment Methods - -Creating a new payment profile for a Customer via the API will not make that Payment Profile current for any of the Customer’s Subscriptions. In order to utilize the payment profile as the default, it must be set as the default payment profile for the subscription or subscription group. - -## Requirements - -Either the full_number, expiration_month, and expiration_year or if you have an existing vault_token from your gateway, that vault_token and the current_vault are required. -Passing in the vault_token and current_vault are only allowed when creating a new payment profile. - -### Taxable Subscriptions - -If your subscriber pays taxes on their purchased product, and you are attempting to create or update the `payment_profile`, complete address information is required. For information on required address formatting to allow your subscriber to be taxed, please see our documentation [here](https://developers.chargify.com/docs/developer-docs/d2e9e34db740e-signups#taxes) - -## BraintreeBlue - -Some merchants use Braintree JavaScript libraries directly and then pass `payment_method_nonce` and/or `paypal_email` to create a payment profile. This implementation is deprecated and does not handle 3D Secure. Instead, we have provided [Chargify.js](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDI0-overview) which is continuously improved and supports Credit Cards (along with 3D Secure), PayPal and ApplePay payment types. - -## GoCardless - -For more information on GoCardless, please view the following resources: - ++ [Taxes](https://developers.chargify.com/docs/developer-docs/d2e9e34db740e-signups#taxes) ++ [Chargify.js](https://docs.maxio.com/hc/en-us/articles/38163190843789-Chargify-js-Overview) + + [Chargify.js with GoCardless - minimal example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QQZKCER8CFK40MR6XJ) + + [Chargify.js with GoCardless - full example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QR09JVHWW0MCA7HVJV) + + [Chargify.js with Stripe Direct Debit - minimal example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QQFKKN8Z7B7DZ9AJS5) + + [Chargify.js with Stripe Direct Debit - full example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QRECQQ4ECS3ZA55GY7) + + [Chargify.js with Stripe BECS Direct Debit - minimal example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#minimal-example-with-sepa-or-becs-direct-debit-stripe-gateway) + + [Chargify.js with Stripe BECS Direct Debit - full example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#full-example-with-sepa-direct-debit-stripe-gateway) + [Full documentation on GoCardless](https://maxio.zendesk.com/hc/en-us/articles/24176159136909-GoCardless) - -+ [Using Chargify.js with GoCardless - minimal example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QQZKCER8CFK40MR6XJ) - -+ [Using Chargify.js with GoCardless - full example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QR09JVHWW0MCA7HVJV) - -### GoCardless with Local Bank Details - -Following examples create customer, bank account and mandate in GoCardless: - -```json -{ - "payment_profile": { - "customer_id": "Valid-Customer-ID", - "bank_name": "Royal Bank of France", - "bank_account_number": "0000000", - "bank_routing_number": "0003", - "bank_branch_code": "00006", - "payment_type": "bank_account", - "billing_address": "20 Place de la Gare", - "billing_city": "Colombes", - "billing_state": "Île-de-France", - "billing_zip": "92700", - "billing_country": "FR" - } -} -``` - -### GoCardless with IBAN - -```json -{ - "payment_profile": { - "customer_id": "24907598", - "bank_name": "French Bank", - "bank_iban": "FR1420041010050500013M02606", - "payment_type": "bank_account", - "billing_address": "20 Place de la Gare", - "billing_city": "Colombes", - "billing_state": "Île-de-France", - "billing_zip": "92700", - "billing_country": "FR" - } -} -``` - -### Importing GoCardless - -If the customer, bank account, and mandate already exist in GoCardless, a payment profile can be created by using the IDs. In order to create masked versions of `bank_account_number` and `bank_routing_number` that are used to display within Advanced Billing Admin UI, you can pass the last four digits for this fields which then will be saved in this form `XXXX[four-provided-digits]`. - -```json -{ - "payment_profile": { - "customer_id": "24907598", - "customer_vault_token": [Existing GoCardless Customer ID] - "vault_token": [Existing GoCardless Mandate ID], - "current_vault": "gocardless", - "bank_name": "French Bank", - "bank_account_number": [Last Four Of The Existing Account Number or IBAN if applicable], - "bank_routing_number": [Last Four Of The Existing Routing Number], - "payment_type": "bank_account", - "billing_address": "20 Place de la Gare", - "billing_city": "Colombes", - "billing_state": "Île-de-France", - "billing_zip": "92700", - "billing_country": "FR" - } -} -``` - -## SEPA Direct Debit - -For more information on Stripe SEPA Direct Debit, please view the following resources: - + [Full documentation on Stripe SEPA Direct Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Stripe-SEPA-and-BECS-Direct-Debit) - -+ [Using Chargify.js with Stripe Direct Debit - minimal example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QQFKKN8Z7B7DZ9AJS5) - -+ [Using Chargify.js with Stripe Direct Debit - full example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QRECQQ4ECS3ZA55GY7) - -### Stripe SEPA Direct Debit Payment Profiles - -The following example creates a customer, bank account and mandate in Stripe: - -```json -{ - "payment_profile": { - "customer_id": "24907598", - "bank_name": "Deutsche bank", - "bank_iban": "DE89370400440532013000", - "payment_type": "bank_account", - "billing_address": "Test", - "billing_city": "Berlin", - "billing_state": "Brandenburg", - "billing_zip": "12345", - "billing_country": "DE" - } -} -``` - -## Stripe BECS Direct Debit - -For more information on Stripe BECS Direct Debit, please view the following resources: - + [Full documentation on Stripe BECS Direct Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Stripe-SEPA-and-BECS-Direct-Debit) - -+ [Using Chargify.js with Stripe BECS Direct Debit - minimal example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#minimal-example-with-sepa-or-becs-direct-debit-stripe-gateway) - -+ [Using Chargify.js with Stripe BECS Direct Debit - full example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#full-example-with-sepa-direct-debit-stripe-gateway) - -### Stripe BECS Direct Debit Payment Profiles - -The following example creates a customer, bank account and mandate in Stripe: - -```json -{ - "payment_profile": { - "customer_id": "24907598", - "bank_name": "Australian bank", - "bank_branch_code": "000000", - "bank_account_number": "000123456" - "payment_type": "bank_account", - "billing_address": "Test", - "billing_city": "Stony Rise", - "billing_state": "Tasmania", - "billing_zip": "12345", - "billing_country": "AU" - } -} -``` - -## Stripe BACS Direct Debit - -Contact the support team to enable this payment method. -For more information on Stripe BACS Direct Debit, please view the following resources: - + [Full documentation on Stripe BACS Direct Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Stripe-SEPA-and-BECS-Direct-Debit) -### Stripe BACS Direct Debit Payment Profiles +## 3D Secure Authentication during payment profile creation. -The following example creates a customer, bank account and mandate in Stripe: - -```json -{ - "payment_profile": { - "customer_id": "24907598", - "bank_name": "British bank", - "bank_branch_code": "108800", - "bank_account_number": "00012345" - "payment_type": "bank_account", - "billing_address": "Test", - "billing_city": "London", - "billing_state": "LND", - "billing_zip": "12345", - "billing_country": "GB" - } -} -``` - -## 3D Secure - Checkout - -It may happen that a payment needs 3D Secure Authentication when the payment profile is created; this is referred to in our help docs as a [post-authentication flow](https://maxio.zendesk.com/hc/en-us/articles/24176278996493-Testing-Implementing-3D-Secure#psd2-flows-pre-authentication-and-post-authentication). The server returns `422 Unprocessable Entity` in this case with the following response: +When a payment requires 3D Secure Authentication to adhear to Strong Customer Authentication (SCA) during payment profile creation, the request enters a [post-authentication flow](https://maxio.zendesk.com/hc/en-us/articles/24176278996493-Testing-Implementing-3D-Secure#psd2-flows-pre-authentication-and-post-authentication). In this case, a 422 Unprocessable Entity status is returned with the following response: ```json { @@ -275,29 +76,34 @@ It may happen that a payment needs 3D Secure Authentication when the payment pro ``` To let the customer go through 3D Secure Authentication, they need to be redirected to the URL specified in `action_link`. -Optionally, you can specify `callback_url` parameter in the `action_link` URL if you’d like to be notified about the result of 3D Secure Authentication. The `callback_url` will return the following information: + +Optionally, you can specify the `callback_url` parameter in the `action_link` URL to receive notification about the result of 3D Secure Authentication. + +The `callback_url` will return the following information: - whether the authentication was successful (`success`) - the payment profile ID (`payment_profile_id`) -Lastly, you can also specify a `redirect_url` parameter within the `action_link` URL if you’d like to redirect a customer back to your site. +You can also specify a `redirect_url` parameter in the `action_link` URL to redirect the customer back to your site. + +You cannot use action_link in an iframe inside a custom application. You must redirect the customer directly to the `action_link` and use the `redirect_url` or `callback_url` to be notified of the result. -It is not possible to use `action_link` in an iframe inside a custom application. You have to redirect the customer directly to the `action_link`, then, to be notified about the result, use `redirect_url` or `callback_url`. +The final URL that you send a customer to complete 3D Secure may resemble the following, where the first half is the `action_link` and the second half contains a `redirect_url` and `callback_url`: -The final URL that you send a customer to complete 3D Secure may resemble the following, where the first half is the `action_link` and the second half contains a `redirect_url` and `callback_url`: `https://checkout-test.chargifypay.test/3d-secure/checkout/pay_uerzhsxd5uhkbodx5jhvkg6yeu?one_time_token_id=93&callback_url=http://localhost:4000&redirect_url=https://yourpage.com` +`https://checkout-test.chargifypay.test/3d-secure/checkout/pay_uerzhsxd5uhkbodx5jhvkg6yeu?one_time_token_id=93&callback_url=http://localhost:4000&redirect_url=https://yourpage.com` ### Example Redirect Flow -You may wish to redirect customers to different pages depending on whether their SCA was performed successfully. Here's an example flow to use as a reference: +Here's an example flow to redirect customers to different pages depending on whether SCA was performed successfully: -1. Create a payment profile via API; it requires 3DS -2. You receive a `action_link` in the response. -3. Use this `action_link` to, for example, connect with your internal resources or generate a session_id -4. Include 1 of those attributes inside the `callback_url` and `redirect_url` to be aware which “session” this applies to +1. Create a payment profile via the API; it requires 3DS. +2. You receive an `action_link` in the response. +3. Use this `action_link` to, for example, connect with your internal resources or generate a `session_id`. +4. Include one of those attributes inside the `callback_url` and `redirect_url` to be aware which “session” this applies to. 5. Redirect the customer to the `action_link` with `callback_url` and `redirect_url` applied -6. After the customer finishes 3DS authentication, we let you know the result by making a request to applied `callback_url`. -7. After that, we redirect the customer to the `redirect_url`; at this point the result of authentication is known -8. Optionally, you can use the applied "msg" param in the `redirect_url` to determine whether it was successful or not +6. After the customer completes 3DS authentication, we notify you of the result via the applied `callback_url`. +7. After that, we redirect the customer to the `redirect_url`; at this point the result of authentication is known. +8. Optionally, you can use the applied "msg" param in the `redirect_url` to determine if the redirect was successful. ```python def create_payment_profile(self, @@ -319,13 +125,8 @@ def create_payment_profile(self, ```python body = CreatePaymentProfileRequest( payment_profile=CreatePaymentProfile( - payment_type=PaymentType.BANK_ACCOUNT, - customer_id=123, - bank_name='Best Bank', - bank_routing_number='021000089', - bank_account_number='111111111111', - bank_account_type=BankAccountType.CHECKING, - bank_account_holder_type=BankAccountHolderType.BUSINESS + chargify_token='tok_w68qcpnftyv53jk33jv6wk3w', + customer_id=1036 ) ) @@ -397,7 +198,7 @@ def list_payment_profiles(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50 } result = payment_profiles_controller.list_payment_profiles(collect) @@ -472,7 +273,7 @@ print(result) Using the GET method you can retrieve a Payment Profile identified by its unique ID. -Please note that a different JSON object will be returned if the card method on file is a bank account. +Note that a different JSON object will be returned if the card method on file is a bank account. ### Response for Bank Account @@ -633,11 +434,6 @@ body = UpdatePaymentProfileRequest( payment_profile=UpdatePaymentProfile( first_name='Graham', last_name='Test', - full_number='4111111111111111', - card_type=CardType.MASTER, - expiration_month='04', - expiration_year='2030', - current_vault=AllVaults.BOGUS, billing_address='456 Juniper Court', billing_city='Boulder', billing_state='CO', @@ -662,23 +458,13 @@ print(result) "id": 10088716, "first_name": "Test", "last_name": "Subscription", - "masked_card_number": "XXXX-XXXX-XXXX-1", - "card_type": "bogus", - "expiration_month": 1, - "expiration_year": 2022, - "customer_id": 14543792, - "current_vault": "bogus", - "vault_token": "1", "billing_address": "123 Montana Way", "billing_city": "Billings", "billing_state": "MT", "billing_zip": "59101", "billing_country": "US", - "customer_vault_token": null, "billing_address_2": "", - "payment_type": "credit_card", - "site_gateway_setting_id": 1, - "gateway_handle": null + "payment_type": "bank_account" } } ``` @@ -813,8 +599,8 @@ print(result) { "payment_profile": { "id": 10089892, - "first_name": "Chester", - "last_name": "Tester", + "first_name": "John", + "last_name": "Doe", "customer_id": 14543792, "current_vault": "stripe_connect", "vault_token": "cus_0123abc456def", diff --git a/doc/controllers/product-families.md b/doc/controllers/product-families.md index 1376998b..647f9866 100644 --- a/doc/controllers/product-families.md +++ b/doc/controllers/product-families.md @@ -18,7 +18,7 @@ product_families_controller = client.product_families # List Products for Product Family -This method allows to retrieve a list of Products belonging to a Product Family. +Retrieves a list of Products belonging to a Product Family. ```python def list_products_for_product_family(self, @@ -50,7 +50,7 @@ def list_products_for_product_family(self, ```python collect = { 'product_family_id': 'product_family_id4', - 'page': 2, + 'page': 1, 'per_page': 50, 'date_field': BasicDateField.UPDATED_AT, 'filter': ListProductsFilter( @@ -174,7 +174,7 @@ print(result) # Create Product Family -This method will create a Product Family within your Advanced Billing site. Create a Product Family to act as a container for your products, components and coupons. +Creates a Product Family within your Advanced Billing site. Create a Product Family to act as a container for your products, components and coupons. Full documentation on how Product Families operate within the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24261098936205-Product-Families). @@ -232,7 +232,7 @@ print(result) # List Product Families -This method allows to retrieve a list of Product Families for a site. +Retrieve a list of Product Families for a site. ```python def list_product_families(self, @@ -295,7 +295,7 @@ print(result) # Read Product Family -This method allows to retrieve a Product Family via the `product_family_id`. The response will contain a Product Family object. +Retrieves a Product Family via the `product_family_id`. The response will contain a Product Family object. The product family can be specified either with the id number, or with the `handle:my-family` format. diff --git a/doc/controllers/product-price-points.md b/doc/controllers/product-price-points.md index 2cd9caf3..df836eb8 100644 --- a/doc/controllers/product-price-points.md +++ b/doc/controllers/product-price-points.md @@ -25,7 +25,7 @@ product_price_points_controller = client.product_price_points # Create Product Price Point -[Product Price Point Documentation](https://maxio.zendesk.com/hc/en-us/articles/24261111947789-Product-Price-Points) +Creates a Product Price Point. See the [Product Price Point](https://maxio.zendesk.com/hc/en-us/articles/24261111947789-Product-Price-Points) documentation for details. ```python def create_product_price_point(self, @@ -59,7 +59,7 @@ body = CreateProductPricePointRequest( trial_price_in_cents=4900, trial_interval=1, trial_interval_unit=IntervalUnit.MONTH, - trial_type='payment_expected', + trial_type=TrialType.PAYMENT_EXPECTED, initial_charge_in_cents=120000, initial_charge_after_trial=False, expiration_interval=12, @@ -110,7 +110,7 @@ print(result) # List Product Price Points -Use this endpoint to retrieve a list of product price points. +Retrieves a list of product price points. ```python def list_product_price_points(self, @@ -137,7 +137,7 @@ def list_product_price_points(self, ```python collect = { 'product_id': 124, - 'page': 2, + 'page': 1, 'per_page': 10, 'filter_type': Liquid error: Value cannot be null. (Parameter 'key') } @@ -177,9 +177,9 @@ print(result) # Update Product Price Point -Use this endpoint to update a product price point. +Updates a product price point. -Note: Custom product price points are not able to be updated. +Note: Custom product price points cannot be updated. ```python def update_product_price_point(self, @@ -317,7 +317,7 @@ print(result) # Archive Product Price Point -Use this endpoint to archive a product price point. +Archives a product price point. ```python def archive_product_price_point(self, @@ -449,9 +449,9 @@ print(result) # Promote Product Price Point to Default -Use this endpoint to make a product price point the default for the product. +Sets a product price point as the default for the product. -Note: Custom product price points are not able to be set as the default for a product. +Note: Custom product price points cannot be set as the default for a product. ```python def promote_product_price_point_to_default(self, @@ -540,7 +540,7 @@ print(result) # Bulk Create Product Price Points -Use this endpoint to create multiple product price points in one request. +Creates multiple product price points in one request. ```python def bulk_create_product_price_points(self, @@ -575,7 +575,7 @@ body = BulkCreateProductPricePointsRequest( trial_price_in_cents=4900, trial_interval=1, trial_interval_unit=IntervalUnit.MONTH, - trial_type='payment_expected', + trial_type=TrialType.PAYMENT_EXPECTED, initial_charge_in_cents=120000, initial_charge_after_trial=False, expiration_interval=12, @@ -590,7 +590,7 @@ body = BulkCreateProductPricePointsRequest( trial_price_in_cents=4900, trial_interval=1, trial_interval_unit=IntervalUnit.MONTH, - trial_type='payment_expected', + trial_type=TrialType.PAYMENT_EXPECTED, initial_charge_in_cents=120000, initial_charge_after_trial=False, expiration_interval=12, @@ -644,7 +644,7 @@ print(result) # Create Product Currency Prices -This endpoint allows you to create currency prices for a given currency that has been defined on the site level in your settings. +Creates currency prices for a given currency that has been defined on the site level in your settings. When creating currency prices, they need to mirror the structure of your primary pricing. If the product price point defines a trial and/or setup fee, each currency must also define a trial and/or setup fee. @@ -725,11 +725,11 @@ print(result) # Update Product Currency Prices -This endpoint allows you to update the `price`s of currency prices for a given currency that exists on the product price point. +Updates the `price`s of currency prices for a given currency that exists on the product price point. When updating the pricing, it needs to mirror the structure of your primary pricing. If the product price point defines a trial and/or setup fee, each currency must also define a trial and/or setup fee. -Note: Currency Prices are not able to be updated for custom product price points. +Note: Currency Prices cannot be updated for custom product price points. ```python def update_product_currency_prices(self, @@ -841,7 +841,7 @@ collect = { ] ), 'include': ListProductsPricePointsInclude.CURRENCY_PRICES, - 'page': 2, + 'page': 1, 'per_page': 50 } result = product_price_points_controller.list_all_product_price_points(collect) diff --git a/doc/controllers/products.md b/doc/controllers/products.md index a4489a25..4bad7301 100644 --- a/doc/controllers/products.md +++ b/doc/controllers/products.md @@ -20,7 +20,9 @@ products_controller = client.products # Create Product -Use this method to create a product within your Advanced Billing site. +Creates a product in your Advanced Billing site. + +See the following product docuemation for more information: + [Products Documentation](https://maxio.zendesk.com/hc/en-us/articles/24261090117645-Products-Overview) + [Changing a Subscription's Product](https://maxio.zendesk.com/hc/en-us/articles/24252069837581-Product-Changes-and-Migrations) @@ -127,7 +129,7 @@ print(result) # Read Product -This endpoint allows you to read the current details of a product that you've created in Advanced Billing. +Reads the current details of a product. ```python def read_product(self, @@ -199,7 +201,7 @@ print(result) # Update Product -Use this method to change aspects of an existing product. +Updates aspects of an existing product. ### Input Attributes Update Notes @@ -292,7 +294,7 @@ print(result) # Archive Product -Sending a DELETE request to this endpoint will archive the product. All current subscribers will be unffected; their subscription/purchase will continue to be charged monthly. +Archives the product. All current subscribers will be unffected; their subscription/purchase will continue to be charged monthly. This will restrict the option to chose the product for purchase via the Billing Portal, as well as disable Public Signup Pages for the product. @@ -372,7 +374,7 @@ print(result) # Read Product by Handle -This method allows to retrieve a Product object by its `api_handle`. +Retrieves a Product object by its `api_handle`. ```python def read_product_by_handle(self, @@ -507,7 +509,7 @@ collect = { 3 ] ), - 'page': 2, + 'page': 1, 'per_page': 50, 'include_archived': True, 'include': ListProductsInclude.PREPAID_PRODUCT_PRICE_POINT diff --git a/doc/controllers/proforma-invoices.md b/doc/controllers/proforma-invoices.md index 2fc94787..4ca6bea8 100644 --- a/doc/controllers/proforma-invoices.md +++ b/doc/controllers/proforma-invoices.md @@ -154,7 +154,7 @@ print(result) This endpoint will create a proforma invoice and return it as a response. If the information becomes outdated, simply void the old proforma invoice and generate a new one. -If you would like to preview the next billing amounts without generating a full proforma invoice, please use the renewal preview endpoint. +If you would like to preview the next billing amounts without generating a full proforma invoice, use the renewal preview endpoint. ## Restrictions @@ -227,7 +227,7 @@ def list_proforma_invoices(self, ```python collect = { 'subscription_id': 222, - 'page': 2, + 'page': 1, 'per_page': 50, 'direction': Direction.DESC, 'line_items': False, diff --git a/doc/controllers/reason-codes.md b/doc/controllers/reason-codes.md index a56e3d64..2e2b9828 100644 --- a/doc/controllers/reason-codes.md +++ b/doc/controllers/reason-codes.md @@ -98,7 +98,7 @@ def list_reason_codes(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50 } result = reason_codes_controller.list_reason_codes(collect) diff --git a/doc/controllers/sales-commissions.md b/doc/controllers/sales-commissions.md index 95773a8d..6e70544b 100644 --- a/doc/controllers/sales-commissions.md +++ b/doc/controllers/sales-commissions.md @@ -23,7 +23,7 @@ Endpoint returns subscriptions with associated sales reps The Sales Commission API differs from other Chargify API endpoints. This resource is associated with the seller itself. Up to now all available resources were at the level of the site, therefore creating the API Key per site was a sufficient solution. To share resources at the seller level, a new authentication method was introduced, which is user authentication. Creating an API Key for a user is a required step to correctly use the Sales Commission API, more details [here](https://developers.chargify.com/docs/developer-docs/ZG9jOjMyNzk5NTg0-2020-04-20-new-api-authentication). -Access to the Sales Commission API endpoints is available to users with financial access, where the seller has the Advanced Analytics component enabled. For further information on getting access to Advanced Analytics please contact Maxio support. +Access to the Sales Commission API endpoints is available to users with financial access, where the seller has the Advanced Analytics component enabled. For further information on getting access to Advanced Analytics contact Maxio support. > Note: The request is at seller level, it means `<>` variable will be replaced by `app` @@ -52,7 +52,7 @@ def list_sales_commission_settings(self, collect = { 'seller_id': 'seller_id8', 'authorization': 'Bearer <>', - 'page': 2, + 'page': 1, 'per_page': 100 } result = sales_commissions_controller.list_sales_commission_settings(collect) @@ -102,7 +102,7 @@ Endpoint returns sales rep list with details The Sales Commission API differs from other Chargify API endpoints. This resource is associated with the seller itself. Up to now all available resources were at the level of the site, therefore creating the API Key per site was a sufficient solution. To share resources at the seller level, a new authentication method was introduced, which is user authentication. Creating an API Key for a user is a required step to correctly use the Sales Commission API, more details [here](https://developers.chargify.com/docs/developer-docs/ZG9jOjMyNzk5NTg0-2020-04-20-new-api-authentication). -Access to the Sales Commission API endpoints is available to users with financial access, where the seller has the Advanced Analytics component enabled. For further information on getting access to Advanced Analytics please contact Maxio support. +Access to the Sales Commission API endpoints is available to users with financial access, where the seller has the Advanced Analytics component enabled. For further information on getting access to Advanced Analytics contact Maxio support. > Note: The request is at seller level, it means `<>` variable will be replaced by `app` @@ -131,7 +131,7 @@ def list_sales_reps(self, collect = { 'seller_id': 'seller_id8', 'authorization': 'Bearer <>', - 'page': 2, + 'page': 1, 'per_page': 100 } result = sales_commissions_controller.list_sales_reps(collect) @@ -230,7 +230,7 @@ Endpoint returns sales rep and attached subscriptions details. The Sales Commission API differs from other Chargify API endpoints. This resource is associated with the seller itself. Up to now all available resources were at the level of the site, therefore creating the API Key per site was a sufficient solution. To share resources at the seller level, a new authentication method was introduced, which is user authentication. Creating an API Key for a user is a required step to correctly use the Sales Commission API, more details [here](https://developers.chargify.com/docs/developer-docs/ZG9jOjMyNzk5NTg0-2020-04-20-new-api-authentication). -Access to the Sales Commission API endpoints is available to users with financial access, where the seller has the Advanced Analytics component enabled. For further information on getting access to Advanced Analytics please contact Maxio support. +Access to the Sales Commission API endpoints is available to users with financial access, where the seller has the Advanced Analytics component enabled. For further information on getting access to Advanced Analytics contact Maxio support. > Note: The request is at seller level, it means `<>` variable will be replaced by `app` @@ -268,7 +268,7 @@ sales_rep_id = 'sales_rep_id4' authorization = 'Bearer <>' -page = 2 +page = 1 per_page = 100 diff --git a/doc/controllers/sites.md b/doc/controllers/sites.md index 7075fc99..99fc54c5 100644 --- a/doc/controllers/sites.md +++ b/doc/controllers/sites.md @@ -157,7 +157,7 @@ def list_chargify_js_public_keys(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50 } result = sites_controller.list_chargify_js_public_keys(collect) diff --git a/doc/controllers/subscription-components.md b/doc/controllers/subscription-components.md index 3c1f80bc..97937c7c 100644 --- a/doc/controllers/subscription-components.md +++ b/doc/controllers/subscription-components.md @@ -572,7 +572,7 @@ subscription_id = 222 component_id = 222 -page = 2 +page = 1 result = subscription_components_controller.list_allocations( subscription_id, @@ -1033,34 +1033,35 @@ subscription_components_controller.delete_prepaid_usage_allocation( # Create Usage -## Documentation +Records an instance of metered or prepaid usage for a subscription. + +You can report metered or prepaid usage to Advanced Billing as often as you wish. You can report usage as it happens or periodically, such as each night or once per billing period. -Full documentation on how to create Components in the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24261149711501-Create-Edit-and-Archive-Components). Additionally, for information on how to record component usage against a subscription, please see the following resources: +Full documentation on how to create Components in the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24261149711501-Create-Edit-and-Archive-Components). Additionally, for information on how to record component usage against a subscription, see the following resources: -+ [Recording Metered Component Usage](https://maxio.zendesk.com/hc/en-us/articles/24251890500109-Reporting-Component-Allocations#reporting-metered-component-usage) -+ [Reporting Prepaid Component Status](https://maxio.zendesk.com/hc/en-us/articles/24251890500109-Reporting-Component-Allocations#reporting-prepaid-component-status) +It is not possible to record metered usage for more than one component at a time Usage should be reported as one API call per component on a single subscription. For example, to record that a subscriber has sent both an SMS Message and an Email, send an API call for each. -You may choose to report metered or prepaid usage to Advanced Billing as often as you wish. You may report usage as it happens. You may also report usage periodically, such as each night or once per billing period. If usage events occur in your system very frequently (on the order of thousands of times an hour), it is best to accumulate usage into batches on your side, and then report those batches less frequently, such as daily. This will ensure you remain below any API throttling limits. If your use case requires higher rates of usage reporting, we recommend utilizing Events Based Components. +See the following product documention articles for more information: -## Create Usage for Subscription +- [Create and Manage Components](https://maxio.zendesk.com/hc/en-us/articles/24261149711501-Create-Edit-and-Archive-Components). A +- [Recording Metered Component Usage](https://maxio.zendesk.com/hc/en-us/articles/24251890500109-Reporting-Component-Allocations#reporting-metered-component-usage) +- [Reporting Prepaid Component Status](https://maxio.zendesk.com/hc/en-us/articles/24251890500109-Reporting-Component-Allocations#reporting-prepaid-component-status) -This endpoint allows you to record an instance of metered or prepaid usage for a subscription. The `quantity` from usage for each component is accumulated to the `unit_balance` on the [Component Line Item](./b3A6MTQxMDgzNzQ-read-subscription-component) for the subscription. +The `quantity` from usage for each component is accumulated to the `unit_balance` on the [Component Line Item](../../doc/controllers/subscription-components.md#read-subscription-component) for the subscription. ## Price Point ID usage -If you are using price points, for metered and prepaid usage components, Advanced Billing gives you the option to specify a price point in your request. +If you are using price points, for metered and prepaid usage components Advanced Billing gives you the option to specify a price point in your request. You do not need to specify a price point ID. If a price point is not included, the default price point for the component will be used when the usage is recorded. -If an invalid `price_point_id` is submitted, the endpoint will return an error. - ## Deducting Usage -In the event that you need to reverse a previous usage report or otherwise deduct from the current usage balance, you may provide a negative quantity. +If you need to reverse a previous usage report or otherwise deduct from the current usage balance, you can provide a negative quantity. Example: -Previously recorded: +Previously recorded quantity was 5000: ```json { @@ -1071,7 +1072,7 @@ Previously recorded: } ``` -At this point, `unit_balance` would be `5000`. To reduce the balance to `0`, POST the following payload: +To reduce the quantity to `0`, POST the following payload: ```json { @@ -1084,12 +1085,6 @@ At this point, `unit_balance` would be `5000`. To reduce the balance to `0`, POS The `unit_balance` has a floor of `0`; negative unit balances are never allowed. For example, if the usage balance is 100 and you deduct 200 units, the unit balance would then be `0`, not `-100`. -## FAQ - -Q. Is it possible to record metered usage for more than one component at a time? - -A. No. Usage should be reported as one API call per component on a single subscription. For example, to record that a subscriber has sent both an SMS Message and an Email, send an API call for each. - ```python def create_usage(self, subscription_id_or_reference, @@ -1202,7 +1197,7 @@ def list_usages(self, collect = { 'subscription_id_or_reference': 234, 'component_id': 144, - 'page': 2, + 'page': 1, 'per_page': 50 } result = subscription_components_controller.list_usages(collect) @@ -1484,7 +1479,7 @@ def list_subscription_components_for_site(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50, 'sort': ListSubscriptionComponentsSort.UPDATED_AT, 'filter': ListSubscriptionComponentsForSiteFilter( diff --git a/doc/controllers/subscription-group-invoice-account.md b/doc/controllers/subscription-group-invoice-account.md index 22eb0fd7..bc428adc 100644 --- a/doc/controllers/subscription-group-invoice-account.md +++ b/doc/controllers/subscription-group-invoice-account.md @@ -92,7 +92,7 @@ def list_prepayments_for_subscription_group(self, ```python collect = { 'uid': 'uid0', - 'page': 2, + 'page': 1, 'per_page': 50, 'filter': ListPrepaymentsFilter( date_field=ListPrepaymentDateField.CREATED_AT, diff --git a/doc/controllers/subscription-group-status.md b/doc/controllers/subscription-group-status.md index df231927..a8287072 100644 --- a/doc/controllers/subscription-group-status.md +++ b/doc/controllers/subscription-group-status.md @@ -18,9 +18,9 @@ subscription_group_status_controller = client.subscription_group_status # Cancel Subscriptions in Group -This endpoint will immediately cancel all subscriptions within the specified group. The group is identified by it's `uid` passed in the URL. To successfully cancel the group, the primary subscription must be on automatic billing. The group members as well must be on automatic billing or they must be prepaid. +Cancels all subscriptions within the specified group immediately. The group is identified by the `uid` that is passed in the URL. To successfully cancel the group, the primary subscription must be on automatic billing. The group members must be on automatic billing or prepaid. -In order to cancel a subscription group while also charging for any unbilled usage on metered or prepaid components, the `charge_unbilled_usage=true` parameter must be included in the request. +To cancel a subscription group while also charging for any unbilled usage on metered or prepaid components, the `charge_unbilled_usage=true` parameter must be included in the request. ```python def cancel_subscriptions_in_group(self, @@ -63,7 +63,7 @@ subscription_group_status_controller.cancel_subscriptions_in_group( # Initiate Delayed Cancellation for Group -This endpoint will schedule all subscriptions within the specified group to be canceled at the end of their billing period. The group is identified by it's uid passed in the URL. +This endpoint will schedule all subscriptions within the specified group to be canceled at the end of their billing period. The group is identified by its uid passed in the URL. All subscriptions in the group must be on automatic billing in order to successfully cancel them, and the group must not be in a "past_due" state. diff --git a/doc/controllers/subscription-groups.md b/doc/controllers/subscription-groups.md index 7f4aafc9..c3cd4240 100644 --- a/doc/controllers/subscription-groups.md +++ b/doc/controllers/subscription-groups.md @@ -32,6 +32,8 @@ You must provide one and only one of the `payment_profile_id`/`credit_card_attri Only one of the `subscriptions` can have `"primary": true` attribute set. When passing product to a subscription you can use either `product_id` or `product_handle` or `offer_id`. You can also use `custom_price` instead. +The subscription request examples below will be split into two sections. +The first section, "Subscription Customization", will focus on passing different information with a subscription, such as components, calendar billing, and custom fields. These examples will presume you are using a secure chargify_token generated by Chargify.js. ```python def signup_with_subscription_group(self, @@ -180,7 +182,7 @@ def list_subscription_groups(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50, 'include': [ SubscriptionGroupsListInclude.ACCOUNT_BALANCES @@ -514,7 +516,7 @@ For sites making use of the [Relationship Billing](https://maxio.zendesk.com/hc/ Passing `group` parameters with a `target` containing a `type` and optional `id` is all that's needed. When the `target` parameter specifies a `"customer"` or `"subscription"` that is already part of a hierarchy, the subscription will become a member of the customer's subscription group. If the target customer or subscription is not part of a subscription group, a new group will be created and the subscription will become part of the group with the specified target customer set as the responsible payer for the group's subscriptions. -**Please Note:** In order to add an existing subscription to a subscription group, it must belong to either the same customer record as the target, or be within the same customer hierarchy. +**Note:** In order to add an existing subscription to a subscription group, it must belong to either the same customer record as the target, or be within the same customer hierarchy. Rather than specifying a customer, the `target` parameter could instead simply have a value of @@ -522,7 +524,7 @@ Rather than specifying a customer, the `target` parameter could instead simply h * `"parent"` which indicates the subscription will be paid for by the subscribing customer's parent within a customer hierarchy, or * `"eldest"` which indicates the subscription will be paid for by the root-level customer in the subscribing customer's hierarchy. -To create a new subscription into a subscription group, please reference the following: +To create a new subscription into a subscription group, reference the following: [Create Subscription in a Subscription Group](https://developers.chargify.com/docs/api-docs/d571659cf0f24-create-subscription#subscription-in-a-subscription-group) ```python diff --git a/doc/controllers/subscription-invoice-account.md b/doc/controllers/subscription-invoice-account.md index 34d7bfe1..5d0383a7 100644 --- a/doc/controllers/subscription-invoice-account.md +++ b/doc/controllers/subscription-invoice-account.md @@ -56,7 +56,7 @@ In order to specify a prepayment made against a subscription, specify the `amoun When the `method` specified is `"credit_card_on_file"`, the prepayment amount will be collected using the default credit card payment profile and applied to the prepayment account balance. This is especially useful for manual replenishment of prepaid subscriptions. -Please note that you **can't** pass `amount_in_cents`. +Note that passing `amount_in_cents` is now allowed. ```python def create_prepayment(self, @@ -146,7 +146,7 @@ def list_prepayments(self, ```python collect = { 'subscription_id': 222, - 'page': 2, + 'page': 1, 'per_page': 50, 'filter': ListPrepaymentsFilter( date_field=ListPrepaymentDateField.CREATED_AT, @@ -320,7 +320,7 @@ def list_service_credits(self, ```python subscription_id = 222 -page = 2 +page = 1 per_page = 50 diff --git a/doc/controllers/subscription-notes.md b/doc/controllers/subscription-notes.md index 1d70b88d..dfc2f06e 100644 --- a/doc/controllers/subscription-notes.md +++ b/doc/controllers/subscription-notes.md @@ -98,7 +98,7 @@ def list_subscription_notes(self, ```python collect = { 'subscription_id': 222, - 'page': 2, + 'page': 1, 'per_page': 50 } result = subscription_notes_controller.list_subscription_notes(collect) diff --git a/doc/controllers/subscription-products.md b/doc/controllers/subscription-products.md index 8bdd64c3..fdc2cdcb 100644 --- a/doc/controllers/subscription-products.md +++ b/doc/controllers/subscription-products.md @@ -30,11 +30,11 @@ Full documentation on how to record Migrations in the Advanced Billing UI can be ## Failed Migrations -One of the most common ways that a migration can fail is when the attempt is made to migrate a subscription to it's current product. Please be aware of this issue! +Importaint note: One of the most common ways that a migration can fail is when the attempt is made to migrate a subscription to its current product. ## Migration 3D Secure - Stripe -It may happen that a payment needs 3D Secure Authentication when the subscription is migrated to a new product; this is referred to in our help docs as a [post-authentication flow](https://maxio.zendesk.com/hc/en-us/articles/24176278996493-Testing-Implementing-3D-Secure#psd2-flows-pre-authentication-and-post-authentication). The server returns `422 Unprocessable Entity` in this case with the following response: +When a payment requires 3D Secure Authentication to adhear to Strong Customer Authentication (SCA) when the subscription is migrated to a new product, the request enters a [post-authentication flow](https://maxio.zendesk.com/hc/en-us/articles/24176278996493-Testing-Implementing-3D-Secure#psd2-flows-pre-authentication-and-post-authentication). The server returns `422 Unprocessable Entity` in this case with the following response: ```json { @@ -62,7 +62,7 @@ The final URL that you send a customer to to complete 3D Secure may resemble the ### Example Redirect Flow -You may wish to redirect customers to different pages depending on whether their SCA was performed successfully. Here's an example flow to use as a reference: +You may wish to redirect customers to different pages depending on whether SCA was performed successfully. Here's an example flow to use as a reference: 1. Create a migration via API; it requires 3DS 2. You receive a `gateway_payment_id` in the `action_link` along other params in the response. diff --git a/doc/controllers/subscription-status.md b/doc/controllers/subscription-status.md index c1721023..17f6861a 100644 --- a/doc/controllers/subscription-status.md +++ b/doc/controllers/subscription-status.md @@ -527,7 +527,7 @@ This will place the subscription in the on_hold state and it will not renew. ## Limitations -You may not place a subscription on hold if the `next_billing` date is within 24 hours. +You may not place a subscription on hold if the `next_billing_at` date is within 24 hours. ```python def pause_subscription(self, @@ -856,8 +856,7 @@ print(result) Advanced Billing offers the ability to reactivate a previously canceled subscription. For details on how the reactivation works, and how to reactivate subscriptions through the application, see [reactivation](https://maxio.zendesk.com/hc/en-us/articles/24252109503629-Reactivating-and-Resuming). -**Please note: The term -"resume" is used also during another process in Advanced Billing. This occurs when an on-hold subscription is "resumed". This returns the subscription to an active state.** +**Note: The term "resume" is used also during another process in Advanced Billing. This occurs when an on-hold subscription is "resumed". This returns the subscription to an active state.** + The response returns the subscription object in the `active` or `trialing` state. + The `canceled_at` and `cancellation_message` fields do not have values. @@ -1297,7 +1296,7 @@ print(result) The Chargify API allows you to preview a renewal by posting to the renewals endpoint. Renewal Preview is an object representing a subscription’s next assessment. You can retrieve it to see a snapshot of how much your customer will be charged on their next renewal. -The "Next Billing" amount and "Next Billing" date are already represented in the UI on each Subscriber's Summary. For more information, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24252493695757-Subscriber-Interface-Overview). +The "Next Billing" amount and "Next Billing" date are already represented in the UI on each Subscriber's Summary. For more information, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24252493695757-Subscriber-Interface-Overview). ## Optional Component Fields diff --git a/doc/controllers/subscriptions.md b/doc/controllers/subscriptions.md index 643b1343..ce719048 100644 --- a/doc/controllers/subscriptions.md +++ b/doc/controllers/subscriptions.md @@ -26,624 +26,21 @@ subscriptions_controller = client.subscriptions # Create Subscription -Full documentation on how subscriptions operate within Advanced Billing can be located under the following topics: +Creates a Subscription for a customer and product -+ [Subscriptions Reference](https://maxio.zendesk.com/hc/en-us/articles/24251526991757-Subscription-Overview) -+ [Subscriptions Actions](https://maxio.zendesk.com/hc/en-us/articles/24251983024653-Subscription-Actions-Overview) -+ [Subscription Cancellation](https://maxio.zendesk.com/hc/en-us/articles/24251957778829-Cancel-Subscriptions) -+ [Subscription Reactivation](https://maxio.zendesk.com/hc/en-us/articles/24252109503629-Reactivating-and-Resuming) -+ [Subscription Import](https://maxio.zendesk.com/hc/en-us/articles/24251489107213-Imports) +Specify the product with `product_id` or `product_handle`. To set a specific product pricepPoint, use `product_price_point_handle` or `product_price_point_id`. -When creating a subscription, you must specify a product and a customer. Credit card details may be required, depending on the options for the Product being subscribed ([see Product Options](https://maxio.zendesk.com/hc/en-us/articles/24261076617869-Product-Editing)). +Identify an existing customer with `customer_id` or `customer_reference`. Optionally, include an existing payment profile using `payment_profile_id`. To create a new customer, pass customer_attributes. -The product may be specified by `product_id` or by `product_handle` (API Handle). In similar fashion, to pass a particular product price point, you may either use `product_price_point_handle` or `product_price_point_id`. +Select an option from the **Request Examples** drop-down on the right side of the portal to see examples of common scenarios for creating subscriptions. -An existing customer may be specified by a `customer_id` (ID within Advanced Billing) or a `customer_reference` (unique value within your app that you have shared with Advanced Billing via the reference attribute on a customer). You may also pass in an existing payment profile for that customer with `payment_profile_id`. A new customer may be created by providing `customer_attributes`. +Payment information may be required to create a subscription, depending on the options for the Product being subscribed. See [product options](https://docs.maxio.com/hc/en-us/articles/24261076617869-Edit-Products) for more information. See the [Payments Profile](../../doc/controllers/payment-profiles.md#create-payment-profile) endpoint for details on payment parameters. -Credit card details may be required, depending on the options for the product being subscribed. The product can be specified by `product_id` or by `product_handle` (API Handle). +Do not use real card information for testing. See the Sites articles that cover [testing your site setup](https://docs.maxio.com/hc/en-us/articles/24250712113165-Testing-Overview#testing-overview-0-0) for more details on testing in your sandbox. -If you are creating a subscription with a payment profile, the attribute to send will be `credit_card_attributes` or `bank_account_attributes` for ACH and Direct Debit. That said, when you read the subscription after creation, we return the profile details under `credit_card` or `bank_account`. +Note that collecting and sending raw card details in production requires [PCI compliance](https://docs.maxio.com/hc/en-us/articles/24183956938381-PCI-Compliance#pci-compliance-0-0) on your end. If your business is not PCI compliant, use [Chargify.js](https://docs.maxio.com/hc/en-us/articles/38163190843789-Chargify-js-Overview#chargify-js-overview-0-0) to collect credit card or bank account information. -## Bulk creation of subscriptions - -Bulk creation of subscriptions is currently not supported. For scenarios where multiple subscriptions must be added, particularly when assigning to the same subscription group, it is essential to switch to a single-threaded approach. - -To avoid data conflicts or inaccuracies, incorporate a sleep interval between requests. - -While this single-threaded approach may impact performance, it ensures data consistency and accuracy in cases where concurrent creation attempts could otherwise lead to issues with subscription alignment and integrity. - -## Taxable Subscriptions - -If your intent is to charge your subscribers tax via [Avalara Taxes](https://maxio.zendesk.com/hc/en-us/articles/24287043035661-Avalara-VAT-Tax) or [Custom Taxes](https://maxio.zendesk.com/hc/en-us/articles/24287044212749-Custom-Taxes), there are a few considerations to be made regarding collecting subscription data. -For subscribers to be eligible to be taxed, the following information for the `customer` object or `payment_profile` object must by supplied: - -+ A subscription to a [taxable product](https://maxio.zendesk.com/hc/en-us/articles/24261076617869-Product-Editing#tax-settings) -+ [Full valid billing or shipping address](https://maxio.zendesk.com/hc/en-us/articles/24287008131853-Advanced-Billing-Managed-Sales-Tax#full-address-required-for-taxable-subscriptions) to identify the tax locale -+ The portion of the address that houses the [state information](https://maxio.zendesk.com/hc/en-us/articles/24287008131853-Advanced-Billing-Managed-Sales-Tax#required-state-format-for-taxable-subscriptions) of either adddress must adhere to the ISO standard of a 2-3 character limit/format. -+ The portion of the address that houses the [country information](https://maxio.zendesk.com/hc/en-us/articles/24287008131853-Advanced-Billing-Managed-Sales-Tax#required-country-format-for-taxable-subscriptions) must adhere to the ISO standard of a 2 character limit/format. - -## Subscription Request Examples - -The subscription examples below will be split into two sections. - -The first section, "Subscription Customization", will focus on passing different information with a subscription, such as components, calendar billing, and custom fields. These examples will presume you are using a secure `chargify_token` generated by Chargify.js. - -The second section, "Passing Payment Information", will focus on passing payment information into Advanced Billing. Please be aware that collecting and sending Advanced Billing raw card details requires PCI compliance on your end; these examples are provided as guidance. If your business is not PCI compliant, we recommend using Chargify.js to collect credit cards or bank accounts. - -# Subscription Customization - -## With Components - -Different components require slightly different data. For example, quantity-based and on/off components accept `allocated_quantity`, while metered components accept `unit_balance`. - -When creating a subscription with a component, a `price_point_id` can be passed in along with the `component_id` to specify which price point to use. If not passed in, the default price point will be used. - -Note: if an invalid `price_point_id` is used, the subscription will still proceed but will use the component's default price point. - -Components and their price points may be added by ID or by handle. See the example request body labeled "Components By Handle (Quantity-Based)"; the format will be the same for other component types. - -## With Coupon(s) - -Pass an array of `coupon_codes`. See the example request body "With Coupon". - -## With Manual Invoice Collection - -The `invoice` collection method works only on legacy Statement Architecture. - -On Relationship Invoicing Architecture use the `remittance` collection method. - -## Prepaid Subscription - -A prepaid subscription can be created with the usual subscription creation parameters, specifying `prepaid` as the `payment_collection_method` and including a nested `prepaid_configuration`. - -After a prepaid subscription has been created, additional funds can be manually added to the prepayment account through the [Create Prepayment Endpoint](https://developers.chargify.com/docs/api-docs/7ec482de77ba7-create-prepayment). - -Prepaid subscriptions do not work on legacy Statement Architecture. - -## With Metafields - -Metafields can either attach to subscriptions or customers. Metafields are popuplated with the supplied metadata to the resource specified. - -If the metafield doesn't exist yet, it will be created on-the-fly. - -## With Custom Pricing - -Custom pricing is pricing specific to the subscription in question. -Create a subscription with custom pricing by passing pricing information instead of a price point. -For a custom priced product, pass the custom_price object in place of `product_price_point_id`. For a custom priced component, pass the `custom_price` object within the component object. -Custom prices and price points can exist in harmony on a subscription. - -# Passing Payment Information - -## Subscription with Chargify.js token - -The `chargify_token` can be obtained using [Chargify.js](https://docs.maxio.com/hc/en-us/articles/38163190843789-Chargify-js-Overview#chargify-js-overview-0-0). The token represents payment profile attributes that were provided by the customer in their browser and stored at the payment gateway. - -The `payment_type` attribute may either be `credit_card` or `bank_account`, depending on the type of payment method being added. If a bank account is being passed, the payment attributes should be changed to `bank_account_attributes`. - -```json -{ - "subscription": { - "product_handle": "pro-plan", - "customer_attributes": { - "first_name": "Joe", - "last_name": "Smith", - "email": "j.smith@example.com" - }, - "credit_card_attributes": { - "chargify_token": "tok_cwhvpfcnbtgkd8nfkzf9dnjn", - "payment_type": "credit_card" - } - } -} -``` - -## Subscription with vault token - -If you already have a customer and card stored in your payment gateway, you may create a subscription with a `vault_token`. Providing the last_four, card type and expiration date will allow the card to be displayed properly in the Advanced Billing UI. - -```json -{ - "subscription": { - "product_handle": "pro-plan", - "customer_attributes": { - "first_name": "Joe", - "last_name": "Smith", - "email": "j.smith@example.com" - }, - "credit_card_attributes": { - first_name: "Joe, - last_name: "Smith", - card_type: "visa", - expiration_month: "05", - expiration_year: "2025", - last_four: "1234", - vault_token: "12345abc", - current_vault: "braintree_blue" - } -} -``` - -## Subscription with ACH as Payment Profile - -```json -{ - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Joe", - "last_name": "Blow", - "email": "joe@example.com", - "zip": "02120", - "state": "MA", - "reference": "XYZ", - "phone": "(617) 111 - 0000", - "organization": "Acme", - "country": "US", - "city": "Boston", - "address_2": null, - "address": "123 Mass Ave." - }, - "bank_account_attributes": { - "bank_name": "Best Bank", - "bank_routing_number": "021000089", - "bank_account_number": "111111111111", - "bank_account_type": "checking", - "bank_account_holder_type": "business", - "payment_type": "bank_account" - } - } -} -``` - -## Subscription with PayPal payment profile - -### With the nonce from Braintree JS - -```json -{ "subscription": { - "product_handle":"test-product-b", - "customer_attributes": { - "first_name":"Amelia", - "last_name":"Johnson", - "email":"amelia@example.com", - "organization":"My Awesome Company" - }, - "payment_profile_attributes":{ - "paypal_email": "amelia@example.com", - "current_vault": "braintree_blue", - "payment_method_nonce":"abc123", - "payment_type":"paypal_account" - } - } -``` - -### With the Braintree Customer ID as the vault token: - -```json -{ "subscription": { - "product_handle":"test-product-b", - "customer_attributes": { - "first_name":"Amelia", - "last_name":"Johnson", - "email":"amelia@example.com", - "organization":"My Awesome Company" - }, - "payment_profile_attributes":{ - "paypal_email": "amelia@example.com", - "current_vault": "braintree_blue", - "vault_token":"58271347", - "payment_type":"paypal_account" - } - } -``` - -## Subscription using GoCardless Bank Number - -These examples creates a customer, bank account and mandate in GoCardless. - -For more information on GoCardless, please view the following two resources: - -+ [Payment Profiles via API for GoCardless](https://developers.chargify.com/docs/api-docs/1f10a4f170405-create-payment-profile#gocardless) - -+ [Full documentation on GoCardless](https://maxio.zendesk.com/hc/en-us/articles/24176159136909-GoCardless) - -+ [Using Chargify.js with GoCardless - minimal example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QQZKCER8CFK40MR6XJ) - -+ [Using Chargify.js with GoCardless - full example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QR09JVHWW0MCA7HVJV) - -```json -{ - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "Royal Bank of France", - "bank_account_number": "0000000", - "bank_routing_number": "0003", - "bank_branch_code": "00006", - "payment_type": "bank_account", - "billing_address": "20 Place de la Gare", - "billing_city": "Colombes", - "billing_state": "Île-de-France", - "billing_zip": "92700", - "billing_country": "FR" - } - } -} -``` - -## Subscription using GoCardless IBAN Number - -```json -{ - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "French Bank", - "bank_iban": "FR1420041010050500013M02606", - "payment_type": "bank_account", - "billing_address": "20 Place de la Gare", - "billing_city": "Colombes", - "billing_state": "Île-de-France", - "billing_zip": "92700", - "billing_country": "FR" - } - } -} -``` - -## Subscription using Stripe SEPA Direct Debit - -For more information on Stripe Direct Debit, please view the following two resources: - -+ [Payment Profiles via API for Stripe SEPA Direct Debit](https://developers.chargify.com/docs/api-docs/1f10a4f170405-create-payment-profile#sepa-direct-debit) - -+ [Full documentation on Stripe Direct Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Stripe-SEPA-and-BECS-Direct-Debit) - -+ [Using Chargify.js with Stripe SEPA or BECS Direct Debit - minimal example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QQFKKN8Z7B7DZ9AJS5) - -+ [Using Chargify.js with Stripe SEPA Direct Debit - full example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QR09JVHWW0MCA7HVJV) - -```json -{ - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "Test Bank", - "bank_iban": "DE89370400440532013000", - "payment_type": "bank_account" - } - } -} -``` - -## Subscription using Stripe BECS Direct Debit - -For more information on Stripe Direct Debit, please view the following two resources: - -+ [Payment Profiles via API for Stripe BECS Direct Debit](../../doc/controllers/payment-profiles.md#create-payment-profile) - -+ [Full documentation on Stripe Direct Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Stripe-SEPA-and-BECS-Direct-Debit) - -+ [Using Chargify.js with Stripe SEPA, BECS or BACS Direct Debit - minimal example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QQFKKN8Z7B7DZ9AJS5) - -+ [Using Chargify.js with Stripe BECS Direct Debit - full example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QRX4B1TYZKZD8ZND6D) - -```json -{ - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "Test Bank", - "bank_branch_code": "000000", - "bank_account_number": "000123456", - "payment_type": "bank_account" - } - } -} -``` - -## Subscription using Stripe BACS Direct Debit - -For more information on Stripe Direct Debit, please view the following two resources: - -+ [Payment Profiles via API for Stripe BACS Direct Debit](../../doc/controllers/payment-profiles.md#create-payment-profile) - -+ [Full documentation on Stripe Direct Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Stripe-SEPA-and-BECS-Direct-Debit) - -+ [Using Chargify.js with Stripe SEPA, BECS or BACS Direct Debit - minimal example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QQFKKN8Z7B7DZ9AJS5) - -+ [Using Chargify.js with Stripe BACS Direct Debit - full example](https://docs.maxio.com/hc/en-us/articles/38206331271693-Examples#h_01K0PJ15QR7PA1DJ3XE9MD05FM) - -```json -{ - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "Test Bank", - "bank_branch_code": "108800", - "bank_account_number": "00012345", - "payment_type": "bank_account", - "billing_address": "123 Main St.", - "billing_city": "London", - "billing_state": "LND", - "billing_zip": "W1A 1AA", - "billing_country": "GB" - } - } -} -``` - -## 3D Secure - Stripe - -It may happen that a payment needs 3D Secure Authentication when the subscription is created; this is referred to in our help docs as a [post-authentication flow](https://maxio.zendesk.com/hc/en-us/articles/24176278996493-Testing-Implementing-3D-Secure#psd2-flows-pre-authentication-and-post-authentication). The server returns `422 Unprocessable Entity` in this case with the following response: - -```json -{ - "errors": [ - "Your card was declined. This transaction requires 3D secure authentication." - ], - "gateway_payment_id": "pi_1F0aGoJ2UDb3Q4av7zU3sHPh", - "description": "This card requires 3D secure authentication. Redirect the customer to the URL from the action_link attribute to authenticate. Attach callback_url param to this URL if you want to be notified about the result of 3D Secure authentication. Attach redirect_url param to this URL if you want to redirect a customer back to your page after 3D Secure authentication. Example: https://mysite.chargify.com/3d-secure/pi_1FCm4RKDeye4C0XfbqquXRYm?one_time_token_id=128&callback_url=https://localhost:4000&redirect_url=https://yourpage.com will do a POST request to https://localhost:4000 after payment is authenticated and will redirect a customer to https://yourpage.com after 3DS authentication.", - "action_link": "http://acme.chargify.com/3d-secure/pi_1F0aGoJ2UDb3Q4av7zU3sHPh?one_time_token_id=242" -} -``` - -To let the customer go through 3D Secure Authentication, they need to be redirected to the URL specified in `action_link`. -Optionally, you can specify `callback_url` parameter in the `action_link` URL if you’d like to be notified about the result of 3D Secure Authentication. The `callback_url` will return the following information: - -- whether the authentication was successful (`success`) -- the gateway ID for the payment (`gateway_payment_id`) -- the subscription ID (`subscription_id`) - -Lastly, you can also specify a `redirect_url` within the `action_link` URL if you’d like to redirect a customer back to your site. - -It is not possible to use `action_link` in an iframe inside a custom application. You have to redirect the customer directly to the `action_link`, then, to be notified about the result, use `redirect_url` or `callback_url`. - -The final URL that you send a customer to to complete 3D Secure may resemble the following, where the first half is the `action_link` and the second half contains a `redirect_url` and `callback_url`: `https://mysite.chargify.com/3d-secure/pi_1FCm4RKDeye4C0XfbqquXRYm?one_time_token_id=128&callback_url=https://localhost:4000&redirect_url=https://yourpage.com` - -## 3D Secure - Checkout - -It may happen that a payment needs 3D Secure Authentication when the subscription is created; this is referred to in our help docs as a [post-authentication flow](https://maxio.zendesk.com/hc/en-us/articles/24176278996493-Testing-Implementing-3D-Secure#psd2-flows-pre-authentication-and-post-authentication). The server returns `422 Unprocessable Entity` in this case with the following response: - -```json -{ - "errors": [ - "Your card was declined. This transaction requires 3D secure authentication." - ], - "gateway_payment_id": "pay_6gjofv7dlyrkpizlolsuspvtiu", - "description": "This card requires 3D secure authentication. Redirect the customer to the URL from the action_link attribute to authenticate. Attach callback_url param to this URL if you want to be notified about the result of 3D Secure authentication. Attach redirect_url param to this URL if you want to redirect a customer back to your page after 3D Secure authentication. Example: https://mysite.chargify.com/3d-secure/pay_6gjofv7dlyrkpizlolsuspvtiu?one_time_token_id=123&callback_url=https://localhost:4000&redirect_url=https://yourpage.com will do a POST request to https://localhost:4000 after payment is authenticated and will redirect a customer to https://yourpage.com after 3DS authentication.", - "action_link": "http://mysite.chargify.com/3d-secure/pay_6gjofv7dlyrkpizlolsuspvtiu?one_time_token_id=123" -} -``` - -To let the customer go through 3D Secure Authentication, they need to be redirected to the URL specified in `action_link`. -Optionally, you can specify `callback_url` parameter in the `action_link` URL if you’d like to be notified about the result of 3D Secure Authentication. The `callback_url` will return the following information: - -- whether the authentication was successful (`success`) -- the gateway ID for the payment (`gateway_payment_id`) -- the subscription ID (`subscription_id`) - -Lastly, you can also specify a `redirect_url` parameter within the `action_link` URL if you’d like to redirect a customer back to your site. - -It is not possible to use `action_link` in an iframe inside a custom application. You have to redirect the customer directly to the `action_link`, then, to be notified about the result, use `redirect_url` or `callback_url`. - -The final URL that you send a customer to complete 3D Secure may resemble the following, where the first half is the `action_link` and the second half contains a `redirect_url` and `callback_url`: `https://mysite.chargify.com/3d-secure/pay_6gjofv7dlyrkpizlolsuspvtiu?one_time_token_id=123&callback_url=https://localhost:4000&redirect_url=https://yourpage.com` - -### Example Redirect Flow - -You may wish to redirect customers to different pages depending on whether their SCA was performed successfully. Here's an example flow to use as a reference: - -1. Create a subscription via API; it requires 3DS -2. You receive a `gateway_payment_id` in the `action_link` along other params in the response. -3. Use this `gateway_payment_id` to, for example, connect with your internal resources or generate a session_id -4. Include 1 of those attributes inside the `callback_url` and `redirect_url` to be aware which “session” this applies to -5. Redirect the customer to the `action_link` with `callback_url` and `redirect_url` applied -6. After the customer finishes 3DS authentication, we let you know the result by making a request to applied `callback_url`. -7. After that, we redirect the customer to the `redirect_url`; at this point the result of authentication is known -8. Optionally, you can use the applied "msg" param in the `redirect_url` to determine whether it was successful or not - -## Subscriptions Import - -Subscriptions can be “imported” via the API to handle the following scenarios: - -+ You already have existing subscriptions with specific start and renewal dates that you would like to import to Advanced Billing -+ You already have credit cards stored in your provider’s vault and you would like to create subscriptions using those tokens - -Before importing, you should have already set up your products to match your offerings. Then, you can create Subscriptions via the API just like you normally would, but using a few special attributes. - -Full documentation on how import Subscriptions using the **import tool** in the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24251489107213-Imports). - -### Important Notices and Disclaimers regarding Imports - -Before performing a bulk import of subscriptions via the API, we suggest reading the [Subscriptions Import](https://maxio.zendesk.com/hc/en-us/articles/24251489107213-Imports) instructions to understand the repurcussions of a large import. - -### Subscription Input Attributes - -The following _additional_ attributes to the subscription input attributes make imports possible: `next_billing_at`, `previous_billing_at`, and `import_mrr`. - -### Current Vault - -If you are using a Legacy gateway such as "eWAY Rapid (Legacy)" or "Stripe (Legacy)" then please contact Support for further instructions on subscription imports. - -### Braintree Blue (Braintree v2) Imports - -Braintree Blue is Braintree’s newer (version 2) API. For this gateway, please provide the `vault_token` parameter with the value from Braintree’s “Customer ID” rather than the “Payment Profile Token”. At this time we do not use `current_vault_token` with the Braintree Blue gateway, and we only support a single payment profile per Braintree Customer. - -When importing PayPal type payment profiles, please set `payment_type` to `paypal_account`. - -### Stripe ACH Imports - -If the bank account has already been verified, currently you will need to create the customer, create the payment profile in Advanced Billing - setting verified=true, then create a subscription using the customer_id and payment_profile_id. - -### Webhooks During Import - -If no `next_billing_at` is provided, webhooks will be fired as normal. If you do set a future `next_billing_at`, only a subset of the webhooks are fired when the subscription is created. Keep reading for more information as to what webhooks will be fired under which scenarios. - -#### Successful creation with Billing Date - -Scenario: If `next_billing_at` provided - -+ `signup_success` -+ `billing_date_change` - -#### Successful creation without Billing Date - -Scenario: If no `next_billing_at` provided - -+ `signup_success` -+ `payment_success` - -#### Unsuccessful creation - -Scenario: If card can’t be charged, and no `next_billing_at` provided - -+ signup_failure - -#### Webhooks fired when next_billing_at is reached: - -+ `renewal_success or renewal_failure` -+ `payment_success or payment_failure` - -### Date and Time Formats - -We will attempt to parse any string you send as the value of next_billing_at in to a date or time. For best results, use a known format like described in “Date and Time Specification” of RFC 2822 or ISO 8601 . - -The following are all equivalent and will work as input to `next_billing_at`: - -``` -Aug 06 2030 11:34:00 -0400 -Aug 06 2030 11:34 -0400 -2030-08-06T11:34:00-04:00 -8/6/2030 11:34:00 EDT -8/6/2030 8:34:00 PDT -2030-08-06T15:34:00Z -``` - -You may also pass just a date, in which case we will assume the time to be noon - -``` -2010-08-06 -``` - -## Subscription Hierarchies & WhoPays - -When subscription groups were first added to our Relationship Invoicing architecture, to group together invoices for related subscriptions and allow for complex customer hierarchies and WhoPays scenarios, they were designed to consist of a primary and a collection of group members. The primary would control many aspects of the group, such as when the consolidated invoice is generated. As of today, groups still function this way. - -In the future, the concept of a "primary" will be removed in order to offer more flexibility into group management and reduce confusion concerning what actions must be done on a primary level, rather than a member level. - -We have introduced a two scheme system as a bridge between these two group organizations. Scheme 1, which is relevant to all subscription groups today, marks the group as being "ruled" by a primary. - -When reading a subscription via API, they will return a top-level attribute called `group`, which will denote which scheme is being used. At this time, the `scheme` attribute will always be 1. - -### Subscription in a Customer Hierarchy - -For sites making use of the [Relationship Billing](https://maxio.zendesk.com/hc/en-us/articles/24252287829645-Advanced-Billing-Invoices-Overview) and [Customer Hierarchy](https://maxio.zendesk.com/hc/en-us/articles/24252185211533-Customer-Hierarchies-WhoPays) features, it is possible to create subscriptions within a customer hierarchy. This can be achieved through the API by passing group parameters in the **Create Subscription** request. - -+ The `group` parameters are optional and consist of the required `target` and optional `billing` parameters. - -When the `target` parameter specifies a customer that is already part of a hierarchy, the new subscription will become a member of the customer hierarchy as well. If the target customer is not part of a hierarchy, a new customer hierarchy will be created and both the target customer and the new subscription will become part of the hierarchy with the specified target customer set as the responsible payer for the hierarchy's subscriptions. - -Rather than specifying a customer, the `target` parameter could instead simply have a value of `self` which indicates the subscription will be paid for not by some other customer, but by the subscribing customer. This will be true whether the customer is being created new, is already part of a hierarchy, or already exists outside a hierarchy. A valid payment method must also be specified in the subscription parameters. - -Note that when creating subscriptions in a customer hierarchy, if the customer hierarchy does not already have a payment method, passing valid credit card attributes in the subscription parameters will also result in the payment method being established as the default payment method for the customer hierarchy irrespective of the responsible payer. - -The optional `billing` parameters specify how some aspects of the billing for the new subscription should be handled. Rather than capturing payment immediately, the `accrue` parameter can be included so that the new subscription charges accrue until the next assessment date. Regarding the date, the `align_date` parameter can be included so that the billing date of the new subscription matches up with the default subscription group in the customer hierarchy. When choosing to align the dates, the `prorate` parameter can also be specified so that the new subscription charges are prorated based on the billing period of the default subscription group in the customer hierarchy also. - -### Subscription in a Subscription Group - -For sites making use of [Relationship Billing](https://maxio.zendesk.com/hc/en-us/articles/24252287829645-Advanced-Billing-Invoices-Overview) it may be desireable to create a subscription as part of a [subscription group](https://maxio.zendesk.com/hc/en-us/articles/24252172565005-Subscription-Groups-Overview) in order to rely on [invoice consolidation](https://maxio.zendesk.com/hc/en-us/articles/24252269909389-Invoice-Consolidation). This can be achieved through the API by passing group parameters in the Create Subscription request. The `group` parameters are optional and consist of the required `target` and optional `billing` parameters. - -The `target` parameters specify an existing subscription with which the newly created subscription should be grouped. If the target subscription is already part of a group, the new subscription will become a member of the group as well. If the target subscription is not part of a group, a new group will be created and both the target and the new subscription will become part of the group with the target as the group's primary subscription. - -The optional `billing` parameters specify how some aspects of the billing for the new subscription should be handled. Rather than capturing payment immediately, the `accrue` parameter can be included so that the new subscription charges accrue until the next assessment date. Regarding the date, the `align_date` parameter can be included so that the billing date of the new subscription matches up with the target subscription. When choosing to align the dates, the `prorate` parameter can also be specified so that the new subscription charges are prorated based on the billing period of the target subscription also. - -## Providing Agreement Acceptance Params - -It is possible to provide a proof of customer's acceptance of terms and policies. -We will be storing this proof in case it might be required (i.e. chargeback). -Currently, we already keep it for subscriptions created via Public Signup Pages. -In order to create a subscription with the proof of agreement acceptance, you must provide additional parameters `agreement acceptance` with `ip_address` and at least one url to the policy that was accepted: `terms_url` or `privacy_policy_url`. Additional urls that can be provided: `return_refund_policy_url`, `delivery_policy_url` and -`secure_checkout_policy_url`. - -```json - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "agreement_acceptance": { - "ip_address": "1.2.3.4", - "terms_url": "https://terms.url", - "privacy_policy_url": "https://privacy_policy.url", - "return_refund_policy_url": "https://return_refund_policy.url", - "delivery_policy_url": "https://delivery_policy.url", - "secure_checkout_policy_url": "https://secure_checkout_policy.url" - } - } -} -``` - -**For Maxio Payments subscriptions, the agreement acceptance params are required, with at least terms_url provided.** - -## Providing ACH Agreement params - -It is also possible to provide a proof that a customer authorized ACH agreement terms. -The proof will be stored and the email will be sent to the customer with a copy of the terms (if enabled). -In order to create a subscription with the proof of authorized ACH agreement terms, you must provide the additional parameter `ach_agreement` with the following nested parameters: `agreement_terms`, `authorizer_first_name`, `authorizer_last_name` and `ip_address`. -Each of them is required. - -```json - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" - }, - "bank_account_attributes": { - "bank_name": "Test Bank", - "bank_routing_number": "021000089", - "bank_account_number": "111111111111", - "bank_account_type": "checking", - "bank_account_holder_type": "business", - "payment_type": "bank_account" - }, - "ach_agreement": { - "agreement_terms": "ACH agreement terms", - "authorizer_first_name": "Jane", - "authorizer_last_name": "Doe", - "ip_address": "1.2.3.4" - } - } -``` +See the [Subscription Signups](page:introduction/basic-concepts/subscription-signup) article for more information on working with subscriptions in Advanced Billing. ```python def create_subscription(self, @@ -669,7 +66,7 @@ body = CreateSubscriptionRequest( payment_collection_method=CollectionMethod.REMITTANCE, customer_attributes=CustomerAttributes( first_name='Joe', - last_name='Blow', + last_name='Smith', email='joe@example.com', organization='Acme', reference='XYZ', @@ -882,7 +279,7 @@ def list_subscriptions(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50, 'start_date': dateutil.parser.parse('2022-07-01').date(), 'end_date': dateutil.parser.parse('2022-08-01').date(), @@ -900,47 +297,55 @@ print(result) # Update Subscription -The subscription endpoint allows you to instantly update one or many attributes about a subscription in a single call. +Updates one or more attributes of a subscription. ## Update Subscription Payment Method -Change the card that your Subscriber uses for their subscription. You can also use this method to simply change the expiration date of the card **if your gateway allows**. +Change the card that your subscriber uses for their subscription. You can also use this method to change the expiration date of the card **if your gateway allows**. -Note that partial card updates for **Authorize.Net** are not allowed via this endpoint. The existing Payment Profile must be directly updated instead. +Do not use real card information for testing. See the Sites articles that cover [testing your site setup](https://docs.maxio.com/hc/en-us/articles/24250712113165-Testing-Overview#testing-overview-0-0) for more details on testing in your sandbox. + +Note that collecting and sending raw card details in production requires [PCI compliance](https://docs.maxio.com/hc/en-us/articles/24183956938381-PCI-Compliance#pci-compliance-0-0) on your end. If your business is not PCI compliant, use [Chargify.js](https://docs.maxio.com/hc/en-us/articles/38163190843789-Chargify-js-Overview#chargify-js-overview-0-0) to collect credit card or bank account information. + +> Note: Partial card updates for **Authorize.Net** are not allowed via this endpoint. The existing Payment Profile must be directly updated instead. + +## Update Product You also use this method to change the subscription to a different product by setting a new value for product_handle. A product change can be done in two different ways, **product change** or **delayed product change**. -## Product Change +### Product Change -This endpoint may be used to change a subscription's product. The new payment amount is calculated and charged at the normal start of the next period. If you desire complex product changes or prorated upgrades and downgrades instead, please see the documentation on Migrating Subscription Products. +You can change a subscription's product. The new payment amount is calculated and charged at the normal start of the next period. If you require complex product changes or prorated upgrades and downgrades instead, please see the documentation on [Migrating Subscription Products](https://docs.maxio.com/hc/en-us/articles/24252069837581-Product-Changes-and-Migrations#product-changes-and-migrations-0-0). -To perform a product change, simply set either the `product_handle` or `product_id` attribute to that of a different product from the same site as the subscription. You can also change the price point by passing in either `product_price_point_id` or `product_price_point_handle` - otherwise the new product's default price point will be used. +To perform a product change, set either the `product_handle` or `product_id` attribute to that of a different product from the same site as the subscription. You can also change the price point by passing in either `product_price_point_id` or `product_price_point_handle` - otherwise the new product's default price point is used. ### Delayed Product Change This method also changes the product and/or price point, and the new payment amount is calculated and charged at the normal start of the next period. -This method schedules the product change to happen automatically at the subscription’s next renewal date. To perform a Delayed Product Change, set the `product_handle` attribute as you would in a regular product change, but also set the `product_change_delayed` attribute to `true`. No proration applies in this case. +This method schedules the product change to happen automatically at the subscription’s next renewal date. To perform a delayed product change, set the `product_handle` attribute as you would in a regular product change, but also set the `product_change_delayed` attribute to `true`. No proration applies in this case. You can also perform a delayed change to the price point by passing in either `product_price_point_id` or `product_price_point_handle` -**Note: To cancel a delayed product change, set `next_product_id` to an empty string.** +> **Note:** To cancel a delayed product change, set `next_product_id` to an empty string. ## Billing Date Changes +You can update dates for a subscrption. + ### Regular Billing Date Changes Send the `next_billing_at` to set the next billing date for the subscription. After that date passes and the subscription is processed, the following billing date will be set according to the subscription's product period. -Note that if you pass an invalid date, we will automatically interpret and set the correct date. For example, when February 30 is entered, the next billing will be set to March 2nd in a non-leap year. +> Note: If you pass an invalid date, the correct date is automatically set to he correct date. For example, if February 30 is passed, the next billing would be set to March 2nd in a non-leap year. -The server response will not return data under the key/value pair of `next_billing`. Please view the key/value pair of `current_period_ends_at` to verify that the `next_billing` date has been changed successfully. +The server response will not return data under the key/value pair of `next_billing_at`. View the key/value pair of `current_period_ends_at` to verify that the `next_billing_at` date has been changed successfully. -### Snap Day Changes +### Calendar Billing and Snap Day Changes For a subscription using Calendar Billing, setting the next billing date is a bit different. Send the `snap_day` attribute to change the calendar billing date for **a subscription using a product eligible for calendar billing**. -Note: If you change the product associated with a subscription that contains a `snap_date` and immediately `READ/GET` the subscription data, it will still contain evidence of the existing `snap_date`. This is due to the fact that a product change is instantanous and only affects the product associated with a subscription. After the `next_billing` date arrives, the `snap_day` associated with the subscription will return to `null.` Another way of looking at this is that you willl have to wait for the next billing cycle to arrive before the `snap_date` will reset to `null`. +> Note: If you change the product associated with a subscription that contains a `snap_day` and immediately `READ/GET` the subscription data, it will still contain original `snap_day`. The `snap_day`will will reset to 'null on the next billing cycle. This is because a product change is instantanous and only affects the product associated with a subscription. ```python def update_subscription(self, @@ -1382,7 +787,7 @@ For sites in test mode, you may purge individual subscriptions. Provide the subscription ID in the url. To confirm, supply the customer ID in the query string `ack` parameter. You may also delete the customer record and/or payment profiles by passing `cascade` parameters. For example, to delete just the customer record, the query params would be: `?ack={customer_id}&cascade[]=customer` -If you need to remove subscriptions from a live site, please contact support to discuss your use case. +If you need to remove subscriptions from a live site, contact support to discuss your use case. ### Delete customer and payment profile @@ -1505,7 +910,7 @@ The "Next Billing" amount and "Next Billing" date are represented in each Subscr A subscription will not be created by utilizing this endpoint; it is meant to serve as a prediction. -For more information, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24252493695757-Subscriber-Interface-Overview). +For more information, see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24252493695757-Subscriber-Interface-Overview). ## Taxable Subscriptions @@ -1515,15 +920,15 @@ This endpoint will preview taxes applicable to a purchase. In order for taxes to + The preview must be for the purchase of a taxable product or component, or combination of the two. + The subscription payload must contain a full billing or shipping address in order to calculate tax -For more information about creating taxable previews, please see our documentation guide on how to create [taxable subscriptions.](https://maxio.zendesk.com/hc/en-us/sections/24287012349325-Taxes) +For more information about creating taxable previews, see our documentation guide on how to create [taxable subscriptions.](https://maxio.zendesk.com/hc/en-us/sections/24287012349325-Taxes) -You do **not** need to include a card number to generate tax information when you are previewing a subscription. However, please note that when you actually want to create the subscription, you must include the credit card information if you want the billing address to be stored in Advanced Billing. The billing address and the credit card information are stored together within the payment profile object. Also, you may not send a billing address to Advanced Billing without payment profile information, as the address is stored on the card. +You do **not** need to include a card number to generate tax information when you are previewing a subscription. However, when you actually want to create the subscription, you must include the credit card information if you want the billing address to be stored in Advanced Billing. The billing address and the credit card information are stored together within the payment profile object. Also, you may not send a billing address to Advanced Billing without payment profile information, as the address is stored on the card. You can pass shipping and billing addresses and still decide not to calculate taxes. To do that, pass `skip_billing_manifest_taxes: true` attribute. ## Non-taxable Subscriptions -If you'd like to calculate subscriptions that do not include tax, please feel free to leave off the billing information. +If you'd like to calculate subscriptions that do not include tax you may leave off the billing information. ```python def preview_subscription(self, @@ -1885,7 +1290,7 @@ print(result) Use this endpoint to remove a coupon from an existing subscription. -For more information on the expected behaviour of removing a coupon from a subscription, please see our documentation [here.](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupons-and-Subscriptions#removing-a-coupon) +For more information on the expected behaviour of removing a coupon from a subscription, See our documentation [here.](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupons-and-Subscriptions#removing-a-coupon) ```python def remove_coupon_from_subscription(self, diff --git a/doc/controllers/webhooks.md b/doc/controllers/webhooks.md index a42b79c7..80d5527f 100644 --- a/doc/controllers/webhooks.md +++ b/doc/controllers/webhooks.md @@ -47,7 +47,7 @@ def list_webhooks(self, ```python collect = { - 'page': 2, + 'page': 1, 'per_page': 50 } result = webhooks_controller.list_webhooks(collect) diff --git a/doc/environment-based-client-initialization.md b/doc/environment-based-client-initialization.md new file mode 100644 index 00000000..64f3faa5 --- /dev/null +++ b/doc/environment-based-client-initialization.md @@ -0,0 +1,55 @@ + +# Environment-Based Client Initialization + +The SDK client can also be initialized directly from environment variables using the `from_environment()` class method. This allows the SDK to automatically read configuration values from the runtime environment or a .env file. + +## Example + +```python +from advancedbilling.advanced_billing_client import AdvancedBillingClient + +# Specify the path to your .env file if it’s located outside the project’s root directory. +client = AdvancedBillingClient.from_environment(dotenv_path='/path/to/.env') +``` + +You can also specify a path to a `.env` file by passing it to the `from_environment()` method: + +The same method can accept keyword arguments to override any values read from the environment, and the arguments to override values should follow the same approach as code-based client initialization. + +```python +from advancedbilling.advanced_billing_client import AdvancedBillingClient + +client = AdvancedBillingClient.from_environment( + dotenv_path='/path/to/.env', + timeout=0, # overrides timeout from environment variable +) +``` + +Values provided through arguments take precedence over those defined in environment variables. + +## Example `.env` File + +```python +SITE=subdomain +ENVIRONMENT=us + +USERNAME=ExampleUsername +PASSWORD=ExamplePassword + +TIMEOUT=60 +MAX_RETRIES=3 +BACKOFF_FACTOR=2 +RETRY_STATUSES=408,413 +RETRY_METHODS=GET,PUT,DELETE + +# Proxy Configuration +PROXY_ADDRESS=http://localhost:3000 +PROXY_PORT=8080 +PROXY_USERNAME=username +PROXY_PASSWORD=password +``` + +## Note + +- If an environment variable is not defined, the default SDK configuration value will be used. + diff --git a/doc/models/activate-event-based-component.md b/doc/models/activate-event-based-component.md index 0fa98ddd..eaedd613 100644 --- a/doc/models/activate-event-based-component.md +++ b/doc/models/activate-event-based-component.md @@ -10,7 +10,7 @@ | Name | Type | Tags | Description | | --- | --- | --- | --- | | `price_point_id` | `int` | Optional | The Chargify id of the price point | -| `billing_schedule` | [`BillingSchedule`](../../doc/models/billing-schedule.md) | Optional | This attribute is particularly useful when you need to align billing events for different components on distinct schedules within a subscription. Please note this only works for site with Multifrequency enabled | +| `billing_schedule` | [`BillingSchedule`](../../doc/models/billing-schedule.md) | Optional | This attribute is particularly useful when you need to align billing events for different components on distinct schedules within a subscription. This only works for site with Multifrequency enabled. | | `custom_price` | [`ComponentCustomPrice`](../../doc/models/component-custom-price.md) | Optional | Create or update custom pricing unique to the subscription. Used in place of `price_point_id`. | ## Example (as JSON) @@ -37,7 +37,8 @@ "ending_quantity": 40, "unit_price": 23.26 } - ] + ], + "renew_prepaid_allocation": false } } ``` diff --git a/doc/models/billing-schedule.md b/doc/models/billing-schedule.md index 1486c22e..2af9d195 100644 --- a/doc/models/billing-schedule.md +++ b/doc/models/billing-schedule.md @@ -1,7 +1,7 @@ # Billing Schedule -This attribute is particularly useful when you need to align billing events for different components on distinct schedules within a subscription. Please note this only works for site with Multifrequency enabled +This attribute is particularly useful when you need to align billing events for different components on distinct schedules within a subscription. This only works for site with Multifrequency enabled. ## Structure diff --git a/doc/models/bulk-create-product-price-points-request.md b/doc/models/bulk-create-product-price-points-request.md index a0851743..c3330592 100644 --- a/doc/models/bulk-create-product-price-points-request.md +++ b/doc/models/bulk-create-product-price-points-request.md @@ -26,7 +26,7 @@ "trial_price_in_cents": 196, "trial_interval": 250, "trial_interval_unit": "day", - "trial_type": "trial_type6" + "trial_type": "no_obligation" } ] } diff --git a/doc/models/calendar-billing.md b/doc/models/calendar-billing.md index 93451e59..d74182bc 100644 --- a/doc/models/calendar-billing.md +++ b/doc/models/calendar-billing.md @@ -11,14 +11,14 @@ | Name | Type | Tags | Description | | --- | --- | --- | --- | -| `snap_day` | int \| str \| None | Optional | This is a container for one-of cases. | +| `snap_day` | int \| [SnapDay](../../doc/models/snap-day.md) \| None | Optional | This is a container for one-of cases. | | `calendar_billing_first_charge` | [`FirstChargeType`](../../doc/models/first-charge-type.md) | Optional | - | ## Example (as JSON) ```json { - "snap_day": 210, + "snap_day": 28, "calendar_billing_first_charge": "prorated" } ``` diff --git a/doc/models/chargify-ebb.md b/doc/models/chargify-ebb.md index 6c77ff27..7539e669 100644 --- a/doc/models/chargify-ebb.md +++ b/doc/models/chargify-ebb.md @@ -10,8 +10,8 @@ | Name | Type | Tags | Description | | --- | --- | --- | --- | | `timestamp` | `datetime` | Optional | This timestamp determines what billing period the event will be billed in. If your request payload does not include it, Chargify will add `chargify.timestamp` to the event payload and set the value to `now`. | -| `id` | `str` | Optional | A unique ID set by Chargify. Please note that this field is reserved. If `chargify.id` is present in the request payload, it will be overwritten. | -| `created_at` | `datetime` | Optional | An ISO-8601 timestamp, set by Chargify at the time each event is recorded. Please note that this field is reserved. If `chargify.created_at` is present in the request payload, it will be overwritten. | +| `id` | `str` | Optional | A unique ID set by Chargify. This field is reserved. If `chargify.id` is present in the request payload, it will be overwritten. | +| `created_at` | `datetime` | Optional | An ISO-8601 timestamp, set by Chargify at the time each event is recorded. This field is reserved. If `chargify.created_at` is present in the request payload, it will be overwritten. | | `uniqueness_token` | `str` | Optional | User-defined string scoped per-stream. Duplicate events within a stream will be silently ignored. Tokens expire after 31 days.

**Constraints**: *Maximum Length*: `64` | | `subscription_id` | `int` | Optional | Id of Maxio Advanced Billing Subscription which is connected to this event.
Provide `subscription_id` if you configured `chargify.subscription_id` as Subscription Identifier in your Event Stream. | | `subscription_reference` | `str` | Optional | Reference of Maxio Advanced Billing Subscription which is connected to this event.
Provide `subscription_reference` if you configured `chargify.subscription_reference` as Subscription Identifier in your Event Stream. | diff --git a/doc/models/component-custom-price.md b/doc/models/component-custom-price.md index 234e69bc..adf51d9d 100644 --- a/doc/models/component-custom-price.md +++ b/doc/models/component-custom-price.md @@ -16,6 +16,10 @@ Create or update custom pricing unique to the subscription. Used in place of `pr | `interval` | `int` | Optional | The numerical interval. i.e. an interval of ‘30’ coupled with an interval_unit of day would mean this component price point would renew every 30 days. This property is only available for sites with Multifrequency enabled. | | `interval_unit` | [`IntervalUnit`](../../doc/models/interval-unit.md) | Optional | A string representing the interval unit for this component price point, either month or day. This property is only available for sites with Multifrequency enabled. | | `prices` | [`List[Price]`](../../doc/models/price.md) | Required | On/off components only need one price bracket starting at 1 | +| `renew_prepaid_allocation` | `bool` | Optional | Applicable only to prepaid usage components. Controls whether the allocated quantity renews each period. | +| `rollover_prepaid_remainder` | `bool` | Optional | Applicable only to prepaid usage components. Controls whether remaining units roll over to the next period. | +| `expiration_interval` | `int` | Optional | Applicable only when rollover is enabled. Number of `expiration_interval_unit`s after which rollover amounts expire. | +| `expiration_interval_unit` | [`ExpirationIntervalUnit`](../../doc/models/expiration-interval-unit.md) | Optional | Applicable only when rollover is enabled. Interval unit for rollover expiration (month or day). | ## Example (as JSON) @@ -31,7 +35,8 @@ Create or update custom pricing unique to the subscription. Used in place of `pr "tax_included": false, "pricing_scheme": "stairstep", "interval": 162, - "interval_unit": "day" + "interval_unit": "day", + "renew_prepaid_allocation": false } ``` diff --git a/doc/models/component.md b/doc/models/component.md index 569e36fa..bcae9eaf 100644 --- a/doc/models/component.md +++ b/doc/models/component.md @@ -21,7 +21,6 @@ | `price_per_unit_in_cents` | `int` | Optional | deprecated - use unit_price instead | | `kind` | [`ComponentKind`](../../doc/models/component-kind.md) | Optional | A handle for the component type | | `archived` | `bool` | Optional | Boolean flag describing whether a component is archived or not. | -| `taxable` | `bool` | Optional | Boolean flag describing whether a component is taxable or not. | | `description` | `str` | Optional | The description of the component. | | `default_price_point_id` | `int` | Optional | - | | `overage_prices` | [`List[ComponentPrice]`](../../doc/models/component-price.md) | Optional | Applicable only to prepaid usage components. An array of overage price brackets. | @@ -29,7 +28,8 @@ | `price_point_count` | `int` | Optional | Count for the number of price points associated with the component | | `price_points_url` | `str` | Optional | URL that points to the location to read the existing price points via GET request | | `default_price_point_name` | `str` | Optional | - | -| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using the Avalara service to tax based on locale. This attribute has a max length of 10 characters. | +| `taxable` | `bool` | Optional | Boolean flag describing whether a component is taxable or not. | +| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using AvaTax to tax based on locale. This attribute has a max length of 25 characters. | | `recurring` | `bool` | Optional | - | | `upgrade_charge` | [`CreditType`](../../doc/models/credit-type.md) | Optional | The type of credit to be created when upgrading/downgrading. Defaults to the component and then site setting if one is not provided.
Available values: `full`, `prorated`, `none`. | | `downgrade_credit` | [`CreditType`](../../doc/models/credit-type.md) | Optional | The type of credit to be created when upgrading/downgrading. Defaults to the component and then site setting if one is not provided.
Available values: `full`, `prorated`, `none`. | diff --git a/doc/models/containers/calendar-billing-snap-day.md b/doc/models/containers/calendar-billing-snap-day.md index c07e74cf..d850a0d6 100644 --- a/doc/models/containers/calendar-billing-snap-day.md +++ b/doc/models/containers/calendar-billing-snap-day.md @@ -3,12 +3,12 @@ ## Data Type -`int | str` +`int | SnapDay` ## Cases | Type | | --- | | `int` | -| `str` | +| [`SnapDay`](../../../doc/models/snap-day.md) | diff --git a/doc/models/containers/subscription-snap-day.md b/doc/models/containers/subscription-snap-day.md new file mode 100644 index 00000000..d1b61cf5 --- /dev/null +++ b/doc/models/containers/subscription-snap-day.md @@ -0,0 +1,14 @@ + +# Subscription Snap Day + +## Data Type + +`int | SnapDay` + +## Cases + +| Type | +| --- | +| `int` | +| [`SnapDay`](../../../doc/models/snap-day.md) | + diff --git a/doc/models/containers/update-subscription-snap-day.md b/doc/models/containers/update-subscription-snap-day.md index cb9174db..e6d532a3 100644 --- a/doc/models/containers/update-subscription-snap-day.md +++ b/doc/models/containers/update-subscription-snap-day.md @@ -3,12 +3,12 @@ ## Data Type -`SnapDay | int` +`int | SnapDay` ## Cases | Type | | --- | -| [`SnapDay`](../../../doc/models/snap-day.md) | | `int` | +| [`SnapDay`](../../../doc/models/snap-day.md) | diff --git a/doc/models/create-allocation.md b/doc/models/create-allocation.md index 768b643c..4ea3ad94 100644 --- a/doc/models/create-allocation.md +++ b/doc/models/create-allocation.md @@ -19,7 +19,7 @@ | `upgrade_charge` | [`CreditType`](../../doc/models/credit-type.md) | Optional | The type of credit to be created when upgrading/downgrading. Defaults to the component and then site setting if one is not provided.
Available values: `full`, `prorated`, `none`. | | `initiate_dunning` | `bool` | Optional | If set to true, if the immediate component payment fails, initiate dunning for the subscription.
Otherwise, leave the charges on the subscription to pay for at renewal. Defaults to false. | | `price_point_id` | str \| int \| None | Optional | This is a container for one-of cases. | -| `billing_schedule` | [`BillingSchedule`](../../doc/models/billing-schedule.md) | Optional | This attribute is particularly useful when you need to align billing events for different components on distinct schedules within a subscription. Please note this only works for site with Multifrequency enabled | +| `billing_schedule` | [`BillingSchedule`](../../doc/models/billing-schedule.md) | Optional | This attribute is particularly useful when you need to align billing events for different components on distinct schedules within a subscription. This only works for site with Multifrequency enabled. | ## Example (as JSON) diff --git a/doc/models/create-invoice-coupon.md b/doc/models/create-invoice-coupon.md index 204e8c46..15b7b83e 100644 --- a/doc/models/create-invoice-coupon.md +++ b/doc/models/create-invoice-coupon.md @@ -10,6 +10,7 @@ | Name | Type | Tags | Description | | --- | --- | --- | --- | | `code` | `str` | Optional | - | +| `subcode` | `str` | Optional | - | | `percentage` | str \| float \| None | Optional | This is a container for one-of cases. | | `amount` | str \| float \| None | Optional | This is a container for one-of cases. | | `description` | `str` | Optional | **Constraints**: *Maximum Length*: `255` | @@ -22,9 +23,9 @@ { "percentage": 50.0, "code": "code4", + "subcode": "subcode8", "amount": "String9", - "description": "description4", - "product_family_id": "String3" + "description": "description4" } ``` diff --git a/doc/models/create-invoice-item.md b/doc/models/create-invoice-item.md index ecd13e0a..9db6382a 100644 --- a/doc/models/create-invoice-item.md +++ b/doc/models/create-invoice-item.md @@ -12,8 +12,8 @@ | `title` | `str` | Optional | - | | `quantity` | float \| str \| None | Optional | This is a container for one-of cases. | | `unit_price` | float \| str \| None | Optional | This is a container for one-of cases. | -| `taxable` | `bool` | Optional | Set to true to automatically calculate taxes. Site must be configured to use and calculate taxes.

If using Avalara, a tax_code parameter must also be sent. | -| `tax_code` | `str` | Optional | - | +| `taxable` | `bool` | Optional | Set to true to automatically calculate taxes. Site must be configured to use and calculate taxes. If using AvaTax, a tax_code parameter must also be sent. | +| `tax_code` | `str` | Optional | A string representing the tax code related to the product type. This is especially important when using AvaTax to tax based on locale. This attribute has a max length of 25 characters. | | `period_range_start` | `str` | Optional | YYYY-MM-DD | | `period_range_end` | `str` | Optional | YYYY-MM-DD | | `product_id` | str \| int \| None | Optional | This is a container for one-of cases. | diff --git a/doc/models/create-metafield.md b/doc/models/create-metafield.md index cda98100..0d4f7526 100644 --- a/doc/models/create-metafield.md +++ b/doc/models/create-metafield.md @@ -11,7 +11,7 @@ | --- | --- | --- | --- | | `name` | `str` | Optional | - | | `scope` | [`MetafieldScope`](../../doc/models/metafield-scope.md) | Optional | Warning: When updating a metafield's scope attribute, all scope attributes must be passed. Partially complete scope attributes will override the existing settings. | -| `input_type` | [`MetafieldInput`](../../doc/models/metafield-input.md) | Optional | Indicates how data should be added to the metafield. For example, a text type is just a string, so a given metafield of this type can have any value attached. On the other hand, dropdown and radio have a set of allowed values that can be input, and appear differently on a Public Signup Page. Defaults to 'text' | +| `input_type` | [`MetafieldInput`](../../doc/models/metafield-input.md) | Optional | Indicates the type of metafield. A text metafield allows any string value. Dropdown and radio metafields have a set of values that can be selected. Defaults to 'text'. | | `enum` | `List[str]` | Optional | Only applicable when input_type is radio or dropdown. Empty strings will not be submitted. | ## Example (as JSON) diff --git a/doc/models/create-or-update-product.md b/doc/models/create-or-update-product.md index 7ffe6d48..157e6afa 100644 --- a/doc/models/create-or-update-product.md +++ b/doc/models/create-or-update-product.md @@ -13,18 +13,18 @@ | `handle` | `str` | Optional | The product API handle | | `description` | `str` | Required | The product description | | `accounting_code` | `str` | Optional | E.g. Internal ID or SKU Number | -| `require_credit_card` | `bool` | Optional | Deprecated value that can be ignored unless you have legacy hosted pages. For Public Signup Page users, please read this attribute from under the signup page. | +| `require_credit_card` | `bool` | Optional | Deprecated value that can be ignored unless you have legacy hosted pages. For Public Signup Page users, read this attribute from under the signup page. | | `price_in_cents` | `int` | Required | The product price, in integer cents | | `interval` | `int` | Required | The numerical interval. i.e. an interval of ‘30’ coupled with an interval_unit of day would mean this product would renew every 30 days | | `interval_unit` | [`IntervalUnit`](../../doc/models/interval-unit.md) | Required | A string representing the interval unit for this product, either month or day | | `trial_price_in_cents` | `int` | Optional | The product trial price, in integer cents | | `trial_interval` | `int` | Optional | The numerical trial interval. i.e. an interval of ‘30’ coupled with a trial_interval_unit of day would mean this product trial would last 30 days. | | `trial_interval_unit` | [`IntervalUnit`](../../doc/models/interval-unit.md) | Optional | A string representing the trial interval unit for this product, either month or day | -| `trial_type` | `str` | Optional | - | +| `trial_type` | [`TrialType`](../../doc/models/trial-type.md) | Optional | Indicates how a trial is handled when the trail period ends and there is no credit card on file. For `no_obligation`, the subscription transitions to a Trial Ended state. Maxio will not send any emails or statements. For `payment_expected`, the subscription transitions to a Past Due state. Maxio will send normal dunning emails and statements according to your other settings. | | `expiration_interval` | `int` | Optional | The numerical expiration interval. i.e. an expiration_interval of ‘30’ coupled with an expiration_interval_unit of day would mean this product would expire after 30 days. | | `expiration_interval_unit` | [`ExpirationIntervalUnit`](../../doc/models/expiration-interval-unit.md) | Optional | A string representing the expiration interval unit for this product, either month, day or never | | `auto_create_signup_page` | `bool` | Optional | - | -| `tax_code` | `str` | Optional | A string representing the tax code related to the product type. This is especially important when using the Avalara service to tax based on locale. This attribute has a max length of 10 characters.

**Constraints**: *Maximum Length*: `10` | +| `tax_code` | `str` | Optional | A string representing the tax code related to the product type. This is especially important when using AvaTax to tax based on locale. This attribute has a max length of 25 characters. | ## Example (as JSON) diff --git a/doc/models/create-payment-profile.md b/doc/models/create-payment-profile.md index 6b0615a3..0f46211a 100644 --- a/doc/models/create-payment-profile.md +++ b/doc/models/create-payment-profile.md @@ -9,7 +9,7 @@ | Name | Type | Tags | Description | | --- | --- | --- | --- | -| `chargify_token` | `str` | Optional | Token received after sending billing informations using chargify.js. | +| `chargify_token` | `str` | Optional | Token received after sending billing information using chargify.js. | | `id` | `int` | Optional | - | | `payment_type` | [`PaymentType`](../../doc/models/payment-type.md) | Optional | - | | `first_name` | `str` | Optional | First name on card or bank account. If omitted, the first_name from customer attributes will be used. | @@ -23,7 +23,7 @@ | `billing_address_2` | `str` | Optional | Second line of the customer’s billing address i.e. Apt. 100 | | `billing_city` | `str` | Optional | The credit card or bank account billing address city (i.e. “Boston”). This value is merely passed through to the payment gateway. | | `billing_state` | `str` | Optional | The credit card or bank account billing address state (i.e. MA). This value is merely passed through to the payment gateway. This must conform to the [ISO_3166-1](https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) in order to be valid for tax locale purposes. | -| `billing_country` | `str` | Optional | The credit card or bank account billing address country, required in [ISO_3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) format (i.e. “US”). This value is merely passed through to the payment gateway. Some gateways require country codes in a specific format. Please check your gateway’s documentation. If creating an ACH subscription, only US is supported at this time. | +| `billing_country` | `str` | Optional | The credit card or bank account billing address country, required in [ISO_3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) format (i.e. “US”). This value is merely passed through to the payment gateway. Some gateways require country codes in a specific format. Check your gateway’s documentation. If creating an ACH subscription, only US is supported at this time. | | `billing_zip` | `str` | Optional | The credit card or bank account billing address zip code (i.e. 12345). This value is merely passed through to the payment gateway. | | `current_vault` | [`AllVaults`](../../doc/models/all-vaults.md) | Optional | The vault that stores the payment profile with the provided `vault_token`. Use `bogus` for testing. | | `vault_token` | `str` | Optional | The “token” provided by your vault storage for an already stored payment profile | diff --git a/doc/models/create-product-price-point-request.md b/doc/models/create-product-price-point-request.md index 625b3fe5..d0d73471 100644 --- a/doc/models/create-product-price-point-request.md +++ b/doc/models/create-product-price-point-request.md @@ -25,7 +25,7 @@ "trial_price_in_cents": 108, "trial_interval": 202, "trial_interval_unit": "day", - "trial_type": "trial_type4" + "trial_type": "no_obligation" } } ``` diff --git a/doc/models/create-product-price-point.md b/doc/models/create-product-price-point.md index 0316c537..564cef82 100644 --- a/doc/models/create-product-price-point.md +++ b/doc/models/create-product-price-point.md @@ -17,7 +17,7 @@ | `trial_price_in_cents` | `int` | Optional | The product price point trial price, in integer cents | | `trial_interval` | `int` | Optional | The numerical trial interval. i.e. an interval of ‘30’ coupled with a trial_interval_unit of day would mean this product price point trial would last 30 days. | | `trial_interval_unit` | [`IntervalUnit`](../../doc/models/interval-unit.md) | Optional | A string representing the trial interval unit for this product price point, either month or day | -| `trial_type` | `str` | Optional | - | +| `trial_type` | [`TrialType`](../../doc/models/trial-type.md) | Optional | Indicates how a trial is handled when the trail period ends and there is no credit card on file. For `no_obligation`, the subscription transitions to a Trial Ended state. Maxio will not send any emails or statements. For `payment_expected`, the subscription transitions to a Past Due state. Maxio will send normal dunning emails and statements according to your other settings. | | `initial_charge_in_cents` | `int` | Optional | The product price point initial charge, in integer cents | | `initial_charge_after_trial` | `bool` | Optional | - | | `expiration_interval` | `int` | Optional | The numerical expiration interval. i.e. an expiration_interval of ‘30’ coupled with an expiration_interval_unit of day would mean this product price point would expire after 30 days. | @@ -37,7 +37,7 @@ "trial_price_in_cents": 48, "trial_interval": 102, "trial_interval_unit": "day", - "trial_type": "trial_type0" + "trial_type": "no_obligation" } ``` diff --git a/doc/models/create-usage-request.md b/doc/models/create-usage-request.md index a783b50b..d94b5821 100644 --- a/doc/models/create-usage-request.md +++ b/doc/models/create-usage-request.md @@ -21,6 +21,25 @@ "memo": "memo2", "billing_schedule": { "initial_billing_at": "2016-03-13" + }, + "custom_price": { + "tax_included": false, + "pricing_scheme": "stairstep", + "interval": 66, + "interval_unit": "day", + "prices": [ + { + "starting_quantity": 242, + "ending_quantity": 40, + "unit_price": 23.26 + }, + { + "starting_quantity": 242, + "ending_quantity": 40, + "unit_price": 23.26 + } + ], + "renew_prepaid_allocation": false } } } diff --git a/doc/models/create-usage.md b/doc/models/create-usage.md index b9e9a1b0..01e8ec4b 100644 --- a/doc/models/create-usage.md +++ b/doc/models/create-usage.md @@ -12,7 +12,8 @@ | `quantity` | `float` | Optional | integer by default or decimal number if fractional quantities are enabled for the component | | `price_point_id` | `str` | Optional | - | | `memo` | `str` | Optional | - | -| `billing_schedule` | [`BillingSchedule`](../../doc/models/billing-schedule.md) | Optional | This attribute is particularly useful when you need to align billing events for different components on distinct schedules within a subscription. Please note this only works for site with Multifrequency enabled | +| `billing_schedule` | [`BillingSchedule`](../../doc/models/billing-schedule.md) | Optional | This attribute is particularly useful when you need to align billing events for different components on distinct schedules within a subscription. This only works for site with Multifrequency enabled. | +| `custom_price` | [`ComponentCustomPrice`](../../doc/models/component-custom-price.md) | Optional | Create or update custom pricing unique to the subscription. Used in place of `price_point_id`. | ## Example (as JSON) @@ -23,6 +24,25 @@ "memo": "memo2", "billing_schedule": { "initial_billing_at": "2016-03-13" + }, + "custom_price": { + "tax_included": false, + "pricing_scheme": "stairstep", + "interval": 66, + "interval_unit": "day", + "prices": [ + { + "starting_quantity": 242, + "ending_quantity": 40, + "unit_price": 23.26 + }, + { + "starting_quantity": 242, + "ending_quantity": 40, + "unit_price": 23.26 + } + ], + "renew_prepaid_allocation": false } } ``` diff --git a/doc/models/ebb-component.md b/doc/models/ebb-component.md index 11dc6ac5..19273adc 100644 --- a/doc/models/ebb-component.md +++ b/doc/models/ebb-component.md @@ -18,7 +18,7 @@ | `prices` | [`List[Price]`](../../doc/models/price.md) | Optional | (Not required for ‘per_unit’ pricing schemes) One or more price brackets. See [Price Bracket Rules](https://maxio.zendesk.com/hc/en-us/articles/24261149166733-Component-Pricing-Schemes#price-bracket-rules) for an overview of how price brackets work for different pricing schemes. | | `price_points` | [`List[ComponentPricePointItem]`](../../doc/models/component-price-point-item.md) | Optional | - | | `unit_price` | str \| float \| None | Optional | This is a container for one-of cases. | -| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using the Avalara service to tax based on locale. This attribute has a max length of 10 characters. | +| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using AvaTax to tax based on locale. This attribute has a max length of 25 characters. | | `hide_date_range_on_invoice` | `bool` | Optional | (Only available on Relationship Invoicing sites) Boolean flag describing if the service date range should show for the component on generated invoices. | | `event_based_billing_metric_id` | `int` | Required | The ID of an event based billing metric that will be attached to this component. | | `interval` | `int` | Optional | The numerical interval. i.e. an interval of ‘30’ coupled with an interval_unit of day would mean this component's default price point would renew every 30 days. This property is only available for sites with Multifrequency enabled. | diff --git a/doc/models/list-coupons-filter.md b/doc/models/list-coupons-filter.md index 9711b108..9a2e6301 100644 --- a/doc/models/list-coupons-filter.md +++ b/doc/models/list-coupons-filter.md @@ -16,7 +16,8 @@ | `end_datetime` | `datetime` | Optional | The end date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns coupons with a timestamp at or before exact time provided in query. You can specify timezone in query - otherwise your site's time zone will be used. If provided, this parameter will be used instead of end_date. Use in query `filter[end_datetime]=2011-12-1T10:15:30+01:00`. | | `ids` | `List[int]` | Optional | Allows fetching coupons with matching id based on provided values. Use in query `filter[ids]=1,2,3`.

**Constraints**: *Minimum Items*: `1` | | `codes` | `List[str]` | Optional | Allows fetching coupons with matching codes based on provided values. Use in query `filter[codes]=free,free_trial`. | -| `use_site_exchange_rate` | `bool` | Optional | Allows fetching coupons with matching use_site_exchange_rate based on provided value. Use in query `filter[use_site_exchange_rate]=true`. | +| `use_site_exchange_rate` | `bool` | Optional | If true, restricts the list to coupons whose pricing is recalculated from the site’s current exchange rates, so their currency_prices array contains on-the-fly conversions rather than stored price records. If false, restricts the list to coupons that have manually defined amounts for each currency, ensuring the response includes the saved currency_prices entries instead of exchange-rate-derived values. Use in query `filter[use_site_exchange_rate]=true`. | +| `include_archived` | `bool` | Optional | Controls returning archived coupons. | ## Example (as JSON) diff --git a/doc/models/metafield-input.md b/doc/models/metafield-input.md index ec8203b8..75443bd3 100644 --- a/doc/models/metafield-input.md +++ b/doc/models/metafield-input.md @@ -1,7 +1,7 @@ # Metafield Input -Indicates how data should be added to the metafield. For example, a text type is just a string, so a given metafield of this type can have any value attached. On the other hand, dropdown and radio have a set of allowed values that can be input, and appear differently on a Public Signup Page. Defaults to 'text' +Indicates the type of metafield. A text metafield allows any string value. Dropdown and radio metafields have a set of values that can be selected. Defaults to 'text'. ## Enumeration diff --git a/doc/models/metafield-scope.md b/doc/models/metafield-scope.md index b6a72805..7ddc6dac 100644 --- a/doc/models/metafield-scope.md +++ b/doc/models/metafield-scope.md @@ -15,8 +15,8 @@ Warning: When updating a metafield's scope attribute, all scope attributes must | `invoices` | [`IncludeOption`](../../doc/models/include-option.md) | Optional | Include (1) or exclude (0) metafields from invoices. | | `statements` | [`IncludeOption`](../../doc/models/include-option.md) | Optional | Include (1) or exclude (0) metafields from statements. | | `portal` | [`IncludeOption`](../../doc/models/include-option.md) | Optional | Include (1) or exclude (0) metafields from the portal. | -| `public_show` | [`IncludeOption`](../../doc/models/include-option.md) | Optional | Include (1) or exclude (0) metafields from being viewable by your ecosystem. | -| `public_edit` | [`IncludeOption`](../../doc/models/include-option.md) | Optional | Include (1) or exclude (0) metafields from being edited by your ecosystem. | +| `public_show` | [`IncludeOption`](../../doc/models/include-option.md) | Optional | Include (1) or exclude (0) metafields used in [Embeddable Components](page:development-tools/embeddable-components/overview) from being viewable by your ecosystem. | +| `public_edit` | [`IncludeOption`](../../doc/models/include-option.md) | Optional | Include (1) or exclude (0) metafields used in [Embeddable Components](page:development-tools/embeddable-components/overview) from being editable by your ecosystem. | | `hosted` | `List[str]` | Optional | - | ## Example (as JSON) diff --git a/doc/models/metafield.md b/doc/models/metafield.md index 46321e61..419d80f5 100644 --- a/doc/models/metafield.md +++ b/doc/models/metafield.md @@ -12,8 +12,8 @@ | `id` | `int` | Optional | - | | `name` | `str` | Optional | - | | `scope` | [`MetafieldScope`](../../doc/models/metafield-scope.md) | Optional | Warning: When updating a metafield's scope attribute, all scope attributes must be passed. Partially complete scope attributes will override the existing settings. | -| `data_count` | `int` | Optional | the amount of subscriptions this metafield has been applied to in Chargify | -| `input_type` | [`MetafieldInput`](../../doc/models/metafield-input.md) | Optional | Indicates how data should be added to the metafield. For example, a text type is just a string, so a given metafield of this type can have any value attached. On the other hand, dropdown and radio have a set of allowed values that can be input, and appear differently on a Public Signup Page. Defaults to 'text' | +| `data_count` | `int` | Optional | The amount of subscriptions this metafield has been applied to in Advanced Billing. | +| `input_type` | [`MetafieldInput`](../../doc/models/metafield-input.md) | Optional | Indicates the type of metafield. A text metafield allows any string value. Dropdown and radio metafields have a set of values that can be selected. Defaults to 'text'. | | `enum` | str \| List[str] \| None | Optional | This is a container for one-of cases. | ## Example (as JSON) diff --git a/doc/models/metered-component.md b/doc/models/metered-component.md index fed1990e..9fb7b725 100644 --- a/doc/models/metered-component.md +++ b/doc/models/metered-component.md @@ -18,7 +18,7 @@ | `prices` | [`List[Price]`](../../doc/models/price.md) | Optional | (Not required for ‘per_unit’ pricing schemes) One or more price brackets. See [Price Bracket Rules](https://maxio.zendesk.com/hc/en-us/articles/24261149166733-Component-Pricing-Schemes#price-bracket-rules) for an overview of how price brackets work for different pricing schemes. | | `price_points` | [`List[ComponentPricePointItem]`](../../doc/models/component-price-point-item.md) | Optional | - | | `unit_price` | str \| float \| None | Optional | This is a container for one-of cases. | -| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using the Avalara service to tax based on locale. This attribute has a max length of 10 characters. | +| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using AvaTax to tax based on locale. This attribute has a max length of 25 characters. | | `hide_date_range_on_invoice` | `bool` | Optional | (Only available on Relationship Invoicing sites) Boolean flag describing if the service date range should show for the component on generated invoices. | | `display_on_hosted_page` | `bool` | Optional | - | | `allow_fractional_quantities` | `bool` | Optional | - | diff --git a/doc/models/on-off-component.md b/doc/models/on-off-component.md index 385ce7dc..660c33fe 100644 --- a/doc/models/on-off-component.md +++ b/doc/models/on-off-component.md @@ -17,7 +17,7 @@ | `downgrade_credit` | [`CreditType`](../../doc/models/credit-type.md) | Optional | The type of credit to be created when upgrading/downgrading. Defaults to the component and then site setting if one is not provided.
Available values: `full`, `prorated`, `none`. | | `price_points` | [`List[ComponentPricePointItem]`](../../doc/models/component-price-point-item.md) | Optional | - | | `unit_price` | str \| float | Required | This is a container for one-of cases. | -| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using the Avalara service to tax based on locale. This attribute has a max length of 10 characters. | +| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using AvaTax to tax based on locale. This attribute has a max length of 25 characters. | | `hide_date_range_on_invoice` | `bool` | Optional | (Only available on Relationship Invoicing sites) Boolean flag describing if the service date range should show for the component on generated invoices. | | `display_on_hosted_page` | `bool` | Optional | - | | `allow_fractional_quantities` | `bool` | Optional | - | diff --git a/doc/models/payment-profile-attributes.md b/doc/models/payment-profile-attributes.md index 00f02248..3eefdd21 100644 --- a/doc/models/payment-profile-attributes.md +++ b/doc/models/payment-profile-attributes.md @@ -25,7 +25,7 @@ alias to credit_card_attributes | `billing_address_2` | `str` | Optional | (Optional) Second line of the customer’s billing address i.e. Apt. 100 | | `billing_city` | `str` | Optional | (Optional, may be required by your product configuration or gateway settings) The credit card or bank account billing address city (i.e. “Boston”). This value is merely passed through to the payment gateway. | | `billing_state` | `str` | Optional | (Optional, may be required by your product configuration or gateway settings) The credit card or bank account billing address state (i.e. MA). This value is merely passed through to the payment gateway. This must conform to the [ISO_3166-1](https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) in order to be valid for tax locale purposes. | -| `billing_country` | `str` | Optional | (Optional, may be required by your product configuration or gateway settings) The credit card or bank account billing address country, required in [ISO_3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) format (i.e. “US”). This value is merely passed through to the payment gateway. Some gateways require country codes in a specific format. Please check your gateway’s documentation. If creating an ACH subscription, only US is supported at this time. | +| `billing_country` | `str` | Optional | (Optional, may be required by your product configuration or gateway settings) The credit card or bank account billing address country, required in [ISO_3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) format (i.e. “US”). This value is merely passed through to the payment gateway. Some gateways require country codes in a specific format. Check your gateway’s documentation. If creating an ACH subscription, only US is supported at this time. | | `billing_zip` | `str` | Optional | (Optional, may be required by your product configuration or gateway settings) The credit card or bank account billing address zip code (i.e. 12345). This value is merely passed through to the payment gateway. | | `current_vault` | [`AllVaults`](../../doc/models/all-vaults.md) | Optional | (Optional, used only for Subscription Import) The vault that stores the payment profile with the provided vault_token. | | `vault_token` | `str` | Optional | (Optional, used only for Subscription Import) The “token” provided by your vault storage for an already stored payment profile | diff --git a/doc/models/prepaid-usage-component.md b/doc/models/prepaid-usage-component.md index 6ac4bad2..6996ee1a 100644 --- a/doc/models/prepaid-usage-component.md +++ b/doc/models/prepaid-usage-component.md @@ -20,7 +20,7 @@ | `downgrade_credit` | [`CreditType`](../../doc/models/credit-type.md) | Optional | The type of credit to be created when upgrading/downgrading. Defaults to the component and then site setting if one is not provided.
Available values: `full`, `prorated`, `none`. | | `price_points` | [`List[CreatePrepaidUsageComponentPricePoint]`](../../doc/models/create-prepaid-usage-component-price-point.md) | Optional | - | | `unit_price` | str \| float \| None | Optional | This is a container for one-of cases. | -| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using the Avalara service to tax based on locale. This attribute has a max length of 10 characters. | +| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using AvaTax to tax based on locale. This attribute has a max length of 25 characters. | | `hide_date_range_on_invoice` | `bool` | Optional | (Only available on Relationship Invoicing sites) Boolean flag describing if the service date range should show for the component on generated invoices. | | `overage_pricing` | [`OveragePricing`](../../doc/models/overage-pricing.md) | Required | - | | `rollover_prepaid_remainder` | `bool` | Optional | Boolean which controls whether or not remaining units should be rolled over to the next period | diff --git a/doc/models/product-price-point.md b/doc/models/product-price-point.md index 6ac82941..560e6265 100644 --- a/doc/models/product-price-point.md +++ b/doc/models/product-price-point.md @@ -18,7 +18,7 @@ | `trial_price_in_cents` | `int` | Optional | The product price point trial price, in integer cents | | `trial_interval` | `int` | Optional | The numerical trial interval. i.e. an interval of ‘30’ coupled with a trial_interval_unit of day would mean this product price point trial would last 30 days | | `trial_interval_unit` | [`IntervalUnit`](../../doc/models/interval-unit.md) | Optional | A string representing the trial interval unit for this product price point, either month or day | -| `trial_type` | `str` | Optional | - | +| `trial_type` | [`TrialType`](../../doc/models/trial-type.md) | Optional | Indicates how a trial is handled when the trail period ends and there is no credit card on file. For `no_obligation`, the subscription transitions to a Trial Ended state. Maxio will not send any emails or statements. For `payment_expected`, the subscription transitions to a Past Due state. Maxio will send normal dunning emails and statements according to your other settings. | | `introductory_offer` | `bool` | Optional | reserved for future use | | `initial_charge_in_cents` | `int` | Optional | The product price point initial charge, in integer cents | | `initial_charge_after_trial` | `bool` | Optional | - | diff --git a/doc/models/product.md b/doc/models/product.md index 557c8b03..abe3152b 100644 --- a/doc/models/product.md +++ b/doc/models/product.md @@ -14,7 +14,7 @@ | `handle` | `str` | Optional | The product API handle | | `description` | `str` | Optional | The product description | | `accounting_code` | `str` | Optional | E.g. Internal ID or SKU Number | -| `request_credit_card` | `bool` | Optional | Deprecated value that can be ignored unless you have legacy hosted pages. For Public Signup Page users, please read this attribute from under the signup page. | +| `request_credit_card` | `bool` | Optional | Deprecated value that can be ignored unless you have legacy hosted pages. For Public Signup Page users, read this attribute from under the signup page. | | `expiration_interval` | `int` | Optional | A numerical interval for the length a subscription to this product will run before it expires. See the description of interval for a description of how this value is coupled with an interval unit to calculate the full interval | | `expiration_interval_unit` | [`ExpirationIntervalUnit`](../../doc/models/expiration-interval-unit.md) | Optional | A string representing the expiration interval unit for this product, either month, day or never | | `created_at` | `datetime` | Optional | Timestamp indicating when this product was created | @@ -40,7 +40,7 @@ | `request_billing_address` | `bool` | Optional | A boolean indicating whether to request a billing address on any Self-Service Pages that are used by subscribers of this product. | | `require_billing_address` | `bool` | Optional | A boolean indicating whether a billing address is required to add a payment profile, especially at signup. | | `require_shipping_address` | `bool` | Optional | A boolean indicating whether a shipping address is required for the customer, especially at signup. | -| `tax_code` | `str` | Optional | A string representing the tax code related to the product type. This is especially important when using the Avalara service to tax based on locale. This attribute has a max length of 10 characters. | +| `tax_code` | `str` | Optional | A string representing the tax code related to the product type. This is especially important when using AvaTax to tax based on locale. This attribute has a max length of 25 characters. | | `default_product_price_point_id` | `int` | Optional | - | | `use_site_exchange_rate` | `bool` | Optional | - | | `item_category` | `str` | Optional | One of the following: Business Software, Consumer Software, Digital Services, Physical Goods, Other | diff --git a/doc/models/quantity-based-component.md b/doc/models/quantity-based-component.md index 5c01bcd1..535321c2 100644 --- a/doc/models/quantity-based-component.md +++ b/doc/models/quantity-based-component.md @@ -20,7 +20,7 @@ | `downgrade_credit` | [`CreditType`](../../doc/models/credit-type.md) | Optional | The type of credit to be created when upgrading/downgrading. Defaults to the component and then site setting if one is not provided.
Available values: `full`, `prorated`, `none`. | | `price_points` | [`List[ComponentPricePointItem]`](../../doc/models/component-price-point-item.md) | Optional | - | | `unit_price` | str \| float \| None | Optional | This is a container for one-of cases. | -| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using the Avalara service to tax based on locale. This attribute has a max length of 10 characters. | +| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using AvaTax to tax based on locale. This attribute has a max length of 25 characters. | | `hide_date_range_on_invoice` | `bool` | Optional | (Only available on Relationship Invoicing sites) Boolean flag describing if the service date range should show for the component on generated invoices. | | `recurring` | `bool` | Optional | - | | `display_on_hosted_page` | `bool` | Optional | - | diff --git a/doc/models/resume-options.md b/doc/models/resume-options.md index 4c56e6a8..1bc16a54 100644 --- a/doc/models/resume-options.md +++ b/doc/models/resume-options.md @@ -9,7 +9,7 @@ | Name | Type | Tags | Description | | --- | --- | --- | --- | -| `require_resume` | `bool` | Optional | Chargify will only attempt to resume the subscription's billing period. If not resumable, the subscription will be left in it's current state. | +| `require_resume` | `bool` | Optional | Chargify will only attempt to resume the subscription's billing period. If not resumable, the subscription will be left in its current state. | | `forgive_balance` | `bool` | Optional | Indicates whether or not Chargify should clear the subscription's existing balance before attempting to resume the subscription. If subscription cannot be resumed, the balance will remain as it was before the attempt to resume was made. | ## Example (as JSON) diff --git a/doc/models/snap-day.md b/doc/models/snap-day.md index 55479f1d..3d441f69 100644 --- a/doc/models/snap-day.md +++ b/doc/models/snap-day.md @@ -1,8 +1,6 @@ # Snap Day -Use for subscriptions with product eligible for calendar billing only. Value can be 1-28 or 'end'. - ## Enumeration `SnapDay` diff --git a/doc/models/subscription-custom-price.md b/doc/models/subscription-custom-price.md index bb85bdf9..2229e58d 100644 --- a/doc/models/subscription-custom-price.md +++ b/doc/models/subscription-custom-price.md @@ -19,6 +19,7 @@ | `trial_price_in_cents` | str \| int \| None | Optional | This is a container for one-of cases. | | `trial_interval` | str \| int \| None | Optional | This is a container for one-of cases. | | `trial_interval_unit` | [`IntervalUnit`](../../doc/models/interval-unit.md) | Optional | (Optional) | +| `trial_type` | [`TrialType`](../../doc/models/trial-type.md) | Optional | Indicates how a trial is handled when the trail period ends and there is no credit card on file. For `no_obligation`, the subscription transitions to a Trial Ended state. Maxio will not send any emails or statements. For `payment_expected`, the subscription transitions to a Past Due state. Maxio will send normal dunning emails and statements according to your other settings. | | `initial_charge_in_cents` | str \| int \| None | Optional | This is a container for one-of cases. | | `initial_charge_after_trial` | `bool` | Optional | (Optional) | | `expiration_interval` | str \| int \| None | Optional | This is a container for one-of cases. | diff --git a/doc/models/subscription-group-component-custom-price.md b/doc/models/subscription-group-component-custom-price.md index f148baba..644c5a56 100644 --- a/doc/models/subscription-group-component-custom-price.md +++ b/doc/models/subscription-group-component-custom-price.md @@ -39,7 +39,8 @@ Used in place of `price_point_id` to define a custom price point unique to the s "ending_quantity": 40, "unit_price": 23.26 } - ] + ], + "renew_prepaid_allocation": false } ] } diff --git a/doc/models/subscription-group-signup-component.md b/doc/models/subscription-group-signup-component.md index e5da82d1..2c6068c4 100644 --- a/doc/models/subscription-group-signup-component.md +++ b/doc/models/subscription-group-signup-component.md @@ -49,7 +49,8 @@ "ending_quantity": 40, "unit_price": 23.26 } - ] + ], + "renew_prepaid_allocation": false }, { "tax_included": false, @@ -62,7 +63,8 @@ "ending_quantity": 40, "unit_price": 23.26 } - ] + ], + "renew_prepaid_allocation": false }, { "tax_included": false, @@ -75,7 +77,8 @@ "ending_quantity": 40, "unit_price": 23.26 } - ] + ], + "renew_prepaid_allocation": false } ] } diff --git a/doc/models/subscription.md b/doc/models/subscription.md index 774164d1..863b8df4 100644 --- a/doc/models/subscription.md +++ b/doc/models/subscription.md @@ -33,7 +33,7 @@ | `signup_revenue` | `str` | Optional | The revenue, formatted as a string of decimal separated dollars and,cents, from the subscription signup ($50.00 would be formatted as,50.00) | | `delayed_cancel_at` | `datetime` | Optional | Timestamp for when the subscription is currently set to cancel. | | `coupon_code` | `str` | Optional | (deprecated) The coupon code of the single coupon currently applied to the subscription. See coupon_codes instead as subscriptions can now have more than one coupon. | -| `snap_day` | `str` | Optional | The day of the month that the subscription will charge according to calendar billing rules, if used. | +| `snap_day` | int \| [SnapDay](../../doc/models/snap-day.md) \| None | Optional | This is a container for one-of cases. | | `payment_collection_method` | [`CollectionMethod`](../../doc/models/collection-method.md) | Optional | The type of payment collection to be used in the subscription. For legacy Statements Architecture valid options are - `invoice`, `automatic`. For current Relationship Invoicing Architecture valid options are - `remittance`, `automatic`, `prepaid`. | | `customer` | [`Customer`](../../doc/models/customer.md) | Optional | - | | `product` | [`Product`](../../doc/models/product.md) | Optional | - | @@ -51,7 +51,7 @@ | `coupon_codes` | `List[str]` | Optional | An array for all the coupons attached to the subscription. | | `offer_id` | `int` | Optional | The ID of the offer associated with the subscription. | | `payer_id` | `int` | Optional | On Relationship Invoicing, the ID of the individual paying for the subscription. Defaults to the Customer ID unless the 'Customer Hierarchies & WhoPays' feature is enabled. | -| `current_billing_amount_in_cents` | `int` | Optional | The balance in cents plus the estimated renewal amount in cents. Returned ONLY for readSubscription operation as it's compute intensive operation. | +| `current_billing_amount_in_cents` | `int` | Optional | The balance in cents plus the estimated renewal amount in cents. Returned ONLY for the readSubscription operation as it's a compute intensive operation. | | `product_price_point_id` | `int` | Optional | The product price point currently subscribed to. | | `product_price_point_type` | [`PricePointType`](../../doc/models/price-point-type.md) | Optional | Price point type. We expose the following types:

1. **default**: a price point that is marked as a default price for a certain product.
2. **custom**: a custom price point.
3. **catalog**: a price point that is **not** marked as a default price for a certain product and is **not** a custom one. | | `next_product_price_point_id` | `int` | Optional | If a delayed product change is scheduled, the ID of the product price point that the subscription will be changed to at the next renewal. | diff --git a/doc/models/trial-type.md b/doc/models/trial-type.md new file mode 100644 index 00000000..1298d99b --- /dev/null +++ b/doc/models/trial-type.md @@ -0,0 +1,16 @@ + +# Trial Type + +Indicates how a trial is handled when the trail period ends and there is no credit card on file. For `no_obligation`, the subscription transitions to a Trial Ended state. Maxio will not send any emails or statements. For `payment_expected`, the subscription transitions to a Past Due state. Maxio will send normal dunning emails and statements according to your other settings. + +## Enumeration + +`TrialType` + +## Fields + +| Name | +| --- | +| `NO_OBLIGATION` | +| `PAYMENT_EXPECTED` | + diff --git a/doc/models/update-component.md b/doc/models/update-component.md index 36a44c03..bc079e1d 100644 --- a/doc/models/update-component.md +++ b/doc/models/update-component.md @@ -14,7 +14,7 @@ | `description` | `str` | Optional | The description of the component. | | `accounting_code` | `str` | Optional | - | | `taxable` | `bool` | Optional | Boolean flag describing whether a component is taxable or not. | -| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using the Avalara service to tax based on locale. This attribute has a max length of 10 characters. | +| `tax_code` | `str` | Optional | A string representing the tax code related to the component type. This is especially important when using AvaTax to tax based on locale. This attribute has a max length of 25 characters. | | `item_category` | [`ItemCategory`](../../doc/models/item-category.md) | Optional | One of the following: Business Software, Consumer Software, Digital Services, Physical Goods, Other | | `display_on_hosted_page` | `bool` | Optional | - | | `upgrade_charge` | [`CreditType`](../../doc/models/credit-type.md) | Optional | The type of credit to be created when upgrading/downgrading. Defaults to the component and then site setting if one is not provided.
Available values: `full`, `prorated`, `none`. | diff --git a/doc/models/update-metafield.md b/doc/models/update-metafield.md index afd3930f..3b9fb6d9 100644 --- a/doc/models/update-metafield.md +++ b/doc/models/update-metafield.md @@ -12,8 +12,8 @@ | `current_name` | `str` | Optional | - | | `name` | `str` | Optional | - | | `scope` | [`MetafieldScope`](../../doc/models/metafield-scope.md) | Optional | Warning: When updating a metafield's scope attribute, all scope attributes must be passed. Partially complete scope attributes will override the existing settings. | -| `input_type` | [`MetafieldInput`](../../doc/models/metafield-input.md) | Optional | Indicates how data should be added to the metafield. For example, a text type is just a string, so a given metafield of this type can have any value attached. On the other hand, dropdown and radio have a set of allowed values that can be input, and appear differently on a Public Signup Page. Defaults to 'text' | -| `enum` | `List[str]` | Optional | Only applicable when input_type is radio or dropdown | +| `input_type` | [`MetafieldInput`](../../doc/models/metafield-input.md) | Optional | Indicates the type of metafield. A text metafield allows any string value. Dropdown and radio metafields have a set of values that can be selected. Defaults to 'text'. | +| `enum` | `List[str]` | Optional | Only applicable when input_type is radio or dropdown. | ## Example (as JSON) diff --git a/doc/models/update-payment-profile.md b/doc/models/update-payment-profile.md index 3746c54b..d9760e94 100644 --- a/doc/models/update-payment-profile.md +++ b/doc/models/update-payment-profile.md @@ -20,7 +20,7 @@ | `billing_city` | `str` | Optional | The credit card or bank account billing address city (i.e. “Boston”). This value is merely passed through to the payment gateway. | | `billing_state` | `str` | Optional | The credit card or bank account billing address state (i.e. MA). This value is merely passed through to the payment gateway. This must conform to the [ISO_3166-1](https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) in order to be valid for tax locale purposes. | | `billing_zip` | `str` | Optional | The credit card or bank account billing address zip code (i.e. 12345). This value is merely passed through to the payment gateway. | -| `billing_country` | `str` | Optional | The credit card or bank account billing address country, required in [ISO_3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) format (i.e. “US”). This value is merely passed through to the payment gateway. Some gateways require country codes in a specific format. Please check your gateway’s documentation. If creating an ACH subscription, only US is supported at this time. | +| `billing_country` | `str` | Optional | The credit card or bank account billing address country, required in [ISO_3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) format (i.e. “US”). This value is merely passed through to the payment gateway. Some gateways require country codes in a specific format. Check your gateway’s documentation. If creating an ACH subscription, only US is supported at this time. | | `billing_address_2` | `str` | Optional | Second line of the customer’s billing address i.e. Apt. 100 | ## Example (as JSON) diff --git a/doc/models/update-subscription-component.md b/doc/models/update-subscription-component.md index d892a2ae..d07141da 100644 --- a/doc/models/update-subscription-component.md +++ b/doc/models/update-subscription-component.md @@ -33,7 +33,8 @@ "ending_quantity": 40, "unit_price": 23.26 } - ] + ], + "renew_prepaid_allocation": false } } ``` diff --git a/doc/models/update-subscription.md b/doc/models/update-subscription.md index 5a9bd1fc..4067a5f8 100644 --- a/doc/models/update-subscription.md +++ b/doc/models/update-subscription.md @@ -15,7 +15,7 @@ | `product_change_delayed` | `bool` | Optional | - | | `next_product_id` | `str` | Optional | Set to an empty string to cancel a delayed product change. | | `next_product_price_point_id` | `str` | Optional | - | -| `snap_day` | [SnapDay](../../doc/models/snap-day.md) \| int \| None | Optional | This is a container for one-of cases. | +| `snap_day` | int \| [SnapDay](../../doc/models/snap-day.md) \| None | Optional | This is a container for one-of cases. | | `initial_billing_at` | `datetime` | Optional | (Optional) Set this attribute to a future date/time to update a subscription in the Awaiting Signup Date state, to Awaiting Signup. In the Awaiting Signup state, a subscription behaves like any other. It can be canceled, allocated to, or have its billing date changed. etc. When the `initial_billing_at` date hits, the subscription will transition to the expected state. If the product has a trial, the subscription will enter a trial, otherwise it will go active. Setup fees will be respected either before or after the trial, as configured on the price point. If the payment is due at the initial_billing_at and it fails the subscription will be immediately canceled. You can omit the initial_billing_at date to activate the subscription immediately. See the [subscription import](https://maxio.zendesk.com/hc/en-us/articles/24251489107213-Advanced-Billing-Subscription-Imports#date-format) documentation for more information about Date/Time formats. | | `defer_signup` | `bool` | Optional | (Optional) Set this attribute to true to move the subscription from Awaiting Signup, to Awaiting Signup Date. Use this when you want to update a subscription that has an unknown initial billing date. When the first billing date is known, update a subscription to set the `initial_billing_at` date. The subscription moves to the awaiting signup with a scheduled initial billing date. You can omit the initial_billing_at date to activate the subscription immediately. See [Subscription States](https://maxio-chargify.zendesk.com/hc/en-us/articles/5404222005773-Subscription-States) for more information.

**Default**: `False` | | `next_billing_at` | `datetime` | Optional | - | diff --git a/pyproject.toml b/pyproject.toml index 1f130dd0..a4f195f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta" [project] name = "maxio-advanced-billing-sdk" description = "Ultimate billing and pricing flexibility for B2B SaaS.\nMaxio integrates directly into your product, so you can seamlessly manage your product catalog, bill customers, and collect payments." -version = "7.0.1" +version = "8.0.0" readme = "README.md" keywords = ["Maxio", "Advaced Billing", "Payments", "Subscription"] -dependencies = ["apimatic-core~=0.2.0, >= 0.2.22", "apimatic-core-interfaces~=0.1.0, >= 0.1.5", "apimatic-requests-client-adapter~=0.1.0, >= 0.1.8", "deprecation~=2.1"] +dependencies = ["apimatic-core~=0.2.0, >= 0.2.24", "apimatic-core-interfaces~=0.1.0, >= 0.1.8", "apimatic-requests-client-adapter~=0.1.0, >= 0.1.10", "python-dotenv>=0.21, <2.0", "deprecation~=2.1"] classifiers = [] requires-python = ">=3.7" [[project.authors]] diff --git a/requirements.txt b/requirements.txt index 4c5fcccf..3c39dfbc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ -apimatic-core~=0.2.0, >= 0.2.22 -apimatic-core-interfaces~=0.1.0, >= 0.1.5 -apimatic-requests-client-adapter~=0.1.0, >= 0.1.8 -deprecation~=2.1 \ No newline at end of file +apimatic-core~=0.2.0, >= 0.2.24 +apimatic-core-interfaces~=0.1.0, >= 0.1.8 +apimatic-requests-client-adapter~=0.1.0, >= 0.1.10 +python-dotenv>=0.21, <2.0 +deprecation~=2.1 diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index dce0f1a3..00000000 --- a/test-requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pytest>=7.2.2 diff --git a/tests/data/invoice_assert_cases.py b/tests/data/invoice_assert_cases.py index b5c76f16..9eb04e34 100644 --- a/tests/data/invoice_assert_cases.py +++ b/tests/data/invoice_assert_cases.py @@ -60,18 +60,6 @@ def get_invoice_data( "subtotal_amount": "1800.0", "tax_amount": "0.0", "total_amount": "1530.0", - "seller": { - "name": "Maxio Developer Experience", - "phone": "555 111 222", - "address": { - "city": "San Antonio", - "country": "US", - "line_2": "123/444", - "state": "TX", - "street": "Asdf Street", - "zip": "78015", - }, - }, "shipping_address": { "city": "Ohio", "country": "US",