From 0d4bcfe6201b6c1214c39ffe4e00dcfaeeaa101c Mon Sep 17 00:00:00 2001 From: maxio-sdk Date: Fri, 30 Aug 2024 12:28:17 +0000 Subject: [PATCH] Automated commit message --- README.md | 80 +- .../controllers/advance_invoice_controller.py | 108 +- .../controllers/api_exports_controller.py | 206 +- .../controllers/base_controller.py | 2 +- .../controllers/billing_portal_controller.py | 108 +- .../component_price_points_controller.py | 458 +-- .../controllers/components_controller.py | 216 +- .../controllers/coupons_controller.py | 724 ++-- .../controllers/custom_fields_controller.py | 454 +-- .../controllers/customers_controller.py | 64 +- ...vents_based_billing_segments_controller.py | 258 +- .../controllers/events_controller.py | 180 +- .../controllers/insights_controller.py | 174 +- .../controllers/invoices_controller.py | 558 ++-- .../controllers/offers_controller.py | 162 +- .../payment_profiles_controller.py | 496 +-- .../product_families_controller.py | 86 +- .../product_price_points_controller.py | 442 +-- .../controllers/products_controller.py | 80 +- .../proforma_invoices_controller.py | 352 +- .../sales_commissions_controller.py | 164 +- .../subscription_components_controller.py | 1464 ++++----- ...iption_group_invoice_account_controller.py | 78 +- .../subscription_group_status_controller.py | 64 +- .../subscription_groups_controller.py | 350 +- ...subscription_invoice_account_controller.py | 186 +- .../subscription_notes_controller.py | 172 +- .../subscription_status_controller.py | 512 +-- .../controllers/subscriptions_controller.py | 844 ++--- .../controllers/webhooks_controller.py | 350 +- advancedbilling/exceptions/__init__.py | 16 +- advancedbilling/models/__init__.py | 650 ++-- .../utilities/union_type_lookup.py | 396 +-- doc/controllers/advance-invoice.md | 64 +- doc/controllers/api-exports.md | 138 +- doc/controllers/billing-portal.md | 114 +- doc/controllers/component-price-points.md | 680 ++-- doc/controllers/components.md | 438 +-- doc/controllers/coupons.md | 964 +++--- doc/controllers/custom-fields.md | 474 +-- doc/controllers/customers.md | 34 +- .../events-based-billing-segments.md | 158 +- doc/controllers/events.md | 176 +- doc/controllers/insights.md | 196 +- doc/controllers/invoices.md | 1894 +++++------ doc/controllers/offers.md | 236 +- doc/controllers/payment-profiles.md | 588 ++-- doc/controllers/product-families.md | 90 +- doc/controllers/product-price-points.md | 644 ++-- doc/controllers/products.md | 144 +- doc/controllers/proforma-invoices.md | 234 +- doc/controllers/sales-commissions.md | 196 +- doc/controllers/subscription-components.md | 1488 ++++----- .../subscription-group-invoice-account.md | 110 +- doc/controllers/subscription-group-status.md | 44 +- doc/controllers/subscription-groups.md | 454 +-- .../subscription-invoice-account.md | 154 +- doc/controllers/subscription-notes.md | 170 +- doc/controllers/subscription-status.md | 1194 +++---- doc/controllers/subscriptions.md | 2926 ++++++++--------- doc/controllers/webhooks.md | 366 +-- pyproject.toml | 4 +- requirements.txt | 1 - 63 files changed, 12413 insertions(+), 12414 deletions(-) diff --git a/README.md b/README.md index 4b247672..1c5e77bb 100644 --- a/README.md +++ b/README.md @@ -31,15 +31,15 @@ The package is compatible with Python versions `3 >=3.7, <= 3.11`. Install the package from PyPi using the following pip command: ```python -pip install maxio-advanced-billing-sdk==5.0.0 +pip install maxio-advanced-billing-sdk==5.0.1 ``` You can also view the package at: -https://pypi.python.org/pypi/maxio-advanced-billing-sdk/5.0.0 +https://pypi.python.org/pypi/maxio-advanced-billing-sdk/5.0.1 ## Initialize the API Client -**_Note:_** Documentation for the client can be found [here.](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/client.md) +**_Note:_** Documentation for the client can be found [here.](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/client.md) The following parameters are configurable for the API Client: @@ -56,7 +56,7 @@ 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']** | -| `basic_auth_credentials` | [`BasicAuthCredentials`](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/auth/basic-authentication.md) | The credential object for Basic Authentication | +| `basic_auth_credentials` | [`BasicAuthCredentials`](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/auth/basic-authentication.md) | The credential object for Basic Authentication | The API client can be initialized as follows: @@ -86,46 +86,46 @@ 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/5.0.0/doc/auth/basic-authentication.md) +* [`BasicAuth (Basic Authentication)`](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/auth/basic-authentication.md) ## List of APIs -* [API Exports](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/api-exports.md) -* [Advance Invoice](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/advance-invoice.md) -* [Billing Portal](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/billing-portal.md) -* [Component Price Points](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/component-price-points.md) -* [Custom Fields](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/custom-fields.md) -* [Events-Based Billing Segments](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/events-based-billing-segments.md) -* [Payment Profiles](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/payment-profiles.md) -* [Product Families](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/product-families.md) -* [Product Price Points](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/product-price-points.md) -* [Proforma Invoices](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/proforma-invoices.md) -* [Reason Codes](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/reason-codes.md) -* [Referral Codes](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/referral-codes.md) -* [Sales Commissions](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/sales-commissions.md) -* [Subscription Components](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/subscription-components.md) -* [Subscription Groups](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/subscription-groups.md) -* [Subscription Group Invoice Account](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/subscription-group-invoice-account.md) -* [Subscription Group Status](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/subscription-group-status.md) -* [Subscription Invoice Account](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/subscription-invoice-account.md) -* [Subscription Notes](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/subscription-notes.md) -* [Subscription Products](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/subscription-products.md) -* [Subscription Status](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/subscription-status.md) -* [Coupons](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/coupons.md) -* [Components](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/components.md) -* [Customers](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/customers.md) -* [Events](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/events.md) -* [Insights](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/insights.md) -* [Invoices](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/invoices.md) -* [Offers](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/offers.md) -* [Products](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/products.md) -* [Sites](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/sites.md) -* [Subscriptions](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/subscriptions.md) -* [Webhooks](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/controllers/webhooks.md) +* [API Exports](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/api-exports.md) +* [Advance Invoice](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/advance-invoice.md) +* [Billing Portal](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/billing-portal.md) +* [Component Price Points](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/component-price-points.md) +* [Custom Fields](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/custom-fields.md) +* [Events-Based Billing Segments](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/events-based-billing-segments.md) +* [Payment Profiles](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/payment-profiles.md) +* [Product Families](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/product-families.md) +* [Product Price Points](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/product-price-points.md) +* [Proforma Invoices](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/proforma-invoices.md) +* [Reason Codes](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/reason-codes.md) +* [Referral Codes](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/referral-codes.md) +* [Sales Commissions](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/sales-commissions.md) +* [Subscription Components](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/subscription-components.md) +* [Subscription Groups](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/subscription-groups.md) +* [Subscription Group Invoice Account](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/subscription-group-invoice-account.md) +* [Subscription Group Status](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/subscription-group-status.md) +* [Subscription Invoice Account](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/subscription-invoice-account.md) +* [Subscription Notes](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/subscription-notes.md) +* [Subscription Products](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/subscription-products.md) +* [Subscription Status](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/subscription-status.md) +* [Coupons](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/coupons.md) +* [Components](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/components.md) +* [Customers](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/customers.md) +* [Events](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/events.md) +* [Insights](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/insights.md) +* [Invoices](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/invoices.md) +* [Offers](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/offers.md) +* [Products](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/products.md) +* [Sites](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/sites.md) +* [Subscriptions](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/subscriptions.md) +* [Webhooks](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/controllers/webhooks.md) ## Classes Documentation -* [Utility Classes](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/utility-classes.md) -* [HttpResponse](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/http-response.md) -* [HttpRequest](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.0/doc/http-request.md) +* [Utility Classes](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/utility-classes.md) +* [HttpResponse](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/http-response.md) +* [HttpRequest](https://www.github.com/maxio-com/ab-python-sdk/tree/5.0.1/doc/http-request.md) diff --git a/advancedbilling/controllers/advance_invoice_controller.py b/advancedbilling/controllers/advance_invoice_controller.py index d9e45cc6..d53e9f75 100644 --- a/advancedbilling/controllers/advance_invoice_controller.py +++ b/advancedbilling/controllers/advance_invoice_controller.py @@ -26,6 +26,60 @@ class AdvanceInvoiceController(BaseController): def __init__(self, config): super(AdvanceInvoiceController, self).__init__(config) + def void_advance_invoice(self, + subscription_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/advance_invoice/void.json. + + 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]($m/Invoice). + + Args: + subscription_id (int): The Chargify id of the subscription + body (VoidInvoiceRequest, optional): TODO: type description here. + + Returns: + Invoice: Response from the API. Created + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/advance_invoice/void.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(Invoice.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + ).execute() + def issue_advance_invoice(self, subscription_id, body=None): @@ -133,57 +187,3 @@ def read_advance_invoice(self, .deserialize_into(Invoice.from_dictionary) .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) ).execute() - - def void_advance_invoice(self, - subscription_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/advance_invoice/void.json. - - 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]($m/Invoice). - - Args: - subscription_id (int): The Chargify id of the subscription - body (VoidInvoiceRequest, optional): TODO: type description here. - - Returns: - Invoice: Response from the API. Created - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/advance_invoice/void.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(Invoice.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - ).execute() diff --git a/advancedbilling/controllers/api_exports_controller.py b/advancedbilling/controllers/api_exports_controller.py index bb8d619e..e37749f8 100644 --- a/advancedbilling/controllers/api_exports_controller.py +++ b/advancedbilling/controllers/api_exports_controller.py @@ -15,10 +15,10 @@ from apimatic_core.types.parameter import Parameter from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.authentication.multiple.single_auth import Single -from advancedbilling.models.proforma_invoice import ProformaInvoice from advancedbilling.models.invoice import Invoice from advancedbilling.models.subscription import Subscription from advancedbilling.models.batch_job_response import BatchJobResponse +from advancedbilling.models.proforma_invoice import ProformaInvoice from advancedbilling.exceptions.api_exception import APIException from advancedbilling.exceptions.single_error_response_exception import SingleErrorResponseException @@ -29,76 +29,6 @@ class APIExportsController(BaseController): def __init__(self, config): super(APIExportsController, self).__init__(config) - def list_exported_proforma_invoices(self, - options=dict()): - """Does a GET request to /api_exports/proforma_invoices/{batch_id}/rows.json. - - This API returns an array of exported proforma invoices for a provided - `batch_id`. Pay close attention to pagination in order to control - responses from the server. - Example: `GET - https://{subdomain}.chargify.com/api_exports/proforma_invoices/123/rows - ?per_page=10000&page=1`. - - Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - batch_id -- str -- Id of a Batch Job. - per_page -- int -- This parameter indicates how many - records to fetch in each request. Default value is - 100. The maximum allowed values is 10000; any - per_page value over 10000 will be changed to 10000. - 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 - 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`. - - Returns: - List[ProformaInvoice]: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/api_exports/proforma_invoices/{batch_id}/rows.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('batch_id') - .value(options.get('batch_id', None)) - .is_required(True) - .should_encode(True)) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) - .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(ProformaInvoice.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - ).execute() - def list_exported_invoices(self, options=dict()): """Does a GET request to /api_exports/invoices/{batch_id}/rows.json. @@ -273,13 +203,17 @@ def export_proforma_invoices(self): .local_error_template('409', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SingleErrorResponseException) ).execute() - def export_invoices(self): - """Does a POST request to /api_exports/invoices.json. + def read_proforma_invoices_export(self, + batch_id): + """Does a GET request to /api_exports/proforma_invoices/{batch_id}.json. - This API creates an invoices export and returns a batchjob object. + This API returns a batchjob object for proforma invoices export. + + Args: + batch_id (str): Id of a Batch Job. Returns: - BatchJobResponse: Response from the API. Created + BatchJobResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -291,8 +225,13 @@ def export_invoices(self): return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/api_exports/invoices.json') - .http_method(HttpMethodEnum.POST) + .path('/api_exports/proforma_invoices/{batch_id}.json') + .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('batch_id') + .value(batch_id) + .is_required(True) + .should_encode(True)) .header_param(Parameter() .key('accept') .value('application/json')) @@ -302,17 +241,43 @@ def export_invoices(self): .deserializer(APIHelper.json_deserialize) .deserialize_into(BatchJobResponse.from_dictionary) .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('409', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SingleErrorResponseException) ).execute() - def export_subscriptions(self): - """Does a POST request to /api_exports/subscriptions.json. + def list_exported_proforma_invoices(self, + options=dict()): + """Does a GET request to /api_exports/proforma_invoices/{batch_id}/rows.json. - This API creates a subscriptions export and returns a batchjob - object. + This API returns an array of exported proforma invoices for a provided + `batch_id`. Pay close attention to pagination in order to control + responses from the server. + Example: `GET + https://{subdomain}.chargify.com/api_exports/proforma_invoices/123/rows + ?per_page=10000&page=1`. + + Args: + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + batch_id -- str -- Id of a Batch Job. + per_page -- int -- This parameter indicates how many + records to fetch in each request. Default value is + 100. The maximum allowed values is 10000; any + per_page value over 10000 will be changed to 10000. + 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 + 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`. Returns: - BatchJobResponse: Response from the API. Created + List[ProformaInvoice]: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -324,8 +289,19 @@ def export_subscriptions(self): return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/api_exports/subscriptions.json') - .http_method(HttpMethodEnum.POST) + .path('/api_exports/proforma_invoices/{batch_id}/rows.json') + .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('batch_id') + .value(options.get('batch_id', None)) + .is_required(True) + .should_encode(True)) + .query_param(Parameter() + .key('per_page') + .value(options.get('per_page', None))) + .query_param(Parameter() + .key('page') + .value(options.get('page', None))) .header_param(Parameter() .key('accept') .value('application/json')) @@ -333,21 +309,18 @@ def export_subscriptions(self): ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(BatchJobResponse.from_dictionary) - .local_error_template('409', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SingleErrorResponseException) + .deserialize_into(ProformaInvoice.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) ).execute() - def read_proforma_invoices_export(self, - batch_id): - """Does a GET request to /api_exports/proforma_invoices/{batch_id}.json. - - This API returns a batchjob object for proforma invoices export. + def export_subscriptions(self): + """Does a POST request to /api_exports/subscriptions.json. - Args: - batch_id (str): Id of a Batch Job. + This API creates a subscriptions export and returns a batchjob + object. Returns: - BatchJobResponse: Response from the API. OK + BatchJobResponse: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -359,13 +332,8 @@ def read_proforma_invoices_export(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/api_exports/proforma_invoices/{batch_id}.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('batch_id') - .value(batch_id) - .is_required(True) - .should_encode(True)) + .path('/api_exports/subscriptions.json') + .http_method(HttpMethodEnum.POST) .header_param(Parameter() .key('accept') .value('application/json')) @@ -374,7 +342,7 @@ def read_proforma_invoices_export(self, ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(BatchJobResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('409', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SingleErrorResponseException) ).execute() def read_invoices_export(self, @@ -456,3 +424,35 @@ def read_subscriptions_export(self, .deserialize_into(BatchJobResponse.from_dictionary) .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) ).execute() + + def export_invoices(self): + """Does a POST request to /api_exports/invoices.json. + + This API creates an invoices export and returns a batchjob object. + + Returns: + BatchJobResponse: Response from the API. Created + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/api_exports/invoices.json') + .http_method(HttpMethodEnum.POST) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(BatchJobResponse.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('409', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SingleErrorResponseException) + ).execute() diff --git a/advancedbilling/controllers/base_controller.py b/advancedbilling/controllers/base_controller.py index 2ae3026f..a7cf39d3 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:5.0.0 on OS {os-info}' + return 'AB SDK Python:5.0.1 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 fcf06917..4c330535 100644 --- a/advancedbilling/controllers/billing_portal_controller.py +++ b/advancedbilling/controllers/billing_portal_controller.py @@ -16,12 +16,12 @@ from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.authentication.multiple.single_auth import Single from advancedbilling.models.customer_response import CustomerResponse -from advancedbilling.models.portal_management_link import PortalManagementLink from advancedbilling.models.resent_invitation import ResentInvitation from advancedbilling.models.revoked_invitation import RevokedInvitation +from advancedbilling.models.portal_management_link import PortalManagementLink from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException -from advancedbilling.exceptions.too_many_management_link_requests_error_exception import TooManyManagementLinkRequestsErrorException from advancedbilling.exceptions.api_exception import APIException +from advancedbilling.exceptions.too_many_management_link_requests_error_exception import TooManyManagementLinkRequestsErrorException class BillingPortalController(BaseController): @@ -104,58 +104,6 @@ def enable_billing_portal_for_customer(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def read_billing_portal_link(self, - customer_id): - """Does a GET request to /portal/customers/{customer_id}/management_link.json. - - This method will provide to the API user the exact URL required for a - subscriber to access the Billing Portal. - ## Rules for Management Link API - + When retrieving a management URL, multiple requests for the same - customer in a short period will return the **same** URL - + We will not generate a new URL for 15 days - + You must cache and remember this URL if you are going to need it - again within 15 days - + Only request a new URL after the `new_link_available_at` date - + You are limited to 15 requests for the same URL. If you make more - than 15 requests before `new_link_available_at`, you will be blocked - from further Management URL requests (with a response code `429`) - - Args: - customer_id (int): The Chargify id of the customer - - Returns: - PortalManagementLink: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/portal/customers/{customer_id}/management_link.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('customer_id') - .value(customer_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(PortalManagementLink.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) - .local_error_template('429', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', TooManyManagementLinkRequestsErrorException) - ).execute() - def resend_billing_portal_invitation(self, customer_id): """Does a POST request to /portal/customers/{customer_id}/invitations/invite.json. @@ -252,3 +200,55 @@ def revoke_billing_portal_access(self, .deserializer(APIHelper.json_deserialize) .deserialize_into(RevokedInvitation.from_dictionary) ).execute() + + def read_billing_portal_link(self, + customer_id): + """Does a GET request to /portal/customers/{customer_id}/management_link.json. + + This method will provide to the API user the exact URL required for a + subscriber to access the Billing Portal. + ## Rules for Management Link API + + When retrieving a management URL, multiple requests for the same + customer in a short period will return the **same** URL + + We will not generate a new URL for 15 days + + You must cache and remember this URL if you are going to need it + again within 15 days + + Only request a new URL after the `new_link_available_at` date + + You are limited to 15 requests for the same URL. If you make more + than 15 requests before `new_link_available_at`, you will be blocked + from further Management URL requests (with a response code `429`) + + Args: + customer_id (int): The Chargify id of the customer + + Returns: + PortalManagementLink: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/portal/customers/{customer_id}/management_link.json') + .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('customer_id') + .value(customer_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(PortalManagementLink.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + .local_error_template('429', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', TooManyManagementLinkRequestsErrorException) + ).execute() diff --git a/advancedbilling/controllers/component_price_points_controller.py b/advancedbilling/controllers/component_price_points_controller.py index d9a51986..5ddf3dd7 100644 --- a/advancedbilling/controllers/component_price_points_controller.py +++ b/advancedbilling/controllers/component_price_points_controller.py @@ -19,9 +19,9 @@ from apimatic_core.authentication.multiple.single_auth import Single from advancedbilling.models.component_response import ComponentResponse from advancedbilling.models.component_price_point_response import ComponentPricePointResponse -from advancedbilling.models.component_price_points_response import ComponentPricePointsResponse from advancedbilling.models.component_currency_prices_response import ComponentCurrencyPricesResponse from advancedbilling.models.list_components_price_points_response import ListComponentsPricePointsResponse +from advancedbilling.models.component_price_points_response import ComponentPricePointsResponse from advancedbilling.exceptions.error_array_map_response_exception import ErrorArrayMapResponseException from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException @@ -136,143 +136,6 @@ def create_component_price_point(self, .deserialize_into(ComponentPricePointResponse.from_dictionary) ).execute() - def list_component_price_points(self, - options=dict()): - """Does a GET request to /components/{component_id}/price_points.json. - - Use this endpoint to read current price points that are associated - with a component. - You may specify the component by using either the numeric id or the - `handle:gold` syntax. - When fetching a component's price points, if you have defined multiple - currencies at the site level, you can optionally pass the - `?currency_prices=true` query param to include an array of currency - price data in the response. - If the price point 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 - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - component_id -- int -- The Advanced Billing id of the - component - currency_prices -- bool -- Include an array of currency - price data - 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 - 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`. - per_page -- int -- 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`. - filter_type -- List[PricePointType] -- Use in query: - `filter[type]=catalog,default`. - - Returns: - ComponentPricePointsResponse: Response from the API. Created - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/components/{component_id}/price_points.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('component_id') - .value(options.get('component_id', None)) - .is_required(True) - .should_encode(True)) - .query_param(Parameter() - .key('currency_prices') - .value(options.get('currency_prices', None))) - .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) - .query_param(Parameter() - .key('filter[type]') - .value(options.get('filter_type', None))) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .array_serialization_format(SerializationFormats.CSV) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(ComponentPricePointsResponse.from_dictionary) - ).execute() - - def bulk_create_component_price_points(self, - component_id, - body=None): - """Does a POST request to /components/{component_id}/price_points/bulk.json. - - Use this endpoint to create multiple component price points in one - request. - - Args: - component_id (str): The Advanced Billing id of the component for - which you want to fetch price points. - body (CreateComponentPricePointsRequest, optional): TODO: type - description here. - - Returns: - ComponentPricePointsResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/components/{component_id}/price_points/bulk.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('component_id') - .value(component_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(ComponentPricePointsResponse.from_dictionary) - ).execute() - def update_component_price_point(self, component_id, price_point_id, @@ -401,27 +264,23 @@ def read_component_price_point(self, .deserialize_into(ComponentPricePointResponse.from_dictionary) ).execute() - def archive_component_price_point(self, - component_id, - price_point_id): - """Does a DELETE request to /components/{component_id}/price_points/{price_point_id}.json. + def update_currency_prices(self, + price_point_id, + body=None): + """Does a PUT request to /price_points/{price_point_id}/currency_prices.json. - A price point can be archived at any time. Subscriptions using a price - point that has been archived will continue using it until they're - moved to another price point. + This endpoint allows you to update currency prices for a given + currency that has been defined on the site level in your settings. + Note: Currency Prices are not able to be updated for custom price + points. Args: - component_id (int | str): The id or handle of the component. When - using the handle, it must be prefixed with `handle:`. Example: - `123` for an integer ID, or `handle:example-product-handle` - for a string handle. - price_point_id (int | str): The id or handle of the price point. - When using the handle, it must be prefixed with `handle:`. - Example: `123` for an integer ID, or - `handle:example-price_point-handle` for a string handle. + price_point_id (int): The Advanced Billing id of the price point + body (UpdateCurrencyPricesRequest, optional): TODO: type + description here. Returns: - ComponentPricePointResponse: Response from the API. OK + ComponentCurrencyPricesResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -433,42 +292,48 @@ def archive_component_price_point(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/components/{component_id}/price_points/{price_point_id}.json') - .http_method(HttpMethodEnum.DELETE) - .template_param(Parameter() - .key('component_id') - .value(component_id) - .is_required(True) - .should_encode(True) - .validator(lambda value: UnionTypeLookUp.get('ArchiveComponentPricePointComponentId').validate(value))) + .path('/price_points/{price_point_id}/currency_prices.json') + .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('price_point_id') .value(price_point_id) .is_required(True) - .should_encode(True) - .validator(lambda value: UnionTypeLookUp.get('ArchiveComponentPricePointPricePointId').validate(value))) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ComponentPricePointResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + .deserialize_into(ComponentCurrencyPricesResponse.from_dictionary) + .local_error('422', 'Unprocessable Entity (WebDAV)', ErrorArrayMapResponseException) ).execute() - def unarchive_component_price_point(self, - component_id, - price_point_id): - """Does a PUT request to /components/{component_id}/price_points/{price_point_id}/unarchive.json. + def archive_component_price_point(self, + component_id, + price_point_id): + """Does a DELETE request to /components/{component_id}/price_points/{price_point_id}.json. - Use this endpoint to unarchive a component price point. + A price point can be archived at any time. Subscriptions using a price + point that has been archived will continue using it until they're + moved to another price point. Args: - component_id (int): The Advanced Billing id of the component to - which the price point belongs - price_point_id (int): The Advanced Billing id of the price point + component_id (int | str): The id or handle of the component. When + using the handle, it must be prefixed with `handle:`. Example: + `123` for an integer ID, or `handle:example-product-handle` + for a string handle. + price_point_id (int | str): The id or handle of the price point. + When using the handle, it must be prefixed with `handle:`. + Example: `123` for an integer ID, or + `handle:example-price_point-handle` for a string handle. Returns: ComponentPricePointResponse: Response from the API. OK @@ -483,18 +348,20 @@ def unarchive_component_price_point(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/components/{component_id}/price_points/{price_point_id}/unarchive.json') - .http_method(HttpMethodEnum.PUT) + .path('/components/{component_id}/price_points/{price_point_id}.json') + .http_method(HttpMethodEnum.DELETE) .template_param(Parameter() .key('component_id') .value(component_id) .is_required(True) - .should_encode(True)) + .should_encode(True) + .validator(lambda value: UnionTypeLookUp.get('ArchiveComponentPricePointComponentId').validate(value))) .template_param(Parameter() .key('price_point_id') .value(price_point_id) .is_required(True) - .should_encode(True)) + .should_encode(True) + .validator(lambda value: UnionTypeLookUp.get('ArchiveComponentPricePointPricePointId').validate(value))) .header_param(Parameter() .key('accept') .value('application/json')) @@ -503,6 +370,7 @@ def unarchive_component_price_point(self, ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(ComponentPricePointResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() def create_currency_prices(self, @@ -561,23 +429,45 @@ def create_currency_prices(self, .local_error('422', 'Unprocessable Entity (WebDAV)', ErrorArrayMapResponseException) ).execute() - def update_currency_prices(self, - price_point_id, - body=None): - """Does a PUT request to /price_points/{price_point_id}/currency_prices.json. + def list_all_component_price_points(self, + options=dict()): + """Does a GET request to /components_price_points.json. - This endpoint allows you to update currency prices for a given - currency that has been defined on the site level in your settings. - Note: Currency Prices are not able to be updated for custom price - points. + This method allows to retrieve a list of Components Price Points + belonging to a Site. Args: - price_point_id (int): The Advanced Billing id of the price point - body (UpdateCurrencyPricesRequest, optional): TODO: type - description here. + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + include -- ListComponentsPricePointsInclude -- Allows + including additional data in the response. Use in + query: `include=currency_prices`. + 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 + 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`. + per_page -- int -- 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`. + direction -- SortingDirection -- Controls the order in + which results are returned. Use in query + `direction=asc`. + filter -- ListPricePointsFilter -- Filter to use for List + PricePoints operations Returns: - ComponentCurrencyPricesResponse: Response from the API. OK + ListComponentsPricePointsResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -589,36 +479,50 @@ def update_currency_prices(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/price_points/{price_point_id}/currency_prices.json') - .http_method(HttpMethodEnum.PUT) - .template_param(Parameter() - .key('price_point_id') - .value(price_point_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) + .path('/components_price_points.json') + .http_method(HttpMethodEnum.GET) + .query_param(Parameter() + .key('include') + .value(options.get('include', None))) + .query_param(Parameter() + .key('page') + .value(options.get('page', None))) + .query_param(Parameter() + .key('per_page') + .value(options.get('per_page', None))) + .query_param(Parameter() + .key('direction') + .value(options.get('direction', None))) + .query_param(Parameter() + .key('filter') + .value(options.get('filter', None))) .header_param(Parameter() .key('accept') .value('application/json')) - .body_serializer(APIHelper.json_serialize) + .array_serialization_format(SerializationFormats.CSV) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ComponentCurrencyPricesResponse.from_dictionary) - .local_error('422', 'Unprocessable Entity (WebDAV)', ErrorArrayMapResponseException) + .deserialize_into(ListComponentsPricePointsResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def list_all_component_price_points(self, - options=dict()): - """Does a GET request to /components_price_points.json. + def list_component_price_points(self, + options=dict()): + """Does a GET request to /components/{component_id}/price_points.json. - This method allows to retrieve a list of Components Price Points - belonging to a Site. + Use this endpoint to read current price points that are associated + with a component. + You may specify the component by using either the numeric id or the + `handle:gold` syntax. + When fetching a component's price points, if you have defined multiple + currencies at the site level, you can optionally pass the + `?currency_prices=true` query param to include an array of currency + price data in the response. + If the price point 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 @@ -627,9 +531,10 @@ def list_all_component_price_points(self, being the key and their desired values being the value. A list of parameters that can be used are:: - include -- ListComponentsPricePointsInclude -- Allows - including additional data in the response. Use in - query: `include=currency_prices`. + component_id -- int -- The Advanced Billing id of the + component + currency_prices -- bool -- Include an array of currency + price data 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 @@ -644,14 +549,11 @@ def list_all_component_price_points(self, The maximum allowed values is 200; any per_page value over 200 will be changed to 200. Use in query `per_page=200`. - direction -- SortingDirection -- Controls the order in - which results are returned. Use in query - `direction=asc`. - filter -- ListPricePointsFilter -- Filter to use for List - PricePoints operations + filter_type -- List[PricePointType] -- Use in query: + `filter[type]=catalog,default`. Returns: - ListComponentsPricePointsResponse: Response from the API. OK + ComponentPricePointsResponse: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -663,11 +565,16 @@ def list_all_component_price_points(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/components_price_points.json') + .path('/components/{component_id}/price_points.json') .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('component_id') + .value(options.get('component_id', None)) + .is_required(True) + .should_encode(True)) .query_param(Parameter() - .key('include') - .value(options.get('include', None))) + .key('currency_prices') + .value(options.get('currency_prices', None))) .query_param(Parameter() .key('page') .value(options.get('page', None))) @@ -675,11 +582,8 @@ def list_all_component_price_points(self, .key('per_page') .value(options.get('per_page', None))) .query_param(Parameter() - .key('direction') - .value(options.get('direction', None))) - .query_param(Parameter() - .key('filter') - .value(options.get('filter', None))) + .key('filter[type]') + .value(options.get('filter_type', None))) .header_param(Parameter() .key('accept') .value('application/json')) @@ -688,6 +592,102 @@ def list_all_component_price_points(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ListComponentsPricePointsResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + .deserialize_into(ComponentPricePointsResponse.from_dictionary) + ).execute() + + def bulk_create_component_price_points(self, + component_id, + body=None): + """Does a POST request to /components/{component_id}/price_points/bulk.json. + + Use this endpoint to create multiple component price points in one + request. + + Args: + component_id (str): The Advanced Billing id of the component for + which you want to fetch price points. + body (CreateComponentPricePointsRequest, optional): TODO: type + description here. + + Returns: + ComponentPricePointsResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/components/{component_id}/price_points/bulk.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('component_id') + .value(component_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(ComponentPricePointsResponse.from_dictionary) + ).execute() + + def unarchive_component_price_point(self, + component_id, + price_point_id): + """Does a PUT request to /components/{component_id}/price_points/{price_point_id}/unarchive.json. + + Use this endpoint to unarchive a component price point. + + Args: + component_id (int): The Advanced Billing id of the component to + which the price point belongs + price_point_id (int): The Advanced Billing id of the price point + + Returns: + ComponentPricePointResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/components/{component_id}/price_points/{price_point_id}/unarchive.json') + .http_method(HttpMethodEnum.PUT) + .template_param(Parameter() + .key('component_id') + .value(component_id) + .is_required(True) + .should_encode(True)) + .template_param(Parameter() + .key('price_point_id') + .value(price_point_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(ComponentPricePointResponse.from_dictionary) ).execute() diff --git a/advancedbilling/controllers/components_controller.py b/advancedbilling/controllers/components_controller.py index 775d6305..4e7e779b 100644 --- a/advancedbilling/controllers/components_controller.py +++ b/advancedbilling/controllers/components_controller.py @@ -28,22 +28,21 @@ class ComponentsController(BaseController): def __init__(self, config): super(ComponentsController, self).__init__(config) - def create_metered_component(self, - product_family_id, - body=None): - """Does a POST request to /product_families/{product_family_id}/metered_components.json. + def create_prepaid_usage_component(self, + product_family_id, + body=None): + """Does a POST request to /product_families/{product_family_id}/prepaid_usage_components.json. This request will create a component definition of kind - **metered_component** under the specified product family. Metered - component can then be added and “allocated” for a subscription. - Metered components are used to bill for any type of unit that resets - to 0 at the end of the billing period (think daily Google Adwords - clicks or monthly cell phone minutes). This is most commonly - associated with usage-based billing and many other pricing schemes. - 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. + **prepaid_usage_component** under the specified product family. + Prepaid component can then be added and “allocated” for a + subscription. + 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-Compo nents-Overview). @@ -51,7 +50,7 @@ def create_metered_component(self, Args: product_family_id (str): Either the product family's id or its handle prefixed with `handle:` - body (CreateMeteredComponent, optional): TODO: type description + body (CreatePrepaidComponent, optional): TODO: type description here. Returns: @@ -67,7 +66,7 @@ def create_metered_component(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/product_families/{product_family_id}/metered_components.json') + .path('/product_families/{product_family_id}/prepaid_usage_components.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('product_family_id') @@ -221,69 +220,6 @@ def create_on_off_component(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def create_prepaid_usage_component(self, - product_family_id, - body=None): - """Does a POST request to /product_families/{product_family_id}/prepaid_usage_components.json. - - This request will create a component definition of kind - **prepaid_usage_component** under the specified product family. - Prepaid component can then be added and “allocated” for a - subscription. - 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-Compo - nents-Overview). - - Args: - product_family_id (str): Either the product family's id or its - handle prefixed with `handle:` - body (CreatePrepaidComponent, optional): TODO: type description - here. - - Returns: - ComponentResponse: Response from the API. Created - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/product_families/{product_family_id}/prepaid_usage_components.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('product_family_id') - .value(product_family_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(ComponentResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) - ).execute() - def create_event_based_component(self, product_family_id, body=None): @@ -389,6 +325,70 @@ def find_component(self, .deserialize_into(ComponentResponse.from_dictionary) ).execute() + def create_metered_component(self, + product_family_id, + body=None): + """Does a POST request to /product_families/{product_family_id}/metered_components.json. + + This request will create a component definition of kind + **metered_component** under the specified product family. Metered + component can then be added and “allocated” for a subscription. + Metered components are used to bill for any type of unit that resets + to 0 at the end of the billing period (think daily Google Adwords + clicks or monthly cell phone minutes). This is most commonly + associated with usage-based billing and many other pricing schemes. + 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-Compo + nents-Overview). + + Args: + product_family_id (str): Either the product family's id or its + handle prefixed with `handle:` + body (CreateMeteredComponent, optional): TODO: type description + here. + + Returns: + ComponentResponse: Response from the API. Created + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/product_families/{product_family_id}/metered_components.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('product_family_id') + .value(product_family_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(ComponentResponse.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + ).execute() + def read_component(self, product_family_id, component_id): @@ -441,15 +441,14 @@ def read_component(self, .deserialize_into(ComponentResponse.from_dictionary) ).execute() - def update_product_family_component(self, - product_family_id, - component_id, - body=None): - """Does a PUT request to /product_families/{product_family_id}/components/{component_id}.json. + def archive_component(self, + product_family_id, + component_id): + """Does a DELETE request to /product_families/{product_family_id}/components/{component_id}.json. - This request will update a component from a specific product family. - You may read the component by either the component's id or handle. - When using the handle, it must be prefixed with `handle:`. + Sending a DELETE request to this endpoint will archive the component. + All current subscribers will be unffected; their subscription/purchase + will continue to be charged as usual. Args: product_family_id (int): The Advanced Billing id of the product @@ -457,11 +456,9 @@ def update_product_family_component(self, component_id (str): Either the Advanced Billing id of the component or the handle for the component prefixed with `handle:` - body (UpdateComponentRequest, optional): TODO: type description - here. Returns: - ComponentResponse: Response from the API. OK + Component: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -474,7 +471,7 @@ def update_product_family_component(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/product_families/{product_family_id}/components/{component_id}.json') - .http_method(HttpMethodEnum.PUT) + .http_method(HttpMethodEnum.DELETE) .template_param(Parameter() .key('product_family_id') .value(product_family_id) @@ -485,31 +482,26 @@ def update_product_family_component(self, .value(component_id) .is_required(True) .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ComponentResponse.from_dictionary) + .deserialize_into(Component.from_dictionary) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def archive_component(self, - product_family_id, - component_id): - """Does a DELETE request to /product_families/{product_family_id}/components/{component_id}.json. + def update_product_family_component(self, + product_family_id, + component_id, + body=None): + """Does a PUT request to /product_families/{product_family_id}/components/{component_id}.json. - Sending a DELETE request to this endpoint will archive the component. - All current subscribers will be unffected; their subscription/purchase - will continue to be charged as usual. + This request will update a component from a specific product family. + You may read the component by either the component's id or handle. + When using the handle, it must be prefixed with `handle:`. Args: product_family_id (int): The Advanced Billing id of the product @@ -517,9 +509,11 @@ def archive_component(self, component_id (str): Either the Advanced Billing id of the component or the handle for the component prefixed with `handle:` + body (UpdateComponentRequest, optional): TODO: type description + here. Returns: - Component: Response from the API. OK + ComponentResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -532,7 +526,7 @@ def archive_component(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/product_families/{product_family_id}/components/{component_id}.json') - .http_method(HttpMethodEnum.DELETE) + .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('product_family_id') .value(product_family_id) @@ -543,14 +537,20 @@ def archive_component(self, .value(component_id) .is_required(True) .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(Component.from_dictionary) + .deserialize_into(ComponentResponse.from_dictionary) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() diff --git a/advancedbilling/controllers/coupons_controller.py b/advancedbilling/controllers/coupons_controller.py index 96df13b7..4dd646fe 100644 --- a/advancedbilling/controllers/coupons_controller.py +++ b/advancedbilling/controllers/coupons_controller.py @@ -17,13 +17,13 @@ from apimatic_core.types.array_serialization_format import SerializationFormats from apimatic_core.authentication.multiple.single_auth import Single from advancedbilling.models.coupon_response import CouponResponse -from advancedbilling.models.coupon_usage import CouponUsage from advancedbilling.models.coupon_currency_response import CouponCurrencyResponse from advancedbilling.models.coupon_subcodes_response import CouponSubcodesResponse from advancedbilling.models.coupon_subcodes import CouponSubcodes -from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException -from advancedbilling.exceptions.single_string_error_response_exception import SingleStringErrorResponseException +from advancedbilling.models.coupon_usage import CouponUsage from advancedbilling.exceptions.api_exception import APIException +from advancedbilling.exceptions.single_string_error_response_exception import SingleStringErrorResponseException +from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException class CouponsController(BaseController): @@ -32,40 +32,48 @@ class CouponsController(BaseController): def __init__(self, config): super(CouponsController, self).__init__(config) - def create_coupon(self, - product_family_id, - body=None): - """Does a POST request to /product_families/{product_family_id}/coupons.json. + def list_coupons_for_product_family(self, + options=dict()): + """Does a GET request to /product_families/{product_family_id}/coupons.json. - ## 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-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 - [here](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupo - ns-and-Subscriptions). - ## Create Coupon - This request will create a coupon, based on the provided information. - When creating a coupon, you must specify a product family using the - `product_family_id`. If no `product_family_id` is passed, the first - product family available is used. You will also need to formulate your - URL to cite the Product Family ID in your request. - You can restrict a coupon to only apply to specific products / - components by optionally passing in hashes of `restricted_products` - and/or `restricted_components` in the format: - `{ "": boolean_value }` + 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: - product_family_id (int): The Advanced Billing id of the product - family to which the coupon belongs - body (CreateOrUpdateCoupon, optional): TODO: type description - here. + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + product_family_id -- int -- The Advanced Billing id of the + product family to which the coupon belongs + 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 + 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`. + per_page -- int -- This parameter indicates how many + records to fetch in each request. Default value is 30. + The maximum allowed values is 200; any per_page value + over 200 will be changed to 200. Use in query + `per_page=200`. + filter -- ListCouponsFilter -- Filter to use for List + Coupons operations + currency_prices -- bool -- When fetching coupons, if you + have defined multiple currencies at the site level, + you can optionally pass the `?currency_prices=true` + query param to include an array of currency price data + in the response. Use in query `currency_prices=true`. Returns: - CouponResponse: Response from the API. Created + List[CouponResponse]: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -78,34 +86,40 @@ def create_coupon(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/product_families/{product_family_id}/coupons.json') - .http_method(HttpMethodEnum.POST) + .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('product_family_id') - .value(product_family_id) + .value(options.get('product_family_id', None)) .is_required(True) .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) + .query_param(Parameter() + .key('page') + .value(options.get('page', None))) + .query_param(Parameter() + .key('per_page') + .value(options.get('per_page', None))) + .query_param(Parameter() + .key('filter') + .value(options.get('filter', None))) + .query_param(Parameter() + .key('currency_prices') + .value(options.get('currency_prices', None))) .header_param(Parameter() .key('accept') .value('application/json')) - .body_serializer(APIHelper.json_serialize) + .array_serialization_format(SerializationFormats.CSV) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(CouponResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def list_coupons_for_product_family(self, - options=dict()): - """Does a GET request to /product_families/{product_family_id}/coupons.json. + def list_coupons(self, + options=dict()): + """Does a GET request to /coupons.json. - List coupons for a specific Product Family in a Site. + 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. @@ -117,8 +131,6 @@ def list_coupons_for_product_family(self, being the key and their desired values being the value. A list of parameters that can be used are:: - product_family_id -- int -- The Advanced Billing id of the - product family to which the coupon belongs 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 @@ -154,13 +166,8 @@ def list_coupons_for_product_family(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/product_families/{product_family_id}/coupons.json') + .path('/coupons.json') .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('product_family_id') - .value(options.get('product_family_id', None)) - .is_required(True) - .should_encode(True)) .query_param(Parameter() .key('page') .value(options.get('page', None))) @@ -184,26 +191,27 @@ def list_coupons_for_product_family(self, .deserialize_into(CouponResponse.from_dictionary) ).execute() - def find_coupon(self, - product_family_id=None, - code=None): - """Does a GET request to /coupons/find.json. + def create_or_update_coupon_currency_prices(self, + coupon_id, + body=None): + """Does a PUT request to /coupons/{coupon_id}/currency_prices.json. - You can search for a coupon via the API with the find method. By - passing a code parameter, the find will attempt to locate a coupon - that matches that code. If no coupon is found, a 404 is returned. - If you have more than one product family and if the coupon you are - trying to find does not belong to the default product family in your - site, then you will need to specify (either in the url or as a query - string param) the product family id. + This endpoint allows you to create and/or update currency prices for + an existing coupon. Multiple prices can be created or updated in a + single request but each of the currencies must be defined on the site + level already and the coupon must be an amount-based coupon, not + percentage. + Currency pricing for coupons must mirror the setup of the primary + coupon pricing - if the primary coupon is percentage based, you will + not be able to define pricing in non-primary currencies. Args: - product_family_id (int, optional): The Advanced Billing id of the - product family to which the coupon belongs - code (str, optional): The code of the coupon + coupon_id (int): The Advanced Billing id of the coupon + body (CouponCurrencyRequest, optional): TODO: type description + here. Returns: - CouponResponse: Response from the API. OK + CouponCurrencyResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -215,48 +223,82 @@ def find_coupon(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/coupons/find.json') - .http_method(HttpMethodEnum.GET) - .query_param(Parameter() - .key('product_family_id') - .value(product_family_id)) - .query_param(Parameter() - .key('code') - .value(code)) + .path('/coupons/{coupon_id}/currency_prices.json') + .http_method(HttpMethodEnum.PUT) + .template_param(Parameter() + .key('coupon_id') + .value(coupon_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(CouponResponse.from_dictionary) + .deserialize_into(CouponCurrencyResponse.from_dictionary) ).execute() - def read_coupon(self, - product_family_id, - coupon_id): - """Does a GET request to /product_families/{product_family_id}/coupons/{coupon_id}.json. - - You can retrieve the Coupon via the API with the Show method. You must - identify the Coupon in this call by the ID parameter that Advanced - Billing assigns. - If instead you would like to find a Coupon using a Coupon code, see - the Coupon Find method. - When fetching a coupon, if you have defined multiple currencies at the - site level, you can optionally pass the `?currency_prices=true` query - param to include an array of currency price data in the response. - 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. + def create_coupon_subcodes(self, + coupon_id, + body=None): + """Does a POST request to /coupons/{coupon_id}/codes.json. + ## Coupon Subcodes Intro + Coupon Subcodes allow you to create a set of unique codes that allow + you to expand the use of one coupon. + For example: + Master Coupon Code: + + SPRING2020 + Coupon Subcodes: + + SPRING90210 + + DP80302 + + SPRINGBALTIMORE + Coupon subcodes can be administered in the Admin Interface or via the + API. + When creating a coupon subcode, you must specify a coupon to attach it + to using the coupon_id. Valid coupon subcodes are all capital letters, + contain only letters and numbers, and do not have any spaces. + Lowercase letters will be capitalized before the subcode is created. + ## Coupon Subcodes Documentation + 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-Coupo + n-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-Coupo + ns-and-Subscriptions). + ## Create Coupon Subcode + This request allows you to create specific subcodes underneath an + existing coupon code. + *Note*: If you are using any of the allowed special characters ("%", + "@", "+", "-", "_", and "."), you must encode them for use in the + URL. + % to %25 + @ to %40 + + to %2B + - to %2D + _ to %5F + . to %2E + So, if the coupon subcode is `20%OFF`, the URL to delete this coupon + subcode would be: + `https://.chargify.com/coupons/567/codes/20%25OFF.` + 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 + body (CouponSubcodes, optional): TODO: type description here. Returns: - CouponResponse: Response from the API. OK + CouponSubcodesResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -268,51 +310,61 @@ def read_coupon(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/product_families/{product_family_id}/coupons/{coupon_id}.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('product_family_id') - .value(product_family_id) - .is_required(True) - .should_encode(True)) + .path('/coupons/{coupon_id}/codes.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('coupon_id') .value(coupon_id) .is_required(True) .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(CouponResponse.from_dictionary) + .deserialize_into(CouponSubcodesResponse.from_dictionary) ).execute() - def update_coupon(self, - product_family_id, - coupon_id, - body=None): - """Does a PUT request to /product_families/{product_family_id}/coupons/{coupon_id}.json. + def list_coupon_subcodes(self, + options=dict()): + """Does a GET request to /coupons/{coupon_id}/codes.json. - ## Update Coupon - You can update a Coupon via the API with a PUT request to the resource - endpoint. - You can restrict a coupon to only apply to specific products / - components by optionally passing in hashes of `restricted_products` - and/or `restricted_components` in the format: - `{ "": boolean_value }` + This request allows you to request the subcodes that are attached to a + coupon. 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 - body (CreateOrUpdateCoupon, optional): TODO: type description - here. + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + coupon_id -- int -- The Advanced Billing id of the coupon + 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 + 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`. + per_page -- int -- 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`. Returns: - CouponResponse: Response from the API. OK + CouponSubcodes: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -324,52 +376,63 @@ def update_coupon(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/product_families/{product_family_id}/coupons/{coupon_id}.json') - .http_method(HttpMethodEnum.PUT) - .template_param(Parameter() - .key('product_family_id') - .value(product_family_id) - .is_required(True) - .should_encode(True)) + .path('/coupons/{coupon_id}/codes.json') + .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('coupon_id') - .value(coupon_id) + .value(options.get('coupon_id', None)) .is_required(True) .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) + .query_param(Parameter() + .key('page') + .value(options.get('page', None))) + .query_param(Parameter() + .key('per_page') + .value(options.get('per_page', None))) .header_param(Parameter() .key('accept') .value('application/json')) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(CouponResponse.from_dictionary) + .deserialize_into(CouponSubcodes.from_dictionary) ).execute() - def archive_coupon(self, - product_family_id, - coupon_id): - """Does a DELETE request to /product_families/{product_family_id}/coupons/{coupon_id}.json. + def delete_coupon_subcode(self, + coupon_id, + subcode): + """Does a DELETE request to /coupons/{coupon_id}/codes/{subcode}.json. - You can archive a Coupon via the API with the archive method. - Archiving makes that Coupon unavailable for future use, but allows it - to remain attached and functional on existing Subscriptions that are - using it. - The `archived_at` date and time will be assigned. + ## Example + Given a coupon with an ID of 567, and a coupon subcode of 20OFF, the + URL to `DELETE` this coupon subcode would be: + ``` + http://subdomain.chargify.com/coupons/567/codes/20OFF. + ``` + Note: If you are using any of the allowed special characters (“%”, + “@”, “+”, “-”, “_”, and “.”), you must encode them for use in the + URL. + | Special character | Encoding | + |-------------------|----------| + | % | %25 | + | @ | %40 | + | + | %2B | + | – | %2D | + | _ | %5F | + | . | %2E | + ## Percent Encoding Example + Or if the coupon subcode is 20%OFF, the URL to delete this coupon + subcode would be: + @https://.chargify.com/coupons/567/codes/20%25OFF. 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 + coupon_id (int): The Advanced Billing id of the coupon to which + the subcode belongs + subcode (str): The subcode of the coupon Returns: - CouponResponse: Response from the API. OK + void: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -381,68 +444,41 @@ def archive_coupon(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/product_families/{product_family_id}/coupons/{coupon_id}.json') + .path('/coupons/{coupon_id}/codes/{subcode}.json') .http_method(HttpMethodEnum.DELETE) .template_param(Parameter() - .key('product_family_id') - .value(product_family_id) + .key('coupon_id') + .value(coupon_id) .is_required(True) .should_encode(True)) .template_param(Parameter() - .key('coupon_id') - .value(coupon_id) + .key('subcode') + .value(subcode) .is_required(True) .should_encode(True)) - .header_param(Parameter() - .key('accept') - .value('application/json')) .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(CouponResponse.from_dictionary) ).execute() - def list_coupons(self, - options=dict()): - """Does a GET request to /coupons.json. + def find_coupon(self, + product_family_id=None, + code=None): + """Does a GET request to /coupons/find.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. + You can search for a coupon via the API with the find method. By + passing a code parameter, the find will attempt to locate a coupon + that matches that code. If no coupon is found, a 404 is returned. + If you have more than one product family and if the coupon you are + trying to find does not belong to the default product family in your + site, then you will need to specify (either in the url or as a query + string param) the product family id. Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - 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 - 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`. - per_page -- int -- This parameter indicates how many - records to fetch in each request. Default value is 30. - The maximum allowed values is 200; any per_page value - over 200 will be changed to 200. Use in query - `per_page=200`. - filter -- ListCouponsFilter -- Filter to use for List - Coupons operations - currency_prices -- bool -- When fetching coupons, if you - have defined multiple currencies at the site level, - you can optionally pass the `?currency_prices=true` - query param to include an array of currency price data - in the response. Use in query `currency_prices=true`. + product_family_id (int, optional): The Advanced Billing id of the + product family to which the coupon belongs + code (str, optional): The code of the coupon Returns: - List[CouponResponse]: Response from the API. OK + CouponResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -454,24 +490,17 @@ def list_coupons(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/coupons.json') + .path('/coupons/find.json') .http_method(HttpMethodEnum.GET) .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) - .query_param(Parameter() - .key('filter') - .value(options.get('filter', None))) + .key('product_family_id') + .value(product_family_id)) .query_param(Parameter() - .key('currency_prices') - .value(options.get('currency_prices', None))) + .key('code') + .value(code)) .header_param(Parameter() .key('accept') .value('application/json')) - .array_serialization_format(SerializationFormats.CSV) .auth(Single('BasicAuth')) ).response( ResponseHandler() @@ -597,27 +626,27 @@ def validate_coupon(self, .local_error('404', 'Not Found', SingleStringErrorResponseException) ).execute() - def create_or_update_coupon_currency_prices(self, - coupon_id, - body=None): - """Does a PUT request to /coupons/{coupon_id}/currency_prices.json. + def update_coupon_subcodes(self, + coupon_id, + body=None): + """Does a PUT request to /coupons/{coupon_id}/codes.json. - This endpoint allows you to create and/or update currency prices for - an existing coupon. Multiple prices can be created or updated in a - single request but each of the currencies must be defined on the site - level already and the coupon must be an amount-based coupon, not - percentage. - Currency pricing for coupons must mirror the setup of the primary - coupon pricing - if the primary coupon is percentage based, you will - not be able to define pricing in non-primary currencies. + You can update the subcodes for the given Coupon via the API with a + PUT request to the resource endpoint. + Send an array of new coupon subcodes. + **Note**: All current subcodes for that Coupon will be deleted first, + and replaced with the list of subcodes sent to this endpoint. + The response will contain: + + The created subcodes, + + Subcodes that were not created because they already exist, + + Any subcodes not created because they are invalid. Args: coupon_id (int): The Advanced Billing id of the coupon - body (CouponCurrencyRequest, optional): TODO: type description - here. + body (CouponSubcodes, optional): TODO: type description here. Returns: - CouponCurrencyResponse: Response from the API. OK + CouponSubcodesResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -629,7 +658,7 @@ def create_or_update_coupon_currency_prices(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/coupons/{coupon_id}/currency_prices.json') + .path('/coupons/{coupon_id}/codes.json') .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('coupon_id') @@ -649,62 +678,43 @@ def create_or_update_coupon_currency_prices(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(CouponCurrencyResponse.from_dictionary) + .deserialize_into(CouponSubcodesResponse.from_dictionary) ).execute() - def create_coupon_subcodes(self, - coupon_id, - body=None): - """Does a POST request to /coupons/{coupon_id}/codes.json. + def create_coupon(self, + product_family_id, + body=None): + """Does a POST request to /product_families/{product_family_id}/coupons.json. - ## Coupon Subcodes Intro - Coupon Subcodes allow you to create a set of unique codes that allow - you to expand the use of one coupon. - For example: - Master Coupon Code: - + SPRING2020 - Coupon Subcodes: - + SPRING90210 - + DP80302 - + SPRINGBALTIMORE - Coupon subcodes can be administered in the Admin Interface or via the - API. - When creating a coupon subcode, you must specify a coupon to attach it - to using the coupon_id. Valid coupon subcodes are all capital letters, - contain only letters and numbers, and do not have any spaces. - Lowercase letters will be capitalized before the subcode is created. - ## Coupon Subcodes Documentation - 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-Coupo - n-Codes). + ## 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-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 + subscription within the Advanced Billing UI, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupo ns-and-Subscriptions). - ## Create Coupon Subcode - This request allows you to create specific subcodes underneath an - existing coupon code. - *Note*: If you are using any of the allowed special characters ("%", - "@", "+", "-", "_", and "."), you must encode them for use in the - URL. - % to %25 - @ to %40 - + to %2B - - to %2D - _ to %5F - . to %2E - So, if the coupon subcode is `20%OFF`, the URL to delete this coupon - subcode would be: - `https://.chargify.com/coupons/567/codes/20%25OFF.` - + ## Create Coupon + This request will create a coupon, based on the provided information. + When creating a coupon, you must specify a product family using the + `product_family_id`. If no `product_family_id` is passed, the first + product family available is used. You will also need to formulate your + URL to cite the Product Family ID in your request. + You can restrict a coupon to only apply to specific products / + components by optionally passing in hashes of `restricted_products` + and/or `restricted_components` in the format: + `{ "": boolean_value }` + Args: - coupon_id (int): The Advanced Billing id of the coupon - body (CouponSubcodes, optional): TODO: type description here. + product_family_id (int): The Advanced Billing id of the product + family to which the coupon belongs + body (CreateOrUpdateCoupon, optional): TODO: type description + here. Returns: - CouponSubcodesResponse: Response from the API. OK + CouponResponse: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -716,11 +726,11 @@ def create_coupon_subcodes(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/coupons/{coupon_id}/codes.json') + .path('/product_families/{product_family_id}/coupons.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() - .key('coupon_id') - .value(coupon_id) + .key('product_family_id') + .value(product_family_id) .is_required(True) .should_encode(True)) .header_param(Parameter() @@ -736,41 +746,34 @@ def create_coupon_subcodes(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(CouponSubcodesResponse.from_dictionary) + .deserialize_into(CouponResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def list_coupon_subcodes(self, - options=dict()): - """Does a GET request to /coupons/{coupon_id}/codes.json. + def read_coupon(self, + product_family_id, + coupon_id): + """Does a GET request to /product_families/{product_family_id}/coupons/{coupon_id}.json. - This request allows you to request the subcodes that are attached to a - coupon. + You can retrieve the Coupon via the API with the Show method. You must + identify the Coupon in this call by the ID parameter that Advanced + Billing assigns. + If instead you would like to find a Coupon using a Coupon code, see + the Coupon Find method. + When fetching a coupon, if you have defined multiple currencies at the + site level, you can optionally pass the `?currency_prices=true` query + param to include an array of currency price data in the response. + 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 - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - coupon_id -- int -- The Advanced Billing id of the coupon - 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 - 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`. - per_page -- int -- 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`. + 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 Returns: - CouponSubcodes: Response from the API. OK + CouponResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -782,19 +785,18 @@ def list_coupon_subcodes(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/coupons/{coupon_id}/codes.json') + .path('/product_families/{product_family_id}/coupons/{coupon_id}.json') .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('product_family_id') + .value(product_family_id) + .is_required(True) + .should_encode(True)) .template_param(Parameter() .key('coupon_id') - .value(options.get('coupon_id', None)) + .value(coupon_id) .is_required(True) .should_encode(True)) - .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) .header_param(Parameter() .key('accept') .value('application/json')) @@ -802,30 +804,32 @@ def list_coupon_subcodes(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(CouponSubcodes.from_dictionary) + .deserialize_into(CouponResponse.from_dictionary) ).execute() - def update_coupon_subcodes(self, - coupon_id, - body=None): - """Does a PUT request to /coupons/{coupon_id}/codes.json. + def update_coupon(self, + product_family_id, + coupon_id, + body=None): + """Does a PUT request to /product_families/{product_family_id}/coupons/{coupon_id}.json. - You can update the subcodes for the given Coupon via the API with a - PUT request to the resource endpoint. - Send an array of new coupon subcodes. - **Note**: All current subcodes for that Coupon will be deleted first, - and replaced with the list of subcodes sent to this endpoint. - The response will contain: - + The created subcodes, - + Subcodes that were not created because they already exist, - + Any subcodes not created because they are invalid. + ## Update Coupon + You can update a Coupon via the API with a PUT request to the resource + endpoint. + You can restrict a coupon to only apply to specific products / + components by optionally passing in hashes of `restricted_products` + and/or `restricted_components` in the format: + `{ "": boolean_value }` 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 - body (CouponSubcodes, optional): TODO: type description here. + body (CreateOrUpdateCoupon, optional): TODO: type description + here. Returns: - CouponSubcodesResponse: Response from the API. OK + CouponResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -837,8 +841,13 @@ def update_coupon_subcodes(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/coupons/{coupon_id}/codes.json') + .path('/product_families/{product_family_id}/coupons/{coupon_id}.json') .http_method(HttpMethodEnum.PUT) + .template_param(Parameter() + .key('product_family_id') + .value(product_family_id) + .is_required(True) + .should_encode(True)) .template_param(Parameter() .key('coupon_id') .value(coupon_id) @@ -857,43 +866,27 @@ def update_coupon_subcodes(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(CouponSubcodesResponse.from_dictionary) + .deserialize_into(CouponResponse.from_dictionary) ).execute() - def delete_coupon_subcode(self, - coupon_id, - subcode): - """Does a DELETE request to /coupons/{coupon_id}/codes/{subcode}.json. + def archive_coupon(self, + product_family_id, + coupon_id): + """Does a DELETE request to /product_families/{product_family_id}/coupons/{coupon_id}.json. - ## Example - Given a coupon with an ID of 567, and a coupon subcode of 20OFF, the - URL to `DELETE` this coupon subcode would be: - ``` - http://subdomain.chargify.com/coupons/567/codes/20OFF. - ``` - Note: If you are using any of the allowed special characters (“%”, - “@”, “+”, “-”, “_”, and “.”), you must encode them for use in the - URL. - | Special character | Encoding | - |-------------------|----------| - | % | %25 | - | @ | %40 | - | + | %2B | - | – | %2D | - | _ | %5F | - | . | %2E | - ## Percent Encoding Example - Or if the coupon subcode is 20%OFF, the URL to delete this coupon - subcode would be: - @https://.chargify.com/coupons/567/codes/20%25OFF. + You can archive a Coupon via the API with the archive method. + Archiving makes that Coupon unavailable for future use, but allows it + to remain attached and functional on existing Subscriptions that are + using it. + The `archived_at` date and time will be assigned. Args: - coupon_id (int): The Advanced Billing id of the coupon to which - the subcode belongs - subcode (str): The subcode of the coupon + 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 Returns: - void: Response from the API. OK + CouponResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -905,17 +898,24 @@ def delete_coupon_subcode(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/coupons/{coupon_id}/codes/{subcode}.json') + .path('/product_families/{product_family_id}/coupons/{coupon_id}.json') .http_method(HttpMethodEnum.DELETE) .template_param(Parameter() - .key('coupon_id') - .value(coupon_id) + .key('product_family_id') + .value(product_family_id) .is_required(True) .should_encode(True)) .template_param(Parameter() - .key('subcode') - .value(subcode) + .key('coupon_id') + .value(coupon_id) .is_required(True) .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(CouponResponse.from_dictionary) ).execute() diff --git a/advancedbilling/controllers/custom_fields_controller.py b/advancedbilling/controllers/custom_fields_controller.py index d5635e3d..48d52bee 100644 --- a/advancedbilling/controllers/custom_fields_controller.py +++ b/advancedbilling/controllers/custom_fields_controller.py @@ -17,8 +17,8 @@ from apimatic_core.types.array_serialization_format import SerializationFormats from apimatic_core.authentication.multiple.single_auth import Single from advancedbilling.models.metafield import Metafield -from advancedbilling.models.list_metafields_response import ListMetafieldsResponse from advancedbilling.models.metadata import Metadata +from advancedbilling.models.list_metafields_response import ListMetafieldsResponse from advancedbilling.models.paginated_metadata import PaginatedMetadata from advancedbilling.exceptions.single_error_response_exception import SingleErrorResponseException from advancedbilling.exceptions.api_exception import APIException @@ -30,51 +30,18 @@ class CustomFieldsController(BaseController): def __init__(self, config): super(CustomFieldsController, self).__init__(config) - def create_metafields(self, - resource_type, - body=None): - """Does a POST request to /{resource_type}/metafields.json. + def update_metafield(self, + resource_type, + body=None): + """Does a PUT 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-existant 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**. + Use the following method to update metafields for your Site. + Metafields can be populated with metadata after the fact. Args: resource_type (ResourceType): the resource type to which the metafields belong - body (CreateMetafieldsRequest, optional): TODO: type description + body (UpdateMetafieldsRequest, optional): TODO: type description here. Returns: @@ -91,7 +58,7 @@ def create_metafields(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/{resource_type}/metafields.json') - .http_method(HttpMethodEnum.POST) + .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('resource_type') .value(resource_type) @@ -114,43 +81,51 @@ def create_metafields(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SingleErrorResponseException) ).execute() - def list_metafields(self, - options=dict()): - """Does a GET request to /{resource_type}/metafields.json. + def create_metadata(self, + resource_type, + resource_id, + body=None): + """Does a POST request to /{resource_type}/{resource_id}/metadata.json. - This endpoint lists metafields associated with a site. The metafield - description and usage is contained in the response. + ## 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. Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - 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 - 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 - 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`. - per_page -- int -- 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`. - direction -- SortingDirection -- Controls the order in - which results are returned. Use in query - `direction=asc`. + 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): TODO: type description + here. Returns: - ListMetafieldsResponse: Response from the API. OK + List[Metadata]: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -162,51 +137,74 @@ def list_metafields(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/{resource_type}/metafields.json') - .http_method(HttpMethodEnum.GET) + .path('/{resource_type}/{resource_id}/metadata.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('resource_type') - .value(options.get('resource_type', None)) + .value(resource_type) .is_required(True) .should_encode(True)) - .query_param(Parameter() - .key('name') - .value(options.get('name', None))) - .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) - .query_param(Parameter() - .key('direction') - .value(options.get('direction', None))) + .template_param(Parameter() + .key('resource_id') + .value(resource_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ListMetafieldsResponse.from_dictionary) + .deserialize_into(Metadata.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SingleErrorResponseException) ).execute() - def update_metafield(self, - resource_type, - body=None): - """Does a PUT request to /{resource_type}/metafields.json. + def delete_metadata(self, + resource_type, + resource_id, + name=None, + names=None): + """Does a DELETE request to /{resource_type}/{resource_id}/metadata.json. - Use the following method to update metafields for your Site. - Metafields can be populated with metadata after the fact. + 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`. Args: resource_type (ResourceType): the resource type to which the metafields belong - body (UpdateMetafieldsRequest, optional): TODO: type description - here. + 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. + names (List[str], optional): Names of fields to be removed. Use in + query: + `names[]=field1&names[]=my-field&names[]=another-field`. Returns: - List[Metafield]: Response from the API. OK + void: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -218,28 +216,26 @@ def update_metafield(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/{resource_type}/metafields.json') - .http_method(HttpMethodEnum.PUT) + .path('/{resource_type}/{resource_id}/metadata.json') + .http_method(HttpMethodEnum.DELETE) .template_param(Parameter() .key('resource_type') .value(resource_type) .is_required(True) .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) + .template_param(Parameter() + .key('resource_id') + .value(resource_id) + .is_required(True) + .should_encode(True)) + .query_param(Parameter() + .key('name') + .value(name)) + .query_param(Parameter() + .key('names') + .value(names)) + .array_serialization_format(SerializationFormats.UN_INDEXED) .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(Metafield.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SingleErrorResponseException) ).execute() def delete_metafield(self, @@ -283,47 +279,21 @@ def delete_metafield(self, .auth(Single('BasicAuth')) ).execute() - def create_metadata(self, + def update_metadata(self, resource_type, resource_id, body=None): - """Does a POST request to /{resource_type}/{resource_id}/metadata.json. + """Does a PUT 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. + This method allows you to update the existing metadata associated with + a subscription or customer. Args: 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): TODO: type description + body (UpdateMetadataRequest, optional): TODO: type description here. Returns: @@ -340,7 +310,7 @@ def create_metadata(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/{resource_type}/{resource_id}/metadata.json') - .http_method(HttpMethodEnum.POST) + .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('resource_type') .value(resource_type) @@ -368,15 +338,12 @@ def create_metadata(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SingleErrorResponseException) ).execute() - def list_metadata(self, - options=dict()): - """Does a GET request to /{resource_type}/{resource_id}/metadata.json. + def list_metafields(self, + options=dict()): + """Does a GET request to /{resource_type}/metafields.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. + This endpoint lists metafields associated with a site. The metafield + description and usage is contained in the response. Args: options (dict, optional): Key-value pairs for any of the @@ -387,9 +354,7 @@ def list_metadata(self, 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 -- 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 @@ -404,9 +369,12 @@ def list_metadata(self, The maximum allowed values is 200; any per_page value over 200 will be changed to 200. Use in query `per_page=200`. + direction -- SortingDirection -- Controls the order in + which results are returned. Use in query + `direction=asc`. Returns: - PaginatedMetadata: Response from the API. OK + ListMetafieldsResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -418,24 +386,25 @@ def list_metadata(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/{resource_type}/{resource_id}/metadata.json') + .path('/{resource_type}/metafields.json') .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('resource_type') .value(options.get('resource_type', None)) .is_required(True) .should_encode(True)) - .template_param(Parameter() - .key('resource_id') - .value(options.get('resource_id', None)) - .is_required(True) - .should_encode(True)) + .query_param(Parameter() + .key('name') + .value(options.get('name', None))) .query_param(Parameter() .key('page') .value(options.get('page', None))) .query_param(Parameter() .key('per_page') .value(options.get('per_page', None))) + .query_param(Parameter() + .key('direction') + .value(options.get('direction', None))) .header_param(Parameter() .key('accept') .value('application/json')) @@ -443,28 +412,58 @@ def list_metadata(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(PaginatedMetadata.from_dictionary) + .deserialize_into(ListMetafieldsResponse.from_dictionary) ).execute() - def update_metadata(self, - resource_type, - resource_id, - body=None): - """Does a PUT request to /{resource_type}/{resource_id}/metadata.json. + def create_metafields(self, + resource_type, + body=None): + """Does a POST request to /{resource_type}/metafields.json. - This method allows you to update the existing metadata associated with - a subscription or customer. + ## 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-existant 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**. Args: 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): TODO: type description + body (CreateMetafieldsRequest, optional): TODO: type description here. Returns: - List[Metadata]: Response from the API. OK + List[Metafield]: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -476,18 +475,13 @@ def update_metadata(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/{resource_type}/{resource_id}/metadata.json') - .http_method(HttpMethodEnum.PUT) + .path('/{resource_type}/metafields.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('resource_type') .value(resource_type) .is_required(True) .should_encode(True)) - .template_param(Parameter() - .key('resource_id') - .value(resource_id) - .is_required(True) - .should_encode(True)) .header_param(Parameter() .key('Content-Type') .value('application/json')) @@ -501,49 +495,49 @@ def update_metadata(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(Metadata.from_dictionary) + .deserialize_into(Metafield.from_dictionary) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SingleErrorResponseException) ).execute() - def delete_metadata(self, - resource_type, - resource_id, - name=None, - names=None): - """Does a DELETE request to /{resource_type}/{resource_id}/metadata.json. + def list_metadata(self, + options=dict()): + """Does a GET 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`. + 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. Args: - 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. - names (List[str], optional): Names of fields to be removed. Use in - query: - `names[]=field1&names[]=my-field&names[]=another-field`. + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + 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_id -- int -- The Advanced Billing id of the + customer or the subscription for which the metadata + applies + 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 + 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`. + per_page -- int -- 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`. Returns: - void: Response from the API. OK + PaginatedMetadata: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -556,25 +550,31 @@ def delete_metadata(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/{resource_type}/{resource_id}/metadata.json') - .http_method(HttpMethodEnum.DELETE) + .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('resource_type') - .value(resource_type) + .value(options.get('resource_type', None)) .is_required(True) .should_encode(True)) .template_param(Parameter() .key('resource_id') - .value(resource_id) + .value(options.get('resource_id', None)) .is_required(True) .should_encode(True)) .query_param(Parameter() - .key('name') - .value(name)) + .key('page') + .value(options.get('page', None))) .query_param(Parameter() - .key('names') - .value(names)) - .array_serialization_format(SerializationFormats.UN_INDEXED) + .key('per_page') + .value(options.get('per_page', None))) + .header_param(Parameter() + .key('accept') + .value('application/json')) .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(PaginatedMetadata.from_dictionary) ).execute() def list_metadata_for_resource_type(self, diff --git a/advancedbilling/controllers/customers_controller.py b/advancedbilling/controllers/customers_controller.py index 23946cfe..cacc5a3b 100644 --- a/advancedbilling/controllers/customers_controller.py +++ b/advancedbilling/controllers/customers_controller.py @@ -317,38 +317,6 @@ def update_customer(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', CustomerErrorResponseException) ).execute() - def delete_customer(self, - id): - """Does a DELETE request to /customers/{id}.json. - - This method allows you to delete the Customer. - - Args: - id (int): The Advanced Billing id of the customer - - Returns: - void: Response from the API. No Content - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/customers/{id}.json') - .http_method(HttpMethodEnum.DELETE) - .template_param(Parameter() - .key('id') - .value(id) - .is_required(True) - .should_encode(True)) - .auth(Single('BasicAuth')) - ).execute() - def read_customer_by_reference(self, reference): """Does a GET request to /customers/lookup.json. @@ -389,6 +357,38 @@ def read_customer_by_reference(self, .deserialize_into(CustomerResponse.from_dictionary) ).execute() + def delete_customer(self, + id): + """Does a DELETE request to /customers/{id}.json. + + This method allows you to delete the Customer. + + Args: + id (int): The Advanced Billing id of the customer + + Returns: + void: Response from the API. No Content + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/customers/{id}.json') + .http_method(HttpMethodEnum.DELETE) + .template_param(Parameter() + .key('id') + .value(id) + .is_required(True) + .should_encode(True)) + .auth(Single('BasicAuth')) + ).execute() + def list_customer_subscriptions(self, customer_id): """Does a GET request to /customers/{customer_id}/subscriptions.json. diff --git a/advancedbilling/controllers/events_based_billing_segments_controller.py b/advancedbilling/controllers/events_based_billing_segments_controller.py index 5a2917b7..40688df7 100644 --- a/advancedbilling/controllers/events_based_billing_segments_controller.py +++ b/advancedbilling/controllers/events_based_billing_segments_controller.py @@ -20,8 +20,8 @@ from advancedbilling.models.list_segments_response import ListSegmentsResponse from advancedbilling.exceptions.api_exception import APIException from advancedbilling.exceptions.event_based_billing_segment_errors_exception import EventBasedBillingSegmentErrorsException -from advancedbilling.exceptions.event_based_billing_list_segments_errors_exception import EventBasedBillingListSegmentsErrorsException from advancedbilling.exceptions.event_based_billing_segment_exception import EventBasedBillingSegmentException +from advancedbilling.exceptions.event_based_billing_list_segments_errors_exception import EventBasedBillingListSegmentsErrorsException class EventsBasedBillingSegmentsController(BaseController): @@ -93,47 +93,29 @@ def create_segment(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', EventBasedBillingSegmentErrorsException) ).execute() - def list_segments_for_price_point(self, - options=dict()): - """Does a GET request to /components/{component_id}/price_points/{price_point_id}/segments.json. + def update_segment(self, + component_id, + price_point_id, + id, + body=None): + """Does a PUT request to /components/{component_id}/price_points/{price_point_id}/segments/{id}.json. - This endpoint allows you to fetch Segments created for a given Price - Point. They will be returned in the order of creation. - You can pass `page` and `per_page` parameters in order to access all - of the segments. By default it will return `30` records. You can set - `per_page` to `200` at most. + This endpoint updates a single Segment for a Component with a + segmented Metric. It allows you to update the pricing for the + segment. You may specify component and/or price point by using either the numeric ID or the `handle:gold` syntax. Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - component_id -- str -- ID or Handle for the Component - price_point_id -- str -- ID or Handle for the Price Point - belonging to the Component - 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 - 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`. - per_page -- int -- This parameter indicates how many - records to fetch in each request. Default value is 30. - The maximum allowed values is 200; any per_page value - over 200 will be changed to 200. Use in query - `per_page=200`. - filter -- ListSegmentsFilter -- Filter to use for List - Segments for a Price Point operation + component_id (str): ID or Handle of the Component + price_point_id (str): ID or Handle of the Price Point belonging to + the Component + id (float): The ID of the Segment + body (UpdateSegmentRequest, optional): TODO: type description + here. Returns: - ListSegmentsResponse: Response from the API. OK + SegmentResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -145,63 +127,64 @@ def list_segments_for_price_point(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/components/{component_id}/price_points/{price_point_id}/segments.json') - .http_method(HttpMethodEnum.GET) + .path('/components/{component_id}/price_points/{price_point_id}/segments/{id}.json') + .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('component_id') - .value(options.get('component_id', None)) + .value(component_id) .is_required(True) .should_encode(True)) .template_param(Parameter() .key('price_point_id') - .value(options.get('price_point_id', None)) + .value(price_point_id) .is_required(True) .should_encode(True)) - .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) - .query_param(Parameter() - .key('filter') - .value(options.get('filter', None))) + .template_param(Parameter() + .key('id') + .value(id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) - .array_serialization_format(SerializationFormats.CSV) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ListSegmentsResponse.from_dictionary) + .deserialize_into(SegmentResponse.from_dictionary) .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', EventBasedBillingListSegmentsErrorsException) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', EventBasedBillingSegmentErrorsException) ).execute() - def update_segment(self, - component_id, - price_point_id, - id, - body=None): - """Does a PUT request to /components/{component_id}/price_points/{price_point_id}/segments/{id}.json. + def bulk_create_segments(self, + component_id, + price_point_id, + body=None): + """Does a POST request to /components/{component_id}/price_points/{price_point_id}/segments/bulk.json. - This endpoint updates a single Segment for a Component with a - segmented Metric. It allows you to update the pricing for the - segment. + This endpoint allows you to create multiple segments in one request. + The array of segments can contain up to `2000` records. + If any of the records contain an error the whole request would fail + and none of the requested segments get created. The error response + contains a message for only the one segment that failed validation, + with the corresponding index in the array. You may specify component and/or price point by using either the numeric ID or the `handle:gold` syntax. Args: - component_id (str): ID or Handle of the Component - price_point_id (str): ID or Handle of the Price Point belonging to - the Component - id (float): The ID of the Segment - body (UpdateSegmentRequest, optional): TODO: type description - here. + component_id (str): ID or Handle for the Component + price_point_id (str): ID or Handle for the Price Point belonging + to the Component + body (BulkCreateSegments, optional): TODO: type description here. Returns: - SegmentResponse: Response from the API. OK + ListSegmentsResponse: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -213,8 +196,8 @@ def update_segment(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/components/{component_id}/price_points/{price_point_id}/segments/{id}.json') - .http_method(HttpMethodEnum.PUT) + .path('/components/{component_id}/price_points/{price_point_id}/segments/bulk.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('component_id') .value(component_id) @@ -225,11 +208,6 @@ def update_segment(self, .value(price_point_id) .is_required(True) .should_encode(True)) - .template_param(Parameter() - .key('id') - .value(id) - .is_required(True) - .should_encode(True)) .header_param(Parameter() .key('Content-Type') .value('application/json')) @@ -243,29 +221,52 @@ def update_segment(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(SegmentResponse.from_dictionary) + .deserialize_into(ListSegmentsResponse.from_dictionary) .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', EventBasedBillingSegmentErrorsException) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', EventBasedBillingSegmentException) ).execute() - def delete_segment(self, - component_id, - price_point_id, - id): - """Does a DELETE request to /components/{component_id}/price_points/{price_point_id}/segments/{id}.json. + def list_segments_for_price_point(self, + options=dict()): + """Does a GET request to /components/{component_id}/price_points/{price_point_id}/segments.json. - This endpoint allows you to delete a Segment with specified ID. + This endpoint allows you to fetch Segments created for a given Price + Point. They will be returned in the order of creation. + You can pass `page` and `per_page` parameters in order to access all + of the segments. By default it will return `30` records. You can set + `per_page` to `200` at most. You may specify component and/or price point by using either the numeric ID or the `handle:gold` syntax. Args: - component_id (str): ID or Handle of the Component - price_point_id (str): ID or Handle of the Price Point belonging to - the Component - id (float): The ID of the Segment + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + component_id -- str -- ID or Handle for the Component + price_point_id -- str -- ID or Handle for the Price Point + belonging to the Component + 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 + 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`. + per_page -- int -- This parameter indicates how many + records to fetch in each request. Default value is 30. + The maximum allowed values is 200; any per_page value + over 200 will be changed to 200. Use in query + `per_page=200`. + filter -- ListSegmentsFilter -- Filter to use for List + Segments for a Price Point operation Returns: - void: Response from the API. No Content + ListSegmentsResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -277,49 +278,58 @@ def delete_segment(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/components/{component_id}/price_points/{price_point_id}/segments/{id}.json') - .http_method(HttpMethodEnum.DELETE) + .path('/components/{component_id}/price_points/{price_point_id}/segments.json') + .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('component_id') - .value(component_id) + .value(options.get('component_id', None)) .is_required(True) .should_encode(True)) .template_param(Parameter() .key('price_point_id') - .value(price_point_id) - .is_required(True) - .should_encode(True)) - .template_param(Parameter() - .key('id') - .value(id) + .value(options.get('price_point_id', None)) .is_required(True) .should_encode(True)) + .query_param(Parameter() + .key('page') + .value(options.get('page', None))) + .query_param(Parameter() + .key('per_page') + .value(options.get('per_page', None))) + .query_param(Parameter() + .key('filter') + .value(options.get('filter', None))) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .array_serialization_format(SerializationFormats.CSV) .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(ListSegmentsResponse.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', EventBasedBillingListSegmentsErrorsException) ).execute() - def bulk_create_segments(self, - component_id, - price_point_id, - body=None): - """Does a POST request to /components/{component_id}/price_points/{price_point_id}/segments/bulk.json. + def delete_segment(self, + component_id, + price_point_id, + id): + """Does a DELETE request to /components/{component_id}/price_points/{price_point_id}/segments/{id}.json. - This endpoint allows you to create multiple segments in one request. - The array of segments can contain up to `2000` records. - If any of the records contain an error the whole request would fail - and none of the requested segments get created. The error response - contains a message for only the one segment that failed validation, - with the corresponding index in the array. + This endpoint allows you to delete a Segment with specified ID. You may specify component and/or price point by using either the numeric ID or the `handle:gold` syntax. Args: - component_id (str): ID or Handle for the Component - price_point_id (str): ID or Handle for the Price Point belonging - to the Component - body (BulkCreateSegments, optional): TODO: type description here. + component_id (str): ID or Handle of the Component + price_point_id (str): ID or Handle of the Price Point belonging to + the Component + id (float): The ID of the Segment Returns: - ListSegmentsResponse: Response from the API. Created + void: Response from the API. No Content Raises: APIException: When an error occurs while fetching the data from @@ -331,8 +341,8 @@ def bulk_create_segments(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/components/{component_id}/price_points/{price_point_id}/segments/bulk.json') - .http_method(HttpMethodEnum.POST) + .path('/components/{component_id}/price_points/{price_point_id}/segments/{id}.json') + .http_method(HttpMethodEnum.DELETE) .template_param(Parameter() .key('component_id') .value(component_id) @@ -343,22 +353,12 @@ def bulk_create_segments(self, .value(price_point_id) .is_required(True) .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) + .template_param(Parameter() + .key('id') + .value(id) + .is_required(True) + .should_encode(True)) .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(ListSegmentsResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', EventBasedBillingSegmentException) ).execute() def bulk_update_segments(self, diff --git a/advancedbilling/controllers/events_controller.py b/advancedbilling/controllers/events_controller.py index c8e60ef6..2b68d400 100644 --- a/advancedbilling/controllers/events_controller.py +++ b/advancedbilling/controllers/events_controller.py @@ -26,6 +26,96 @@ class EventsController(BaseController): def __init__(self, config): super(EventsController, self).__init__(config) + def list_subscription_events(self, + options=dict()): + """Does a GET request to /subscriptions/{subscription_id}/events.json. + + The following request will return a list of events for a + subscription. + Each event type has its own `event_specific_data` specified. + + Args: + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + subscription_id -- int -- The Chargify id of the + subscription + 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 + 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`. + per_page -- int -- 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`. + since_id -- long|int -- Returns events with an id greater + than or equal to the one specified + max_id -- long|int -- Returns events with an id less than + or equal to the one specified + direction -- Direction -- The sort direction of the + returned events. + filter -- List[EventType] -- You can pass multiple event + keys after comma. Use in query + `filter=signup_success,payment_success`. + + Returns: + List[EventResponse]: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/events.json') + .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('subscription_id') + .value(options.get('subscription_id', None)) + .is_required(True) + .should_encode(True)) + .query_param(Parameter() + .key('page') + .value(options.get('page', None))) + .query_param(Parameter() + .key('per_page') + .value(options.get('per_page', None))) + .query_param(Parameter() + .key('since_id') + .value(options.get('since_id', None))) + .query_param(Parameter() + .key('max_id') + .value(options.get('max_id', None))) + .query_param(Parameter() + .key('direction') + .value(options.get('direction', None))) + .query_param(Parameter() + .key('filter') + .value(options.get('filter', None))) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .array_serialization_format(SerializationFormats.CSV) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(EventResponse.from_dictionary) + ).execute() + def list_events(self, options=dict()): """Does a GET request to /events.json. @@ -206,96 +296,6 @@ def list_events(self, .deserialize_into(EventResponse.from_dictionary) ).execute() - def list_subscription_events(self, - options=dict()): - """Does a GET request to /subscriptions/{subscription_id}/events.json. - - The following request will return a list of events for a - subscription. - Each event type has its own `event_specific_data` specified. - - Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - subscription_id -- int -- The Chargify id of the - subscription - 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 - 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`. - per_page -- int -- 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`. - since_id -- long|int -- Returns events with an id greater - than or equal to the one specified - max_id -- long|int -- Returns events with an id less than - or equal to the one specified - direction -- Direction -- The sort direction of the - returned events. - filter -- List[EventType] -- You can pass multiple event - keys after comma. Use in query - `filter=signup_success,payment_success`. - - Returns: - List[EventResponse]: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/events.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('subscription_id') - .value(options.get('subscription_id', None)) - .is_required(True) - .should_encode(True)) - .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) - .query_param(Parameter() - .key('since_id') - .value(options.get('since_id', None))) - .query_param(Parameter() - .key('max_id') - .value(options.get('max_id', None))) - .query_param(Parameter() - .key('direction') - .value(options.get('direction', None))) - .query_param(Parameter() - .key('filter') - .value(options.get('filter', None))) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .array_serialization_format(SerializationFormats.CSV) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(EventResponse.from_dictionary) - ).execute() - def read_events_count(self, options=dict()): """Does a GET request to /events/count.json. diff --git a/advancedbilling/controllers/insights_controller.py b/advancedbilling/controllers/insights_controller.py index c510a8dc..1cbe3836 100644 --- a/advancedbilling/controllers/insights_controller.py +++ b/advancedbilling/controllers/insights_controller.py @@ -17,10 +17,10 @@ from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.types.array_serialization_format import SerializationFormats from apimatic_core.authentication.multiple.single_auth import Single -from advancedbilling.models.site_summary import SiteSummary -from advancedbilling.models.mrr_response import MRRResponse from advancedbilling.models.list_mrr_response import ListMRRResponse from advancedbilling.models.subscription_mrr_response import SubscriptionMRRResponse +from advancedbilling.models.site_summary import SiteSummary +from advancedbilling.models.mrr_response import MRRResponse from advancedbilling.exceptions.subscriptions_mrr_error_response_exception import SubscriptionsMrrErrorResponseException @@ -30,91 +30,6 @@ class InsightsController(BaseController): def __init__(self, config): super(InsightsController, self).__init__(config) - def read_site_stats(self): - """Does a GET request to /stats.json. - - The Stats API is a very basic view of some Site-level stats. This API - call only answers with JSON responses. An XML version is not - provided. - ## Stats Documentation - There currently is not a complimentary matching set of documentation - that compliments this endpoint. However, each Site's dashboard will - reflect the summary of information provided in the Stats reposnse. - ``` - https://subdomain.chargify.com/dashboard - ``` - - Returns: - SiteSummary: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/stats.json') - .http_method(HttpMethodEnum.GET) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(SiteSummary.from_dictionary) - ).execute() - - @deprecated() - def read_mrr(self, - at_time=None, - subscription_id=None): - """Does a GET request to /mrr.json. - - This endpoint returns your site's current MRR, including plan and - usage breakouts. - - Args: - at_time (datetime, optional): submit a timestamp in ISO8601 format - to request MRR for a historic time - subscription_id (int, optional): submit the id of a subscription - in order to limit results - - Returns: - MRRResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/mrr.json') - .http_method(HttpMethodEnum.GET) - .query_param(Parameter() - .key('at_time') - .value(APIHelper.when_defined(APIHelper.RFC3339DateTime, at_time))) - .query_param(Parameter() - .key('subscription_id') - .value(subscription_id)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(MRRResponse.from_dictionary) - ).execute() - @deprecated() def list_mrr_movements(self, options=dict()): @@ -289,3 +204,88 @@ def list_mrr_per_subscription(self, .deserialize_into(SubscriptionMRRResponse.from_dictionary) .local_error_template('400', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SubscriptionsMrrErrorResponseException) ).execute() + + def read_site_stats(self): + """Does a GET request to /stats.json. + + The Stats API is a very basic view of some Site-level stats. This API + call only answers with JSON responses. An XML version is not + provided. + ## Stats Documentation + There currently is not a complimentary matching set of documentation + that compliments this endpoint. However, each Site's dashboard will + reflect the summary of information provided in the Stats reposnse. + ``` + https://subdomain.chargify.com/dashboard + ``` + + Returns: + SiteSummary: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/stats.json') + .http_method(HttpMethodEnum.GET) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(SiteSummary.from_dictionary) + ).execute() + + @deprecated() + def read_mrr(self, + at_time=None, + subscription_id=None): + """Does a GET request to /mrr.json. + + This endpoint returns your site's current MRR, including plan and + usage breakouts. + + Args: + at_time (datetime, optional): submit a timestamp in ISO8601 format + to request MRR for a historic time + subscription_id (int, optional): submit the id of a subscription + in order to limit results + + Returns: + MRRResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/mrr.json') + .http_method(HttpMethodEnum.GET) + .query_param(Parameter() + .key('at_time') + .value(APIHelper.when_defined(APIHelper.RFC3339DateTime, at_time))) + .query_param(Parameter() + .key('subscription_id') + .value(subscription_id)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(MRRResponse.from_dictionary) + ).execute() diff --git a/advancedbilling/controllers/invoices_controller.py b/advancedbilling/controllers/invoices_controller.py index 7612b801..80cbcf6a 100644 --- a/advancedbilling/controllers/invoices_controller.py +++ b/advancedbilling/controllers/invoices_controller.py @@ -21,10 +21,10 @@ from advancedbilling.models.list_invoice_events_response import ListInvoiceEventsResponse from advancedbilling.models.multi_invoice_payment_response import MultiInvoicePaymentResponse from advancedbilling.models.list_credit_notes_response import ListCreditNotesResponse -from advancedbilling.models.credit_note import CreditNote -from advancedbilling.models.record_payment_response import RecordPaymentResponse from advancedbilling.models.consolidated_invoice import ConsolidatedInvoice +from advancedbilling.models.credit_note import CreditNote from advancedbilling.models.invoice_response import InvoiceResponse +from advancedbilling.models.record_payment_response import RecordPaymentResponse from advancedbilling.models.customer_changes_preview_response import CustomerChangesPreviewResponse from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException from advancedbilling.exceptions.api_exception import APIException @@ -37,24 +37,27 @@ class InvoicesController(BaseController): def __init__(self, config): super(InvoicesController, self).__init__(config) - def refund_invoice(self, - uid, - body=None): - """Does a POST request to /invoices/{uid}/refunds.json. + def read_invoice(self, + uid): + """Does a GET request to /invoices/{uid}.json. - Refund an invoice, segment, or consolidated invoice. - ## Partial Refund for Consolidated Invoice - A refund less than the total of a consolidated invoice will be split - across its segments. - A $50.00 refund on a $100.00 consolidated invoice with one $60.00 and - one $40.00 segment, the refunded amount will be applied as 50% of each - ($30.00 and $20.00 respectively). + Use this endpoint to retrieve the details for an invoice. + ## PDF Invoice retrieval + Individual PDF Invoices can be retrieved by using the "Accept" header + application/pdf or appending .pdf as the format portion of the URL: + ```curl -u :x -H + Accept:application/pdf -H + https://acme.chargify.com/invoices/inv_8gd8tdhtd3hgr.pdf > + output_file.pdf + URL: `https://.chargify.com/invoices/.` + Method: GET + Required parameters: `uid` + Response: A single Invoice. + ``` Args: uid (str): The unique identifier for the invoice, this does not refer to the public facing invoice number. - body (RefundInvoiceRequest, optional): TODO: type description - here. Returns: Invoice: Response from the API. OK @@ -69,28 +72,21 @@ def refund_invoice(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/invoices/{uid}/refunds.json') - .http_method(HttpMethodEnum.POST) + .path('/invoices/{uid}.json') + .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('uid') .value(uid) .is_required(True) .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(Invoice.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() def list_invoices(self, @@ -273,58 +269,6 @@ def list_invoices(self, .deserialize_into(ListInvoicesResponse.from_dictionary) ).execute() - def read_invoice(self, - uid): - """Does a GET request to /invoices/{uid}.json. - - Use this endpoint to retrieve the details for an invoice. - ## PDF Invoice retrieval - Individual PDF Invoices can be retrieved by using the "Accept" header - application/pdf or appending .pdf as the format portion of the URL: - ```curl -u :x -H - Accept:application/pdf -H - https://acme.chargify.com/invoices/inv_8gd8tdhtd3hgr.pdf > - output_file.pdf - URL: `https://.chargify.com/invoices/.` - Method: GET - Required parameters: `uid` - Response: A single Invoice. - ``` - - Args: - uid (str): The unique identifier for the invoice, this does not - refer to the public facing invoice number. - - Returns: - Invoice: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/invoices/{uid}.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('uid') - .value(uid) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(Invoice.from_dictionary) - ).execute() - def list_invoice_events(self, options=dict()): """Does a GET request to /invoices/events.json. @@ -442,103 +386,6 @@ def list_invoice_events(self, .deserialize_into(ListInvoiceEventsResponse.from_dictionary) ).execute() - def record_payment_for_invoice(self, - uid, - body=None): - """Does a POST request to /invoices/{uid}/payments.json. - - This API call should be used when you want to record a payment of a - given type against a specific invoice. If you would like to apply a - payment across multiple invoices, you can use the Bulk Payment - endpoint. - ## Create a Payment from the existing payment profile - In order to apply a payment to an invoice using an existing payment - profile, specify `type` as `payment`, the amount less than the invoice - total, and the customer's `payment_profile_id`. The ID of a payment - profile might be retrieved via the Payment Profiles API endpoint. - ``` - { - "type": "payment", - "payment": { - "amount": 10.00, - "payment_profile_id": 123 - } - } - ``` - ## Create a Payment from the Subscription's Prepayment Account - In order apply a prepayment to an invoice, specify the `type` as - `prepayment`, and also the `amount`. - ``` - { - "type": "prepayment", - "payment": { - "amount": 10.00 - } - } - ``` - Note that the `amount` must be less than or equal to the - Subscription's Prepayment account balance. - ## Create a Payment from the Subscription's Service Credit Account - In order to apply a service credit to an invoice, specify the `type` - as `service_credit`, and also the `amount`: - ``` - { - "type": "service_credit", - "payment": { - "amount": 10.00 - } - } - ``` - Note that Advanced Billing will attempt to fully pay the invoice's - `due_amount` from the Subscription's Service Credit account. At this - time, partial payments from a Service Credit Account are only allowed - for consolidated invoices (subscription groups). Therefore, for normal - invoices the Service Credit account balance must be greater than or - equal to the invoice's `due_amount`. - - Args: - uid (str): The unique identifier for the invoice, this does not - refer to the public facing invoice number. - body (CreateInvoicePaymentRequest, optional): TODO: type - description here. - - Returns: - Invoice: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/invoices/{uid}/payments.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('uid') - .value(uid) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(Invoice.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) - ).execute() - def record_payment_for_multiple_invoices(self, body=None): """Does a POST request to /invoices/payments.json. @@ -696,17 +543,27 @@ def list_credit_notes(self, .deserialize_into(ListCreditNotesResponse.from_dictionary) ).execute() - def read_credit_note(self, - uid): - """Does a GET request to /credit_notes/{uid}.json. + def refund_invoice(self, + uid, + body=None): + """Does a POST request to /invoices/{uid}/refunds.json. - Use this endpoint to retrieve the details for a credit note. + Refund an invoice, segment, or consolidated invoice. + ## Partial Refund for Consolidated Invoice + A refund less than the total of a consolidated invoice will be split + across its segments. + A $50.00 refund on a $100.00 consolidated invoice with one $60.00 and + one $40.00 segment, the refunded amount will be applied as 50% of each + ($30.00 and $20.00 respectively). Args: - uid (str): The unique identifier of the credit note + uid (str): The unique identifier for the invoice, this does not + refer to the public facing invoice number. + body (RefundInvoiceRequest, optional): TODO: type description + here. Returns: - CreditNote: Response from the API. OK + Invoice: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -718,45 +575,92 @@ def read_credit_note(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/credit_notes/{uid}.json') - .http_method(HttpMethodEnum.GET) + .path('/invoices/{uid}/refunds.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('uid') .value(uid) .is_required(True) .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(CreditNote.from_dictionary) + .deserialize_into(Invoice.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def record_payment_for_subscription(self, - subscription_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/payments.json. + def record_payment_for_invoice(self, + uid, + body=None): + """Does a POST request to /invoices/{uid}/payments.json. - Record an external payment made against a subscription that will pay - partially or in full one or more invoices. - Payment will be applied starting with the oldest open invoice and then - next oldest, and so on until the amount of the payment is fully - consumed. - Excess payment will result in the creation of a prepayment on the - Invoice Account. - Only ungrouped or primary subscriptions may be paid using the "bulk" - payment request. + This API call should be used when you want to record a payment of a + given type against a specific invoice. If you would like to apply a + payment across multiple invoices, you can use the Bulk Payment + endpoint. + ## Create a Payment from the existing payment profile + In order to apply a payment to an invoice using an existing payment + profile, specify `type` as `payment`, the amount less than the invoice + total, and the customer's `payment_profile_id`. The ID of a payment + profile might be retrieved via the Payment Profiles API endpoint. + ``` + { + "type": "payment", + "payment": { + "amount": 10.00, + "payment_profile_id": 123 + } + } + ``` + ## Create a Payment from the Subscription's Prepayment Account + In order apply a prepayment to an invoice, specify the `type` as + `prepayment`, and also the `amount`. + ``` + { + "type": "prepayment", + "payment": { + "amount": 10.00 + } + } + ``` + Note that the `amount` must be less than or equal to the + Subscription's Prepayment account balance. + ## Create a Payment from the Subscription's Service Credit Account + In order to apply a service credit to an invoice, specify the `type` + as `service_credit`, and also the `amount`: + ``` + { + "type": "service_credit", + "payment": { + "amount": 10.00 + } + } + ``` + Note that Advanced Billing will attempt to fully pay the invoice's + `due_amount` from the Subscription's Service Credit account. At this + time, partial payments from a Service Credit Account are only allowed + for consolidated invoices (subscription groups). Therefore, for normal + invoices the Service Credit account balance must be greater than or + equal to the invoice's `due_amount`. Args: - subscription_id (int): The Chargify id of the subscription - body (RecordPaymentRequest, optional): TODO: type description - here. + uid (str): The unique identifier for the invoice, this does not + refer to the public facing invoice number. + body (CreateInvoicePaymentRequest, optional): TODO: type + description here. Returns: - RecordPaymentResponse: Response from the API. OK + Invoice: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -768,11 +672,11 @@ def record_payment_for_subscription(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/payments.json') + .path('/invoices/{uid}/payments.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) + .key('uid') + .value(uid) .is_required(True) .should_encode(True)) .header_param(Parameter() @@ -788,7 +692,7 @@ def record_payment_for_subscription(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(RecordPaymentResponse.from_dictionary) + .deserialize_into(Invoice.from_dictionary) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() @@ -851,19 +755,45 @@ def reopen_invoice(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def void_invoice(self, - uid, - body=None): - """Does a POST request to /invoices/{uid}/void.json. + def issue_invoice(self, + uid, + body=None): + """Does a POST request to /invoices/{uid}/issue.json. - This endpoint allows you to void any invoice with the "open" or - "canceled" status. It will also allow voiding of an invoice with the - "pending" status if it is not a consolidated invoice. + This endpoint allows you to issue an invoice that is in "pending" + status. For example, you can issue an invoice that was created when + allocating new quantity on a component and using "accrue charges" + option. + You cannot issue a pending child invoice that was created for a member + subscription in a group. + For Remittance subscriptions, the invoice will go into "open" status + and payment won't be attempted. The value for `on_failed_payment` + would be rejected if sent. Any prepayments or service credits that + exist on subscription will be automatically applied. Additionally, if + setting is on, an email will be sent for issued invoice. + For Automatic subscriptions, prepayments and service credits will + apply to the invoice and before payment is attempted. On successful + payment, the invoice will go into "paid" status and email will be sent + to the customer (if setting applies). When payment fails, the next + event depends on the `on_failed_payment` value: + - `leave_open_invoice` - prepayments and credits applied to invoice; + invoice status set to "open"; email sent to the customer for the + issued invoice (if setting applies); payment failure recorded in the + invoice history. This is the default option. + - `rollback_to_pending` - prepayments and credits not applied; invoice + remains in "pending" status; no email sent to the customer; payment + failure recorded in the invoice history. + - `initiate_dunning` - prepayments and credits applied to the invoice; + invoice status set to "open"; email sent to the customer for the + issued invoice (if setting applies); payment failure recorded in the + invoice history; subscription will most likely go into "past_due" or + "canceled" state (depending upon net terms and dunning settings). Args: uid (str): The unique identifier for the invoice, this does not refer to the public facing invoice number. - body (VoidInvoiceRequest, optional): TODO: type description here. + body (IssueInvoiceRequest, optional): TODO: type description + here. Returns: Invoice: Response from the API. OK @@ -878,7 +808,7 @@ def void_invoice(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/invoices/{uid}/void.json') + .path('/invoices/{uid}/issue.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('uid') @@ -976,6 +906,45 @@ def list_consolidated_invoice_segments(self, .deserialize_into(ConsolidatedInvoice.from_dictionary) ).execute() + def read_credit_note(self, + uid): + """Does a GET request to /credit_notes/{uid}.json. + + Use this endpoint to retrieve the details for a credit note. + + Args: + uid (str): The unique identifier of the credit note + + Returns: + CreditNote: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/credit_notes/{uid}.json') + .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('uid') + .value(uid) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(CreditNote.from_dictionary) + ).execute() + def create_invoice(self, subscription_id, body=None): @@ -1249,23 +1218,79 @@ def send_invoice(self, .auth(Single('BasicAuth')) ).execute() - def preview_customer_information_changes(self, - uid): - """Does a POST request to /invoices/{uid}/customer_information/preview.json. + def record_payment_for_subscription(self, + subscription_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/payments.json. - Customer information may change after an invoice is issued which may - lead to a mismatch between customer information that are present on an - open invoice and actual customer information. This endpoint allows to - preview these differences, if any. - The endpoint doesn't accept a request body. Customer information - differences are calculated on the application side. + Record an external payment made against a subscription that will pay + partially or in full one or more invoices. + Payment will be applied starting with the oldest open invoice and then + next oldest, and so on until the amount of the payment is fully + consumed. + Excess payment will result in the creation of a prepayment on the + Invoice Account. + Only ungrouped or primary subscriptions may be paid using the "bulk" + payment request. + + Args: + subscription_id (int): The Chargify id of the subscription + body (RecordPaymentRequest, optional): TODO: type description + here. + + Returns: + RecordPaymentResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/payments.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(RecordPaymentResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + ).execute() + + def void_invoice(self, + uid, + body=None): + """Does a POST request to /invoices/{uid}/void.json. + + This endpoint allows you to void any invoice with the "open" or + "canceled" status. It will also allow voiding of an invoice with the + "pending" status if it is not a consolidated invoice. Args: uid (str): The unique identifier for the invoice, this does not refer to the public facing invoice number. + body (VoidInvoiceRequest, optional): TODO: type description here. Returns: - CustomerChangesPreviewResponse: Response from the API. OK + Invoice: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -1277,33 +1302,39 @@ def preview_customer_information_changes(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/invoices/{uid}/customer_information/preview.json') + .path('/invoices/{uid}/void.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('uid') .value(uid) .is_required(True) .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(CustomerChangesPreviewResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', ErrorListResponseException) + .deserialize_into(Invoice.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def update_customer_information(self, - uid): - """Does a PUT request to /invoices/{uid}/customer_information.json. + def preview_customer_information_changes(self, + uid): + """Does a POST request to /invoices/{uid}/customer_information/preview.json. - This endpoint updates customer information on an open invoice and - returns the updated invoice. If you would like to preview changes that - will be applied, use the - `/invoices/{uid}/customer_information/preview.json` endpoint before. + Customer information may change after an invoice is issued which may + lead to a mismatch between customer information that are present on an + open invoice and actual customer information. This endpoint allows to + preview these differences, if any. The endpoint doesn't accept a request body. Customer information differences are calculated on the application side. @@ -1312,7 +1343,7 @@ def update_customer_information(self, refer to the public facing invoice number. Returns: - Invoice: Response from the API. OK + CustomerChangesPreviewResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -1324,8 +1355,8 @@ def update_customer_information(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/invoices/{uid}/customer_information.json') - .http_method(HttpMethodEnum.PUT) + .path('/invoices/{uid}/customer_information/preview.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('uid') .value(uid) @@ -1338,50 +1369,25 @@ def update_customer_information(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(Invoice.from_dictionary) + .deserialize_into(CustomerChangesPreviewResponse.from_dictionary) .local_error_template('404', 'Not Found:\'{$response.body}\'', ErrorListResponseException) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def issue_invoice(self, - uid, - body=None): - """Does a POST request to /invoices/{uid}/issue.json. + def update_customer_information(self, + uid): + """Does a PUT request to /invoices/{uid}/customer_information.json. - This endpoint allows you to issue an invoice that is in "pending" - status. For example, you can issue an invoice that was created when - allocating new quantity on a component and using "accrue charges" - option. - You cannot issue a pending child invoice that was created for a member - subscription in a group. - For Remittance subscriptions, the invoice will go into "open" status - and payment won't be attempted. The value for `on_failed_payment` - would be rejected if sent. Any prepayments or service credits that - exist on subscription will be automatically applied. Additionally, if - setting is on, an email will be sent for issued invoice. - For Automatic subscriptions, prepayments and service credits will - apply to the invoice and before payment is attempted. On successful - payment, the invoice will go into "paid" status and email will be sent - to the customer (if setting applies). When payment fails, the next - event depends on the `on_failed_payment` value: - - `leave_open_invoice` - prepayments and credits applied to invoice; - invoice status set to "open"; email sent to the customer for the - issued invoice (if setting applies); payment failure recorded in the - invoice history. This is the default option. - - `rollback_to_pending` - prepayments and credits not applied; invoice - remains in "pending" status; no email sent to the customer; payment - failure recorded in the invoice history. - - `initiate_dunning` - prepayments and credits applied to the invoice; - invoice status set to "open"; email sent to the customer for the - issued invoice (if setting applies); payment failure recorded in the - invoice history; subscription will most likely go into "past_due" or - "canceled" state (depending upon net terms and dunning settings). + This endpoint updates customer information on an open invoice and + returns the updated invoice. If you would like to preview changes that + will be applied, use the + `/invoices/{uid}/customer_information/preview.json` endpoint before. + The endpoint doesn't accept a request body. Customer information + differences are calculated on the application side. Args: uid (str): The unique identifier for the invoice, this does not refer to the public facing invoice number. - body (IssueInvoiceRequest, optional): TODO: type description - here. Returns: Invoice: Response from the API. OK @@ -1396,27 +1402,21 @@ def issue_invoice(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/invoices/{uid}/issue.json') - .http_method(HttpMethodEnum.POST) + .path('/invoices/{uid}/customer_information.json') + .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('uid') .value(uid) .is_required(True) .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(Invoice.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('404', 'Not Found:\'{$response.body}\'', ErrorListResponseException) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() diff --git a/advancedbilling/controllers/offers_controller.py b/advancedbilling/controllers/offers_controller.py index 1b1c03b1..6bc75a8f 100644 --- a/advancedbilling/controllers/offers_controller.py +++ b/advancedbilling/controllers/offers_controller.py @@ -15,8 +15,8 @@ from apimatic_core.types.parameter import Parameter from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.authentication.multiple.single_auth import Single -from advancedbilling.models.offer_response import OfferResponse from advancedbilling.models.list_offers_response import ListOffersResponse +from advancedbilling.models.offer_response import OfferResponse from advancedbilling.exceptions.error_array_map_response_exception import ErrorArrayMapResponseException @@ -26,63 +26,6 @@ class OffersController(BaseController): def __init__(self, config): super(OffersController, self).__init__(config) - def create_offer(self, - body=None): - """Does a POST request to /offers.json. - - Create an offer within your Advanced Billing site by sending a POST - request. - ## Documentation - Offers allow you to package complicated combinations of products, - components and coupons into a convenient package which can then be - subscribed to just like products. - Once an offer is defined it can be used as an alternative to the - product when creating subscriptions. - Full documentation on how to use offers in the Advanced Billing UI can - be located - [here](https://maxio.zendesk.com/hc/en-us/articles/24261295098637-Offer - s-Overview). - ## Using a Product Price Point - You can optionally pass in a `product_price_point_id` that corresponds - with the `product_id` and the offer will use that price point. If a - `product_price_point_id` is not passed in, the product's default price - point will be used. - - Args: - body (CreateOfferRequest, optional): TODO: type description here. - - Returns: - OfferResponse: Response from the API. Created - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/offers.json') - .http_method(HttpMethodEnum.POST) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(OfferResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorArrayMapResponseException) - ).execute() - def list_offers(self, options=dict()): """Does a GET request to /offers.json. @@ -147,19 +90,18 @@ def list_offers(self, .deserialize_into(ListOffersResponse.from_dictionary) ).execute() - def read_offer(self, - offer_id): - """Does a GET request to /offers/{offer_id}.json. + def unarchive_offer(self, + offer_id): + """Does a PUT request to /offers/{offer_id}/unarchive.json. - This method allows you to list a specific offer's attributes. This is - different than list all offers for a site, as it requires an - `offer_id`. + Unarchive a previously archived offer. Please provide an `offer_id` in + order to un-archive the correct item. Args: offer_id (int): The Chargify id of the offer Returns: - OfferResponse: Response from the API. OK + void: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -171,35 +113,86 @@ def read_offer(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/offers/{offer_id}.json') - .http_method(HttpMethodEnum.GET) + .path('/offers/{offer_id}/unarchive.json') + .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('offer_id') .value(offer_id) .is_required(True) .should_encode(True)) + .auth(Single('BasicAuth')) + ).execute() + + def create_offer(self, + body=None): + """Does a POST request to /offers.json. + + Create an offer within your Advanced Billing site by sending a POST + request. + ## Documentation + Offers allow you to package complicated combinations of products, + components and coupons into a convenient package which can then be + subscribed to just like products. + Once an offer is defined it can be used as an alternative to the + product when creating subscriptions. + Full documentation on how to use offers in the Advanced Billing UI can + be located + [here](https://maxio.zendesk.com/hc/en-us/articles/24261295098637-Offer + s-Overview). + ## Using a Product Price Point + You can optionally pass in a `product_price_point_id` that corresponds + with the `product_id` and the offer will use that price point. If a + `product_price_point_id` is not passed in, the product's default price + point will be used. + + Args: + body (CreateOfferRequest, optional): TODO: type description here. + + Returns: + OfferResponse: Response from the API. Created + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/offers.json') + .http_method(HttpMethodEnum.POST) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(OfferResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorArrayMapResponseException) ).execute() - def archive_offer(self, - offer_id): - """Does a PUT request to /offers/{offer_id}/archive.json. + def read_offer(self, + offer_id): + """Does a GET request to /offers/{offer_id}.json. - Archive an existing offer. Please provide an `offer_id` in order to - archive the correct item. + This method allows you to list a specific offer's attributes. This is + different than list all offers for a site, as it requires an + `offer_id`. Args: offer_id (int): The Chargify id of the offer Returns: - void: Response from the API. OK + OfferResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -211,22 +204,29 @@ def archive_offer(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/offers/{offer_id}/archive.json') - .http_method(HttpMethodEnum.PUT) + .path('/offers/{offer_id}.json') + .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('offer_id') .value(offer_id) .is_required(True) .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(OfferResponse.from_dictionary) ).execute() - def unarchive_offer(self, - offer_id): - """Does a PUT request to /offers/{offer_id}/unarchive.json. + def archive_offer(self, + offer_id): + """Does a PUT request to /offers/{offer_id}/archive.json. - Unarchive a previously archived offer. Please provide an `offer_id` in - order to un-archive the correct item. + Archive an existing offer. Please provide an `offer_id` in order to + archive the correct item. Args: offer_id (int): The Chargify id of the offer @@ -244,7 +244,7 @@ def unarchive_offer(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/offers/{offer_id}/unarchive.json') + .path('/offers/{offer_id}/archive.json') .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('offer_id') diff --git a/advancedbilling/controllers/payment_profiles_controller.py b/advancedbilling/controllers/payment_profiles_controller.py index 38fa242c..f1be2512 100644 --- a/advancedbilling/controllers/payment_profiles_controller.py +++ b/advancedbilling/controllers/payment_profiles_controller.py @@ -16,10 +16,10 @@ from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.authentication.multiple.single_auth import Single from advancedbilling.models.payment_profile_response import PaymentProfileResponse -from advancedbilling.models.bank_account_response import BankAccountResponse from advancedbilling.models.get_one_time_token_request import GetOneTimeTokenRequest -from advancedbilling.exceptions.api_exception import APIException +from advancedbilling.models.bank_account_response import BankAccountResponse from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException +from advancedbilling.exceptions.api_exception import APIException from advancedbilling.exceptions.error_string_map_response_exception import ErrorStringMapResponseException @@ -29,6 +29,252 @@ class PaymentProfilesController(BaseController): def __init__(self, config): super(PaymentProfilesController, self).__init__(config) + def list_payment_profiles(self, + options=dict()): + """Does a GET request to /payment_profiles.json. + + This method will return all of the active `payment_profiles` for a + Site, or for one Customer within a site. If no payment profiles are + found, this endpoint will return an empty array, not a 404. + + Args: + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + 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 + 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`. + per_page -- int -- 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`. + customer_id -- int -- The ID of the customer for which you + wish to list payment profiles + + Returns: + List[PaymentProfileResponse]: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/payment_profiles.json') + .http_method(HttpMethodEnum.GET) + .query_param(Parameter() + .key('page') + .value(options.get('page', None))) + .query_param(Parameter() + .key('per_page') + .value(options.get('per_page', None))) + .query_param(Parameter() + .key('customer_id') + .value(options.get('customer_id', None))) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(PaymentProfileResponse.from_dictionary) + ).execute() + + def change_subscription_group_default_payment_profile(self, + uid, + payment_profile_id): + """Does a POST request to /subscription_groups/{uid}/payment_profiles/{payment_profile_id}/change_payment_profile.json. + + This will change the default payment profile on the subscription group + to the existing payment profile with the id specified. + You must elect to change the existing payment profile to a new payment + profile ID in order to receive a satisfactory response from this + endpoint. + The new payment profile must belong to the subscription group's + customer, otherwise you will receive an error. + + Args: + uid (str): The uid of the subscription group + payment_profile_id (int): The Chargify id of the payment profile + + Returns: + PaymentProfileResponse: Response from the API. Created + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscription_groups/{uid}/payment_profiles/{payment_profile_id}/change_payment_profile.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('uid') + .value(uid) + .is_required(True) + .should_encode(True)) + .template_param(Parameter() + .key('payment_profile_id') + .value(payment_profile_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(PaymentProfileResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + ).execute() + + def read_one_time_token(self, + chargify_token): + """Does a GET request to /one_time_tokens/{chargify_token}.json. + + One Time Tokens aka Advanced Billing Tokens house the credit card or + ACH (Authorize.Net or Stripe only) data for a customer. + You can use One Time Tokens while creating a subscription or payment + profile instead of passing all bank account or credit card data + directly to a given API endpoint. + To obtain a One Time Token you have to use + [Chargify.js](https://developers.chargify.com/docs/developer-docs/ZG9jO + jE0NjAzNDI0-overview). + + Args: + chargify_token (str): Advanced Billing Token + + Returns: + GetOneTimeTokenRequest: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/one_time_tokens/{chargify_token}.json') + .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('chargify_token') + .value(chargify_token) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(GetOneTimeTokenRequest.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', ErrorListResponseException) + ).execute() + + def send_request_update_payment_email(self, + subscription_id): + """Does a POST request to /subscriptions/{subscription_id}/request_payment_profiles_update.json. + + You can send a "request payment update" email to the customer + associated with the subscription. + If you attempt to send a "request payment update" email more than five + times within a 30-minute period, you will receive a `422` response + with an error message in the body. This error message will indicate + that the request has been rejected due to excessive attempts, and will + provide instructions on how to resubmit the request. + Additionally, if you attempt to send a "request payment update" email + for a subscription that does not exist, you will receive a `404` error + response. This error message will indicate that the subscription could + not be found, and will provide instructions on how to correct the + error and resubmit the request. + These error responses are designed to prevent excessive or invalid + requests, and to provide clear and helpful information to users who + encounter errors during the request process. + + Args: + subscription_id (int): The Chargify id of the subscription + + Returns: + void: Response from the API. Created + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/request_payment_profiles_update.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .auth(Single('BasicAuth')) + ).execute() + + def delete_unused_payment_profile(self, + payment_profile_id): + """Does a DELETE request to /payment_profiles/{payment_profile_id}.json. + + Deletes an unused payment profile. + If the payment profile is in use by one or more subscriptions or + groups, a 422 and error message will be returned. + + Args: + payment_profile_id (int): The Chargify id of the payment profile + + Returns: + void: Response from the API. No Content + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/payment_profiles/{payment_profile_id}.json') + .http_method(HttpMethodEnum.DELETE) + .template_param(Parameter() + .key('payment_profile_id') + .value(payment_profile_id) + .is_required(True) + .should_encode(True)) + .auth(Single('BasicAuth')) + ).execute() + def create_payment_profile(self, body=None): """Does a POST request to /payment_profiles.json. @@ -400,72 +646,6 @@ def create_payment_profile(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def list_payment_profiles(self, - options=dict()): - """Does a GET request to /payment_profiles.json. - - This method will return all of the active `payment_profiles` for a - Site, or for one Customer within a site. If no payment profiles are - found, this endpoint will return an empty array, not a 404. - - Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - 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 - 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`. - per_page -- int -- 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`. - customer_id -- int -- The ID of the customer for which you - wish to list payment profiles - - Returns: - List[PaymentProfileResponse]: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/payment_profiles.json') - .http_method(HttpMethodEnum.GET) - .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) - .query_param(Parameter() - .key('customer_id') - .value(options.get('customer_id', None))) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(PaymentProfileResponse.from_dictionary) - ).execute() - def read_payment_profile(self, payment_profile_id): """Does a GET request to /payment_profiles/{payment_profile_id}.json. @@ -629,40 +809,6 @@ def update_payment_profile(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorStringMapResponseException) ).execute() - def delete_unused_payment_profile(self, - payment_profile_id): - """Does a DELETE request to /payment_profiles/{payment_profile_id}.json. - - Deletes an unused payment profile. - If the payment profile is in use by one or more subscriptions or - groups, a 422 and error message will be returned. - - Args: - payment_profile_id (int): The Chargify id of the payment profile - - Returns: - void: Response from the API. No Content - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/payment_profiles/{payment_profile_id}.json') - .http_method(HttpMethodEnum.DELETE) - .template_param(Parameter() - .key('payment_profile_id') - .value(payment_profile_id) - .is_required(True) - .should_encode(True)) - .auth(Single('BasicAuth')) - ).execute() - def delete_subscriptions_payment_profile(self, subscription_id, payment_profile_id): @@ -856,149 +1002,3 @@ def change_subscription_default_payment_profile(self, .local_error('404', 'Not Found', APIException) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - - def change_subscription_group_default_payment_profile(self, - uid, - payment_profile_id): - """Does a POST request to /subscription_groups/{uid}/payment_profiles/{payment_profile_id}/change_payment_profile.json. - - This will change the default payment profile on the subscription group - to the existing payment profile with the id specified. - You must elect to change the existing payment profile to a new payment - profile ID in order to receive a satisfactory response from this - endpoint. - The new payment profile must belong to the subscription group's - customer, otherwise you will receive an error. - - Args: - uid (str): The uid of the subscription group - payment_profile_id (int): The Chargify id of the payment profile - - Returns: - PaymentProfileResponse: Response from the API. Created - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/{uid}/payment_profiles/{payment_profile_id}/change_payment_profile.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('uid') - .value(uid) - .is_required(True) - .should_encode(True)) - .template_param(Parameter() - .key('payment_profile_id') - .value(payment_profile_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(PaymentProfileResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) - ).execute() - - def read_one_time_token(self, - chargify_token): - """Does a GET request to /one_time_tokens/{chargify_token}.json. - - One Time Tokens aka Advanced Billing Tokens house the credit card or - ACH (Authorize.Net or Stripe only) data for a customer. - You can use One Time Tokens while creating a subscription or payment - profile instead of passing all bank account or credit card data - directly to a given API endpoint. - To obtain a One Time Token you have to use - [Chargify.js](https://developers.chargify.com/docs/developer-docs/ZG9jO - jE0NjAzNDI0-overview). - - Args: - chargify_token (str): Advanced Billing Token - - Returns: - GetOneTimeTokenRequest: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/one_time_tokens/{chargify_token}.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('chargify_token') - .value(chargify_token) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(GetOneTimeTokenRequest.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', ErrorListResponseException) - ).execute() - - def send_request_update_payment_email(self, - subscription_id): - """Does a POST request to /subscriptions/{subscription_id}/request_payment_profiles_update.json. - - You can send a "request payment update" email to the customer - associated with the subscription. - If you attempt to send a "request payment update" email more than five - times within a 30-minute period, you will receive a `422` response - with an error message in the body. This error message will indicate - that the request has been rejected due to excessive attempts, and will - provide instructions on how to resubmit the request. - Additionally, if you attempt to send a "request payment update" email - for a subscription that does not exist, you will receive a `404` error - response. This error message will indicate that the subscription could - not be found, and will provide instructions on how to correct the - error and resubmit the request. - These error responses are designed to prevent excessive or invalid - requests, and to provide clear and helpful information to users who - encounter errors during the request process. - - Args: - subscription_id (int): The Chargify id of the subscription - - Returns: - void: Response from the API. Created - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/request_payment_profiles_update.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .auth(Single('BasicAuth')) - ).execute() diff --git a/advancedbilling/controllers/product_families_controller.py b/advancedbilling/controllers/product_families_controller.py index cbf4a002..9d05e7a2 100644 --- a/advancedbilling/controllers/product_families_controller.py +++ b/advancedbilling/controllers/product_families_controller.py @@ -152,6 +152,49 @@ def list_products_for_product_family(self, .local_error('404', 'Not Found', APIException) ).execute() + 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. + The product family can be specified either with the id number, or with + the `handle:my-family` format. + + Args: + id (int): The Advanced Billing id of the product family + + Returns: + ProductFamilyResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/product_families/{id}.json') + .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('id') + .value(id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(ProductFamilyResponse.from_dictionary) + ).execute() + def create_product_family(self, body=None): """Does a POST request to /product_families.json. @@ -278,46 +321,3 @@ def list_product_families(self, .deserializer(APIHelper.json_deserialize) .deserialize_into(ProductFamilyResponse.from_dictionary) ).execute() - - 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. - The product family can be specified either with the id number, or with - the `handle:my-family` format. - - Args: - id (int): The Advanced Billing id of the product family - - Returns: - ProductFamilyResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/product_families/{id}.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('id') - .value(id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(ProductFamilyResponse.from_dictionary) - ).execute() diff --git a/advancedbilling/controllers/product_price_points_controller.py b/advancedbilling/controllers/product_price_points_controller.py index 81547710..b787128e 100644 --- a/advancedbilling/controllers/product_price_points_controller.py +++ b/advancedbilling/controllers/product_price_points_controller.py @@ -19,13 +19,13 @@ from apimatic_core.authentication.multiple.single_auth import Single from advancedbilling.models.product_price_point_response import ProductPricePointResponse from advancedbilling.models.list_product_price_points_response import ListProductPricePointsResponse -from advancedbilling.models.product_response import ProductResponse -from advancedbilling.models.bulk_create_product_price_points_response import BulkCreateProductPricePointsResponse from advancedbilling.models.currency_prices_response import CurrencyPricesResponse +from advancedbilling.models.bulk_create_product_price_points_response import BulkCreateProductPricePointsResponse +from advancedbilling.models.product_response import ProductResponse +from advancedbilling.exceptions.error_array_map_response_exception import ErrorArrayMapResponseException from advancedbilling.exceptions.product_price_point_error_response_exception import ProductPricePointErrorResponseException -from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException from advancedbilling.exceptions.api_exception import APIException -from advancedbilling.exceptions.error_array_map_response_exception import ErrorArrayMapResponseException +from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException class ProductPricePointsController(BaseController): @@ -34,23 +34,21 @@ class ProductPricePointsController(BaseController): def __init__(self, config): super(ProductPricePointsController, self).__init__(config) - def create_product_price_point(self, - product_id, - body=None): - """Does a POST request to /products/{product_id}/price_points.json. + def unarchive_product_price_point(self, + product_id, + price_point_id): + """Does a PATCH request to /products/{product_id}/price_points/{price_point_id}/unarchive.json. - [Product Price Point - Documentation](https://maxio.zendesk.com/hc/en-us/articles/242611119477 - 89-Product-Price-Points) + Use this endpoint to unarchive an archived product price point. Args: - product_id (int | str): The id or handle of the product. When - using the handle, it must be prefixed with `handle:` - body (CreateProductPricePointRequest, optional): TODO: type - description here. + product_id (int): The Advanced Billing id of the product to which + the price point belongs + price_point_id (int): The Advanced Billing id of the product price + point Returns: - ProductPricePointResponse: Response from the API. Created + ProductPricePointResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -62,29 +60,26 @@ def create_product_price_point(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/products/{product_id}/price_points.json') - .http_method(HttpMethodEnum.POST) + .path('/products/{product_id}/price_points/{price_point_id}/unarchive.json') + .http_method(HttpMethodEnum.PATCH) .template_param(Parameter() .key('product_id') .value(product_id) .is_required(True) - .should_encode(True) - .validator(lambda value: UnionTypeLookUp.get('CreateProductPricePointProductId').validate(value))) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) + .should_encode(True)) + .template_param(Parameter() + .key('price_point_id') + .value(price_point_id) + .is_required(True) + .should_encode(True)) .header_param(Parameter() .key('accept') .value('application/json')) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(ProductPricePointResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ProductPricePointErrorResponseException) ).execute() def list_product_price_points(self, @@ -172,71 +167,6 @@ def list_product_price_points(self, .deserialize_into(ListProductPricePointsResponse.from_dictionary) ).execute() - def update_product_price_point(self, - product_id, - price_point_id, - 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. - - Args: - product_id (int | str): The id or handle of the product. When - using the handle, it must be prefixed with `handle:`. Example: - `123` for an integer ID, or `handle:example-product-handle` - for a string handle. - price_point_id (int | str): The id or handle of the price point. - When using the handle, it must be prefixed with `handle:`. - Example: `123` for an integer ID, or - `handle:example-product-price-point-handle` for a string - handle. - body (UpdateProductPricePointRequest, optional): TODO: type - description here. - - Returns: - ProductPricePointResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/products/{product_id}/price_points/{price_point_id}.json') - .http_method(HttpMethodEnum.PUT) - .template_param(Parameter() - .key('product_id') - .value(product_id) - .is_required(True) - .should_encode(True) - .validator(lambda value: UnionTypeLookUp.get('UpdateProductPricePointProductId').validate(value))) - .template_param(Parameter() - .key('price_point_id') - .value(price_point_id) - .is_required(True) - .should_encode(True) - .validator(lambda value: UnionTypeLookUp.get('UpdateProductPricePointPricePointId').validate(value))) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(ProductPricePointResponse.from_dictionary) - ).execute() - def read_product_price_point(self, product_id, price_point_id, @@ -306,26 +236,28 @@ def read_product_price_point(self, .deserialize_into(ProductPricePointResponse.from_dictionary) ).execute() - def archive_product_price_point(self, - product_id, - price_point_id): - """Does a DELETE request to /products/{product_id}/price_points/{price_point_id}.json. + def create_product_currency_prices(self, + product_price_point_id, + body=None): + """Does a POST request to /product_price_points/{product_price_point_id}/currency_prices.json. - Use this endpoint to archive a product price point. + This endpoint allows you to create 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. + Note: Currency Prices are not able to be created for custom product + price points. Args: - product_id (int | str): The id or handle of the product. When - using the handle, it must be prefixed with `handle:`. Example: - `123` for an integer ID, or `handle:example-product-handle` - for a string handle. - price_point_id (int | str): The id or handle of the price point. - When using the handle, it must be prefixed with `handle:`. - Example: `123` for an integer ID, or - `handle:example-product-price-point-handle` for a string - handle. + product_price_point_id (int): The Advanced Billing id of the + product price point + body (CreateProductCurrencyPricesRequest, optional): TODO: type + description here. Returns: - ProductPricePointResponse: Response from the API. OK + CurrencyPricesResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -337,97 +269,47 @@ def archive_product_price_point(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/products/{product_id}/price_points/{price_point_id}.json') - .http_method(HttpMethodEnum.DELETE) - .template_param(Parameter() - .key('product_id') - .value(product_id) - .is_required(True) - .should_encode(True) - .validator(lambda value: UnionTypeLookUp.get('ArchiveProductPricePointProductId').validate(value))) + .path('/product_price_points/{product_price_point_id}/currency_prices.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() - .key('price_point_id') - .value(price_point_id) + .key('product_price_point_id') + .value(product_price_point_id) .is_required(True) - .should_encode(True) - .validator(lambda value: UnionTypeLookUp.get('ArchiveProductPricePointPricePointId').validate(value))) + .should_encode(True)) .header_param(Parameter() - .key('accept') + .key('Content-Type') .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(ProductPricePointResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) - ).execute() - - def unarchive_product_price_point(self, - product_id, - price_point_id): - """Does a PATCH request to /products/{product_id}/price_points/{price_point_id}/unarchive.json. - - Use this endpoint to unarchive an archived product price point. - - Args: - product_id (int): The Advanced Billing id of the product to which - the price point belongs - price_point_id (int): The Advanced Billing id of the product price - point - - Returns: - ProductPricePointResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/products/{product_id}/price_points/{price_point_id}/unarchive.json') - .http_method(HttpMethodEnum.PATCH) - .template_param(Parameter() - .key('product_id') - .value(product_id) - .is_required(True) - .should_encode(True)) - .template_param(Parameter() - .key('price_point_id') - .value(price_point_id) - .is_required(True) - .should_encode(True)) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ProductPricePointResponse.from_dictionary) + .deserialize_into(CurrencyPricesResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorArrayMapResponseException) ).execute() - def promote_product_price_point_to_default(self, - product_id, - price_point_id): - """Does a PATCH request to /products/{product_id}/price_points/{price_point_id}/default.json. + def create_product_price_point(self, + product_id, + body=None): + """Does a POST request to /products/{product_id}/price_points.json. - Use this endpoint to make a product price point the default for the - product. - Note: Custom product price points are not able to be set as the - default for a product. + [Product Price Point + Documentation](https://maxio.zendesk.com/hc/en-us/articles/242611119477 + 89-Product-Price-Points) Args: - product_id (int): The Advanced Billing id of the product to which - the price point belongs - price_point_id (int): The Advanced Billing id of the product price - point + product_id (int | str): The id or handle of the product. When + using the handle, it must be prefixed with `handle:` + body (CreateProductPricePointRequest, optional): TODO: type + description here. Returns: - ProductResponse: Response from the API. OK + ProductPricePointResponse: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -439,26 +321,29 @@ def promote_product_price_point_to_default(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/products/{product_id}/price_points/{price_point_id}/default.json') - .http_method(HttpMethodEnum.PATCH) + .path('/products/{product_id}/price_points.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('product_id') .value(product_id) .is_required(True) - .should_encode(True)) - .template_param(Parameter() - .key('price_point_id') - .value(price_point_id) - .is_required(True) - .should_encode(True)) + .should_encode(True) + .validator(lambda value: UnionTypeLookUp.get('CreateProductPricePointProductId').validate(value))) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ProductResponse.from_dictionary) + .deserialize_into(ProductPricePointResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ProductPricePointErrorResponseException) ).execute() def bulk_create_product_price_points(self, @@ -513,24 +398,23 @@ def bulk_create_product_price_points(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', APIException) ).execute() - def create_product_currency_prices(self, + def update_product_currency_prices(self, product_price_point_id, body=None): - """Does a POST request to /product_price_points/{product_price_point_id}/currency_prices.json. + """Does a PUT 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. - 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. - Note: Currency Prices are not able to be created for custom product + This endpoint allows you to update 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. Args: product_price_point_id (int): The Advanced Billing id of the product price point - body (CreateProductCurrencyPricesRequest, optional): TODO: type + body (UpdateCurrencyPricesRequest, optional): TODO: type description here. Returns: @@ -547,7 +431,7 @@ def create_product_currency_prices(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/product_price_points/{product_price_point_id}/currency_prices.json') - .http_method(HttpMethodEnum.POST) + .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('product_price_point_id') .value(product_price_point_id) @@ -570,27 +454,30 @@ def create_product_currency_prices(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorArrayMapResponseException) ).execute() - def update_product_currency_prices(self, - product_price_point_id, - body=None): - """Does a PUT request to /product_price_points/{product_price_point_id}/currency_prices.json. + def update_product_price_point(self, + product_id, + price_point_id, + body=None): + """Does a PUT request to /products/{product_id}/price_points/{price_point_id}.json. - This endpoint allows you to update 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. + Use this endpoint to update a product price point. + Note: Custom product price points are not able to be updated. Args: - product_price_point_id (int): The Advanced Billing id of the - product price point - body (UpdateCurrencyPricesRequest, optional): TODO: type + product_id (int | str): The id or handle of the product. When + using the handle, it must be prefixed with `handle:`. Example: + `123` for an integer ID, or `handle:example-product-handle` + for a string handle. + price_point_id (int | str): The id or handle of the price point. + When using the handle, it must be prefixed with `handle:`. + Example: `123` for an integer ID, or + `handle:example-product-price-point-handle` for a string + handle. + body (UpdateProductPricePointRequest, optional): TODO: type description here. Returns: - CurrencyPricesResponse: Response from the API. OK + ProductPricePointResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -602,13 +489,20 @@ def update_product_currency_prices(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/product_price_points/{product_price_point_id}/currency_prices.json') + .path('/products/{product_id}/price_points/{price_point_id}.json') .http_method(HttpMethodEnum.PUT) .template_param(Parameter() - .key('product_price_point_id') - .value(product_price_point_id) + .key('product_id') + .value(product_id) .is_required(True) - .should_encode(True)) + .should_encode(True) + .validator(lambda value: UnionTypeLookUp.get('UpdateProductPricePointProductId').validate(value))) + .template_param(Parameter() + .key('price_point_id') + .value(price_point_id) + .is_required(True) + .should_encode(True) + .validator(lambda value: UnionTypeLookUp.get('UpdateProductPricePointPricePointId').validate(value))) .header_param(Parameter() .key('Content-Type') .value('application/json')) @@ -622,8 +516,114 @@ def update_product_currency_prices(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(CurrencyPricesResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorArrayMapResponseException) + .deserialize_into(ProductPricePointResponse.from_dictionary) + ).execute() + + def archive_product_price_point(self, + product_id, + 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. + + Args: + product_id (int | str): The id or handle of the product. When + using the handle, it must be prefixed with `handle:`. Example: + `123` for an integer ID, or `handle:example-product-handle` + for a string handle. + price_point_id (int | str): The id or handle of the price point. + When using the handle, it must be prefixed with `handle:`. + Example: `123` for an integer ID, or + `handle:example-product-price-point-handle` for a string + handle. + + Returns: + ProductPricePointResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/products/{product_id}/price_points/{price_point_id}.json') + .http_method(HttpMethodEnum.DELETE) + .template_param(Parameter() + .key('product_id') + .value(product_id) + .is_required(True) + .should_encode(True) + .validator(lambda value: UnionTypeLookUp.get('ArchiveProductPricePointProductId').validate(value))) + .template_param(Parameter() + .key('price_point_id') + .value(price_point_id) + .is_required(True) + .should_encode(True) + .validator(lambda value: UnionTypeLookUp.get('ArchiveProductPricePointPricePointId').validate(value))) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(ProductPricePointResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + ).execute() + + def promote_product_price_point_to_default(self, + product_id, + 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 + 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 + the price point belongs + price_point_id (int): The Advanced Billing id of the product price + point + + Returns: + ProductResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/products/{product_id}/price_points/{price_point_id}/default.json') + .http_method(HttpMethodEnum.PATCH) + .template_param(Parameter() + .key('product_id') + .value(product_id) + .is_required(True) + .should_encode(True)) + .template_param(Parameter() + .key('price_point_id') + .value(price_point_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(ProductResponse.from_dictionary) ).execute() def list_all_product_price_points(self, diff --git a/advancedbilling/controllers/products_controller.py b/advancedbilling/controllers/products_controller.py index 62c8b0b0..55406433 100644 --- a/advancedbilling/controllers/products_controller.py +++ b/advancedbilling/controllers/products_controller.py @@ -83,46 +83,6 @@ def create_product(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - 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. - - Args: - product_id (int): The Advanced Billing id of the product - - Returns: - ProductResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/products/{product_id}.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('product_id') - .value(product_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(ProductResponse.from_dictionary) - ).execute() - def update_product(self, product_id, body=None): @@ -264,6 +224,46 @@ def read_product_by_handle(self, .deserialize_into(ProductResponse.from_dictionary) ).execute() + 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. + + Args: + product_id (int): The Advanced Billing id of the product + + Returns: + ProductResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/products/{product_id}.json') + .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('product_id') + .value(product_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(ProductResponse.from_dictionary) + ).execute() + def list_products(self, options=dict()): """Does a GET request to /products.json. diff --git a/advancedbilling/controllers/proforma_invoices_controller.py b/advancedbilling/controllers/proforma_invoices_controller.py index 38d405b6..feea299a 100644 --- a/advancedbilling/controllers/proforma_invoices_controller.py +++ b/advancedbilling/controllers/proforma_invoices_controller.py @@ -15,8 +15,8 @@ from apimatic_core.types.parameter import Parameter from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.authentication.multiple.single_auth import Single -from advancedbilling.models.list_proforma_invoices_response import ListProformaInvoicesResponse from advancedbilling.models.proforma_invoice import ProformaInvoice +from advancedbilling.models.list_proforma_invoices_response import ListProformaInvoicesResponse from advancedbilling.models.signup_proforma_preview_response import SignupProformaPreviewResponse from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException from advancedbilling.exceptions.api_exception import APIException @@ -73,35 +73,26 @@ def create_consolidated_proforma_invoice(self, .auth(Single('BasicAuth')) ).execute() - def list_subscription_group_proforma_invoices(self, - options=dict()): - """Does a GET request to /subscription_groups/{uid}/proforma_invoices.json. + def create_proforma_invoice(self, + subscription_id): + """Does a POST request to /subscriptions/{subscription_id}/proforma_invoices.json. - Only proforma invoices with a `consolidation_level` of parent are - returned. - By default, proforma invoices returned on the index will only include - totals, not detailed breakdowns for `line_items`, `discounts`, - `taxes`, `credits`, `payments`, `custom_fields`. To include - breakdowns, pass the specific field as a key in the query with a value - set to true. + 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. + ## Restrictions + Proforma invoices are only available on Relationship Invoicing sites. + To create a proforma invoice, the subscription must not be in a group, + must not be prepaid, and must be in a live state. Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - uid -- str -- The uid of the subscription group - line_items -- bool -- Include line items data - discounts -- bool -- Include discounts data - taxes -- bool -- Include taxes data - credits -- bool -- Include credits data - payments -- bool -- Include payments data - custom_fields -- bool -- Include custom fields data + subscription_id (int): The Chargify id of the subscription Returns: - ListProformaInvoicesResponse: Response from the API. OK + ProformaInvoice: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -113,31 +104,13 @@ def list_subscription_group_proforma_invoices(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/{uid}/proforma_invoices.json') - .http_method(HttpMethodEnum.GET) + .path('/subscriptions/{subscription_id}/proforma_invoices.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() - .key('uid') - .value(options.get('uid', None)) + .key('subscription_id') + .value(subscription_id) .is_required(True) .should_encode(True)) - .query_param(Parameter() - .key('line_items') - .value(options.get('line_items', None))) - .query_param(Parameter() - .key('discounts') - .value(options.get('discounts', None))) - .query_param(Parameter() - .key('taxes') - .value(options.get('taxes', None))) - .query_param(Parameter() - .key('credits') - .value(options.get('credits', None))) - .query_param(Parameter() - .key('payments') - .value(options.get('payments', None))) - .query_param(Parameter() - .key('custom_fields') - .value(options.get('custom_fields', None))) .header_param(Parameter() .key('accept') .value('application/json')) @@ -145,21 +118,34 @@ def list_subscription_group_proforma_invoices(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ListProformaInvoicesResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .deserialize_into(ProformaInvoice.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def read_proforma_invoice(self, - proforma_invoice_uid): - """Does a GET request to /proforma_invoices/{proforma_invoice_uid}.json. + def preview_proforma_invoice(self, + subscription_id): + """Does a POST request to /subscriptions/{subscription_id}/proforma_invoices/preview.json. - Use this endpoint to read the details of an existing proforma - invoice. - ## Restrictions - Proforma invoices are only available on Relationship Invoicing sites. + Return a preview of the data that will be included on a given + subscription's proforma invoice if one were to be generated. It will + have similar line items and totals as a renewal preview, but the + response will be presented in the format of a proforma invoice. + Consequently it will include additional information such as the name + and addresses that will appear on the proforma invoice. + The preview endpoint is subject to all the same conditions as the + proforma invoice endpoint. For example, previews are only available on + the Relationship Invoicing architecture, and previews cannot be made + for end-of-life subscriptions. + If all the data returned in the preview is as expected, you may then + create a static proforma invoice and send it to your customer. The + data within a preview will not be saved and will not be accessible + after the call is made. + Alternatively, if you have some proforma invoices already, you may + make a preview call to determine whether any billing information for + the subscription's upcoming renewal has changed. Args: - proforma_invoice_uid (str): The uid of the proforma invoice + subscription_id (int): The Chargify id of the subscription Returns: ProformaInvoice: Response from the API. OK @@ -174,11 +160,11 @@ def read_proforma_invoice(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/proforma_invoices/{proforma_invoice_uid}.json') - .http_method(HttpMethodEnum.GET) + .path('/subscriptions/{subscription_id}/proforma_invoices/preview.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() - .key('proforma_invoice_uid') - .value(proforma_invoice_uid) + .key('subscription_id') + .value(subscription_id) .is_required(True) .should_encode(True)) .header_param(Parameter() @@ -190,25 +176,20 @@ def read_proforma_invoice(self, .deserializer(APIHelper.json_deserialize) .deserialize_into(ProformaInvoice.from_dictionary) .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def create_proforma_invoice(self, - subscription_id): - """Does a POST request to /subscriptions/{subscription_id}/proforma_invoices.json. + def read_proforma_invoice(self, + proforma_invoice_uid): + """Does a GET request to /proforma_invoices/{proforma_invoice_uid}.json. - 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. + Use this endpoint to read the details of an existing proforma + invoice. ## Restrictions Proforma invoices are only available on Relationship Invoicing sites. - To create a proforma invoice, the subscription must not be in a group, - must not be prepaid, and must be in a live state. Args: - subscription_id (int): The Chargify id of the subscription + proforma_invoice_uid (str): The uid of the proforma invoice Returns: ProformaInvoice: Response from the API. OK @@ -223,11 +204,11 @@ def create_proforma_invoice(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/proforma_invoices.json') - .http_method(HttpMethodEnum.POST) + .path('/proforma_invoices/{proforma_invoice_uid}.json') + .http_method(HttpMethodEnum.GET) .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) + .key('proforma_invoice_uid') + .value(proforma_invoice_uid) .is_required(True) .should_encode(True)) .header_param(Parameter() @@ -238,7 +219,7 @@ def create_proforma_invoice(self, ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(ProformaInvoice.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) ).execute() def list_proforma_invoices(self, @@ -356,29 +337,34 @@ def list_proforma_invoices(self, .deserialize_into(ListProformaInvoicesResponse.from_dictionary) ).execute() - def void_proforma_invoice(self, - proforma_invoice_uid, - body=None): - """Does a POST request to /proforma_invoices/{proforma_invoice_uid}/void.json. + def preview_signup_proforma_invoice(self, + include=None, + body=None): + """Does a POST request to /subscriptions/proforma_invoices/preview.json. - This endpoint will void a proforma invoice that has the status - "draft". - ## Restrictions - Proforma invoices are only available on Relationship Invoicing sites. - Only proforma invoices that have the appropriate status may be - reopened. If the invoice identified by {uid} does not have the - appropriate status, the response will have HTTP status code 422 and an - error message. - A reason for the void operation is required to be included in the - request body. If one is not provided, the response will have HTTP - status code 422 and an error message. + This endpoint is only available for Relationship Invoicing sites. It + cannot be used to create consolidated proforma invoice previews or + preview prepaid subscriptions. + Create a signup preview in the format of a proforma invoice to preview + costs before a subscription's signup. You have the option of + optionally previewing the first renewal's costs as well. The proforma + invoice preview will not be persisted. + Pass a payload that resembles a subscription create or signup preview + request. For example, you can specify components, coupons/a referral, + offers, custom pricing, and an existing customer or payment profile to + populate a shipping or billing address. + A product and customer first name, last name, and email are the + minimum requirements. Args: - proforma_invoice_uid (str): The uid of the proforma invoice - body (VoidInvoiceRequest, optional): TODO: type description here. + include (CreateSignupProformaPreviewInclude, optional): Choose to + include a proforma invoice preview for the first renewal. Use + in query `include=next_proforma_invoice`. + body (CreateSubscriptionRequest, optional): TODO: type description + here. Returns: - ProformaInvoice: Response from the API. OK + SignupProformaPreviewResponse: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -390,16 +376,14 @@ def void_proforma_invoice(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/proforma_invoices/{proforma_invoice_uid}/void.json') + .path('/subscriptions/proforma_invoices/preview.json') .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('proforma_invoice_uid') - .value(proforma_invoice_uid) - .is_required(True) - .should_encode(True)) .header_param(Parameter() .key('Content-Type') .value('application/json')) + .query_param(Parameter() + .key('include') + .value(include)) .body_param(Parameter() .value(body)) .header_param(Parameter() @@ -410,38 +394,40 @@ def void_proforma_invoice(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ProformaInvoice.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + .deserialize_into(SignupProformaPreviewResponse.from_dictionary) + .local_error_template('400', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ProformaBadRequestErrorResponseException) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorArrayMapResponseException) ).execute() - def preview_proforma_invoice(self, - subscription_id): - """Does a POST request to /subscriptions/{subscription_id}/proforma_invoices/preview.json. + def list_subscription_group_proforma_invoices(self, + options=dict()): + """Does a GET request to /subscription_groups/{uid}/proforma_invoices.json. - Return a preview of the data that will be included on a given - subscription's proforma invoice if one were to be generated. It will - have similar line items and totals as a renewal preview, but the - response will be presented in the format of a proforma invoice. - Consequently it will include additional information such as the name - and addresses that will appear on the proforma invoice. - The preview endpoint is subject to all the same conditions as the - proforma invoice endpoint. For example, previews are only available on - the Relationship Invoicing architecture, and previews cannot be made - for end-of-life subscriptions. - If all the data returned in the preview is as expected, you may then - create a static proforma invoice and send it to your customer. The - data within a preview will not be saved and will not be accessible - after the call is made. - Alternatively, if you have some proforma invoices already, you may - make a preview call to determine whether any billing information for - the subscription's upcoming renewal has changed. + Only proforma invoices with a `consolidation_level` of parent are + returned. + By default, proforma invoices returned on the index will only include + totals, not detailed breakdowns for `line_items`, `discounts`, + `taxes`, `credits`, `payments`, `custom_fields`. To include + breakdowns, pass the specific field as a key in the query with a value + set to true. Args: - subscription_id (int): The Chargify id of the subscription + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + uid -- str -- The uid of the subscription group + line_items -- bool -- Include line items data + discounts -- bool -- Include discounts data + taxes -- bool -- Include taxes data + credits -- bool -- Include credits data + payments -- bool -- Include payments data + custom_fields -- bool -- Include custom fields data Returns: - ProformaInvoice: Response from the API. OK + ListProformaInvoicesResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -453,13 +439,31 @@ def preview_proforma_invoice(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/proforma_invoices/preview.json') - .http_method(HttpMethodEnum.POST) + .path('/subscription_groups/{uid}/proforma_invoices.json') + .http_method(HttpMethodEnum.GET) .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) + .key('uid') + .value(options.get('uid', None)) .is_required(True) .should_encode(True)) + .query_param(Parameter() + .key('line_items') + .value(options.get('line_items', None))) + .query_param(Parameter() + .key('discounts') + .value(options.get('discounts', None))) + .query_param(Parameter() + .key('taxes') + .value(options.get('taxes', None))) + .query_param(Parameter() + .key('credits') + .value(options.get('credits', None))) + .query_param(Parameter() + .key('payments') + .value(options.get('payments', None))) + .query_param(Parameter() + .key('custom_fields') + .value(options.get('custom_fields', None))) .header_param(Parameter() .key('accept') .value('application/json')) @@ -467,36 +471,33 @@ def preview_proforma_invoice(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ProformaInvoice.from_dictionary) + .deserialize_into(ListProformaInvoicesResponse.from_dictionary) .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def create_signup_proforma_invoice(self, - body=None): - """Does a POST request to /subscriptions/proforma_invoices.json. + def void_proforma_invoice(self, + proforma_invoice_uid, + body=None): + """Does a POST request to /proforma_invoices/{proforma_invoice_uid}/void.json. - This endpoint is only available for Relationship Invoicing sites. It - cannot be used to create consolidated proforma invoices or preview - prepaid subscriptions. - Create a proforma invoice to preview costs before a subscription's - signup. Like other proforma invoices, it can be emailed to the - customer, voided, and publicly viewed on the chargifypay domain. - Pass a payload that resembles a subscription create or signup preview - request. For example, you can specify components, coupons/a referral, - offers, custom pricing, and an existing customer or payment profile to - populate a shipping or billing address. - A product and customer first name, last name, and email are the - minimum requirements. We recommend associating the proforma invoice - with a customer_id to easily find their proforma invoices, since the - subscription_id will always be blank. + This endpoint will void a proforma invoice that has the status + "draft". + ## Restrictions + Proforma invoices are only available on Relationship Invoicing sites. + Only proforma invoices that have the appropriate status may be + reopened. If the invoice identified by {uid} does not have the + appropriate status, the response will have HTTP status code 422 and an + error message. + A reason for the void operation is required to be included in the + request body. If one is not provided, the response will have HTTP + status code 422 and an error message. Args: - body (CreateSubscriptionRequest, optional): TODO: type description - here. + proforma_invoice_uid (str): The uid of the proforma invoice + body (VoidInvoiceRequest, optional): TODO: type description here. Returns: - ProformaInvoice: Response from the API. Created + ProformaInvoice: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -508,8 +509,13 @@ def create_signup_proforma_invoice(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/proforma_invoices.json') + .path('/proforma_invoices/{proforma_invoice_uid}/void.json') .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('proforma_invoice_uid') + .value(proforma_invoice_uid) + .is_required(True) + .should_encode(True)) .header_param(Parameter() .key('Content-Type') .value('application/json')) @@ -524,38 +530,35 @@ def create_signup_proforma_invoice(self, ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(ProformaInvoice.from_dictionary) - .local_error_template('400', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ProformaBadRequestErrorResponseException) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorArrayMapResponseException) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def preview_signup_proforma_invoice(self, - include=None, - body=None): - """Does a POST request to /subscriptions/proforma_invoices/preview.json. + def create_signup_proforma_invoice(self, + body=None): + """Does a POST request to /subscriptions/proforma_invoices.json. This endpoint is only available for Relationship Invoicing sites. It - cannot be used to create consolidated proforma invoice previews or - preview prepaid subscriptions. - Create a signup preview in the format of a proforma invoice to preview - costs before a subscription's signup. You have the option of - optionally previewing the first renewal's costs as well. The proforma - invoice preview will not be persisted. + cannot be used to create consolidated proforma invoices or preview + prepaid subscriptions. + Create a proforma invoice to preview costs before a subscription's + signup. Like other proforma invoices, it can be emailed to the + customer, voided, and publicly viewed on the chargifypay domain. Pass a payload that resembles a subscription create or signup preview request. For example, you can specify components, coupons/a referral, offers, custom pricing, and an existing customer or payment profile to populate a shipping or billing address. A product and customer first name, last name, and email are the - minimum requirements. + minimum requirements. We recommend associating the proforma invoice + with a customer_id to easily find their proforma invoices, since the + subscription_id will always be blank. Args: - include (CreateSignupProformaPreviewInclude, optional): Choose to - include a proforma invoice preview for the first renewal. Use - in query `include=next_proforma_invoice`. body (CreateSubscriptionRequest, optional): TODO: type description here. Returns: - SignupProformaPreviewResponse: Response from the API. Created + ProformaInvoice: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -567,14 +570,11 @@ def preview_signup_proforma_invoice(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/proforma_invoices/preview.json') + .path('/subscriptions/proforma_invoices.json') .http_method(HttpMethodEnum.POST) .header_param(Parameter() .key('Content-Type') .value('application/json')) - .query_param(Parameter() - .key('include') - .value(include)) .body_param(Parameter() .value(body)) .header_param(Parameter() @@ -585,7 +585,7 @@ def preview_signup_proforma_invoice(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(SignupProformaPreviewResponse.from_dictionary) + .deserialize_into(ProformaInvoice.from_dictionary) .local_error_template('400', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ProformaBadRequestErrorResponseException) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorArrayMapResponseException) ).execute() diff --git a/advancedbilling/controllers/sales_commissions_controller.py b/advancedbilling/controllers/sales_commissions_controller.py index 66d41e76..41d31507 100644 --- a/advancedbilling/controllers/sales_commissions_controller.py +++ b/advancedbilling/controllers/sales_commissions_controller.py @@ -16,8 +16,8 @@ from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.authentication.multiple.single_auth import Single from advancedbilling.models.sale_rep_settings import SaleRepSettings -from advancedbilling.models.list_sale_rep_item import ListSaleRepItem from advancedbilling.models.sale_rep import SaleRep +from advancedbilling.models.list_sale_rep_item import ListSaleRepItem class SalesCommissionsController(BaseController): @@ -120,11 +120,16 @@ def list_sales_commission_settings(self, .deserialize_into(SaleRepSettings.from_dictionary) ).execute() - def list_sales_reps(self, - options=dict()): - """Does a GET request to /sellers/{seller_id}/sales_reps.json. + def read_sales_rep(self, + seller_id, + sales_rep_id, + authorization='Bearer <>', + live_mode=None, + page=1, + per_page=100): + """Does a GET request to /sellers/{seller_id}/sales_reps/{sales_rep_id}.json. - Endpoint returns sales rep list with details + Endpoint returns sales rep and attached subscriptions details. ## Modified Authentication Process The Sales Commission API differs from other Chargify API endpoints. This resource is associated with the seller itself. Up to now all @@ -143,37 +148,28 @@ def list_sales_reps(self, variable will be replaced by `app` Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - seller_id -- str -- The Chargify id of your seller - account - authorization -- str -- For authorization use user API - key. See details - [here](https://developers.chargify.com/docs/developer-d - ocs/ZG9jOjMyNzk5NTg0-2020-04-20-new-api-authentication) - . - live_mode -- bool -- This parameter indicates if records - should be fetched from live mode sites. Default value - is true. - 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 - 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`. - per_page -- int -- This parameter indicates how many - records to fetch in each request. Default value is - 100. + seller_id (str): The Chargify id of your seller account + sales_rep_id (str): The Advanced Billing id of sales rep. + authorization (str, optional): For authorization use user API key. + See details + [here](https://developers.chargify.com/docs/developer-docs/ZG9j + OjMyNzk5NTg0-2020-04-20-new-api-authentication). + live_mode (bool, optional): This parameter indicates if records + should be fetched from live mode sites. Default value is + true. + page (int, 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`. + per_page (int, optional): This parameter indicates how many + records to fetch in each request. Default value is 100. Returns: - List[ListSaleRepItem]: Response from the API. OK + SaleRep: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -185,25 +181,30 @@ def list_sales_reps(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/sellers/{seller_id}/sales_reps.json') + .path('/sellers/{seller_id}/sales_reps/{sales_rep_id}.json') .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('seller_id') - .value(options.get('seller_id', None)) + .value(seller_id) + .is_required(True) + .should_encode(True)) + .template_param(Parameter() + .key('sales_rep_id') + .value(sales_rep_id) .is_required(True) .should_encode(True)) .header_param(Parameter() .key('Authorization') - .value(options.get('authorization', None))) + .value(authorization)) .query_param(Parameter() .key('live_mode') - .value(options.get('live_mode', None))) + .value(live_mode)) .query_param(Parameter() .key('page') - .value(options.get('page', None))) + .value(page)) .query_param(Parameter() .key('per_page') - .value(options.get('per_page', None))) + .value(per_page)) .header_param(Parameter() .key('accept') .value('application/json')) @@ -211,19 +212,14 @@ def list_sales_reps(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ListSaleRepItem.from_dictionary) + .deserialize_into(SaleRep.from_dictionary) ).execute() - def read_sales_rep(self, - seller_id, - sales_rep_id, - authorization='Bearer <>', - live_mode=None, - page=1, - per_page=100): - """Does a GET request to /sellers/{seller_id}/sales_reps/{sales_rep_id}.json. + def list_sales_reps(self, + options=dict()): + """Does a GET request to /sellers/{seller_id}/sales_reps.json. - Endpoint returns sales rep and attached subscriptions details. + Endpoint returns sales rep list with details ## Modified Authentication Process The Sales Commission API differs from other Chargify API endpoints. This resource is associated with the seller itself. Up to now all @@ -242,28 +238,37 @@ def read_sales_rep(self, variable will be replaced by `app` Args: - seller_id (str): The Chargify id of your seller account - sales_rep_id (str): The Advanced Billing id of sales rep. - authorization (str, optional): For authorization use user API key. - See details - [here](https://developers.chargify.com/docs/developer-docs/ZG9j - OjMyNzk5NTg0-2020-04-20-new-api-authentication). - live_mode (bool, optional): This parameter indicates if records - should be fetched from live mode sites. Default value is - true. - page (int, 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`. - per_page (int, optional): This parameter indicates how many - records to fetch in each request. Default value is 100. + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + seller_id -- str -- The Chargify id of your seller + account + authorization -- str -- For authorization use user API + key. See details + [here](https://developers.chargify.com/docs/developer-d + ocs/ZG9jOjMyNzk5NTg0-2020-04-20-new-api-authentication) + . + live_mode -- bool -- This parameter indicates if records + should be fetched from live mode sites. Default value + is true. + 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 + 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`. + per_page -- int -- This parameter indicates how many + records to fetch in each request. Default value is + 100. Returns: - SaleRep: Response from the API. OK + List[ListSaleRepItem]: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -275,30 +280,25 @@ def read_sales_rep(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/sellers/{seller_id}/sales_reps/{sales_rep_id}.json') + .path('/sellers/{seller_id}/sales_reps.json') .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('seller_id') - .value(seller_id) - .is_required(True) - .should_encode(True)) - .template_param(Parameter() - .key('sales_rep_id') - .value(sales_rep_id) + .value(options.get('seller_id', None)) .is_required(True) .should_encode(True)) .header_param(Parameter() .key('Authorization') - .value(authorization)) + .value(options.get('authorization', None))) .query_param(Parameter() .key('live_mode') - .value(live_mode)) + .value(options.get('live_mode', None))) .query_param(Parameter() .key('page') - .value(page)) + .value(options.get('page', None))) .query_param(Parameter() .key('per_page') - .value(per_page)) + .value(options.get('per_page', None))) .header_param(Parameter() .key('accept') .value('application/json')) @@ -306,5 +306,5 @@ def read_sales_rep(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(SaleRep.from_dictionary) + .deserialize_into(ListSaleRepItem.from_dictionary) ).execute() diff --git a/advancedbilling/controllers/subscription_components_controller.py b/advancedbilling/controllers/subscription_components_controller.py index 2e6c88f4..550b3265 100644 --- a/advancedbilling/controllers/subscription_components_controller.py +++ b/advancedbilling/controllers/subscription_components_controller.py @@ -17,15 +17,15 @@ from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.types.array_serialization_format import SerializationFormats from apimatic_core.authentication.multiple.single_auth import Single -from advancedbilling.models.subscription_component_response import SubscriptionComponentResponse from advancedbilling.models.bulk_components_price_point_assignment import BulkComponentsPricePointAssignment -from advancedbilling.models.subscription_response import SubscriptionResponse -from advancedbilling.models.allocation_response import AllocationResponse -from advancedbilling.models.allocation_preview_response import AllocationPreviewResponse from advancedbilling.models.usage_response import UsageResponse from advancedbilling.models.list_subscription_components_response import ListSubscriptionComponentsResponse -from advancedbilling.exceptions.api_exception import APIException +from advancedbilling.models.subscription_component_response import SubscriptionComponentResponse +from advancedbilling.models.allocation_response import AllocationResponse +from advancedbilling.models.allocation_preview_response import AllocationPreviewResponse +from advancedbilling.models.subscription_response import SubscriptionResponse from advancedbilling.exceptions.component_price_point_error_exception import ComponentPricePointErrorException +from advancedbilling.exceptions.api_exception import APIException from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException from advancedbilling.exceptions.component_allocation_error_exception import ComponentAllocationErrorException from advancedbilling.exceptions.subscription_component_allocation_error_exception import SubscriptionComponentAllocationErrorException @@ -37,21 +37,26 @@ class SubscriptionComponentsController(BaseController): def __init__(self, config): super(SubscriptionComponentsController, self).__init__(config) - def read_subscription_component(self, - subscription_id, - component_id): - """Does a GET request to /subscriptions/{subscription_id}/components/{component_id}.json. + def bulk_update_subscription_components_price_points(self, + subscription_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/price_points.json. - This request will list information regarding a specific component - owned by a subscription. + Updates the price points on one or more of a subscription's + components. + The `price_point` key can take either a: + 1. Price point id (integer) + 2. Price point handle (string) + 3. `"_default"` string, which will reset the price point to the + component's current default price point. Args: subscription_id (int): The Chargify id of the subscription - component_id (int): The Advanced Billing id of the component. - Alternatively, the component's handle prefixed by `handle:` + body (BulkComponentsPricePointAssignment, optional): TODO: type + description here. Returns: - SubscriptionComponentResponse: Response from the API. OK + BulkComponentsPricePointAssignment: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -63,38 +68,50 @@ def read_subscription_component(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/components/{component_id}.json') - .http_method(HttpMethodEnum.GET) + .path('/subscriptions/{subscription_id}/price_points.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('subscription_id') .value(subscription_id) .is_required(True) .should_encode(True)) - .template_param(Parameter() - .key('component_id') - .value(component_id) - .is_required(True) - .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionComponentResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .deserialize_into(BulkComponentsPricePointAssignment.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ComponentPricePointErrorException) ).execute() - def list_subscription_components(self, - options=dict()): - """Does a GET request to /subscriptions/{subscription_id}/components.json. + def list_usages(self, + options=dict()): + """Does a GET request to /subscriptions/{subscription_id}/components/{component_id}/usages.json. - This request will list a subscription's applied components. - ## Archived Components - When requesting to list components for a given subscription, if the - subscription contains **archived** components they will be listed in - the server response. + This request will return a list of the usages associated with a + subscription for a particular metered component. This will display the + previously recorded components for a subscription. + This endpoint is not compatible with quantity-based components. + ## Since Date and Until Date Usage + Note: The `since_date` and `until_date` attributes each default to + midnight on the date specified. For example, in order to list usages + for January 20th, you would need to append the following to the URL. + ``` + ?since_date=2016-01-20&until_date=2016-01-21 + ``` + ## Read Usage by Handle + Use this endpoint to read the previously recorded components for a + subscription. You can now specify either the component id (integer) + or the component handle prefixed by "handle:" to specify the unique + identifier for the component you are working with. Args: options (dict, optional): Key-value pairs for any of the @@ -105,56 +122,36 @@ def list_subscription_components(self, subscription_id -- int -- The Chargify id of the subscription - date_field -- SubscriptionListDateField -- The type of - filter you'd like to apply to your search. Use in - query `date_field=updated_at`. - direction -- SortingDirection -- Controls the order in - which results are returned. Use in query - `direction=asc`. - filter -- ListSubscriptionComponentsFilter -- Filter to - use for List Subscription Components operation - end_date -- str -- The end date (format YYYY-MM-DD) with - which to filter the date_field. Returns components - with a timestamp up to and including 11:59:59PM in - your site’s time zone on the date specified. - end_datetime -- str -- The end date and time (format - YYYY-MM-DD HH:MM:SS) with which to filter the - date_field. Returns components 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. - price_point_ids -- IncludeNotNull -- Allows fetching - components allocation only if price point id is - present. Use in query `price_point_ids=not_null`. - product_family_ids -- List[int] -- Allows fetching - components allocation with matching product family id - based on provided ids. Use in query - `product_family_ids=1,2,3`. - sort -- ListSubscriptionComponentsSort -- The attribute by - which to sort. Use in query `sort=updated_at`. - start_date -- str -- The start date (format YYYY-MM-DD) - with which to filter the date_field. Returns - components with a timestamp at or after midnight - (12:00:00 AM) in your site’s time zone on the date - specified. - start_datetime -- str -- The start date and time (format - YYYY-MM-DD HH:MM:SS) with which to filter the - date_field. Returns components with a timestamp at or - after 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 start_date. - include -- List[ListSubscriptionComponentsInclude] -- - Allows including additional data in the response. Use - in query `include=subscription,historic_usages`. - in_use -- bool -- If in_use is set to true, it returns - only components that are currently in use. However, if - it's set to false or not provided, it returns all - components connected with the subscription. + component_id -- int | str -- Either the Advanced Billing + id for the component or the component's handle + prefixed by `handle:` + since_id -- long|int -- Returns usages with an id greater + than or equal to the one specified + max_id -- long|int -- Returns usages with an id less than + or equal to the one specified + since_date -- date -- Returns usages with a created_at + date greater than or equal to midnight (12:00 AM) on + the date specified. + until_date -- date -- Returns usages with a created_at + date less than or equal to midnight (12:00 AM) on the + date specified. + 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 + 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`. + per_page -- int -- 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`. Returns: - List[SubscriptionComponentResponse]: Response from the API. OK + List[UsageResponse]: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -166,80 +163,76 @@ def list_subscription_components(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/components.json') + .path('/subscriptions/{subscription_id}/components/{component_id}/usages.json') .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('subscription_id') .value(options.get('subscription_id', None)) .is_required(True) .should_encode(True)) + .template_param(Parameter() + .key('component_id') + .value(options.get('component_id', None)) + .is_required(True) + .should_encode(True) + .validator(lambda value: UnionTypeLookUp.get('ListUsagesInputComponentId').validate(value))) .query_param(Parameter() - .key('date_field') - .value(options.get('date_field', None))) - .query_param(Parameter() - .key('direction') - .value(options.get('direction', None))) - .query_param(Parameter() - .key('filter') - .value(options.get('filter', None))) - .query_param(Parameter() - .key('end_date') - .value(options.get('end_date', None))) - .query_param(Parameter() - .key('end_datetime') - .value(options.get('end_datetime', None))) - .query_param(Parameter() - .key('price_point_ids') - .value(options.get('price_point_ids', None))) - .query_param(Parameter() - .key('product_family_ids') - .value(options.get('product_family_ids', None))) + .key('since_id') + .value(options.get('since_id', None))) .query_param(Parameter() - .key('sort') - .value(options.get('sort', None))) + .key('max_id') + .value(options.get('max_id', None))) .query_param(Parameter() - .key('start_date') - .value(options.get('start_date', None))) + .key('since_date') + .value(options.get('since_date', None))) .query_param(Parameter() - .key('start_datetime') - .value(options.get('start_datetime', None))) + .key('until_date') + .value(options.get('until_date', None))) .query_param(Parameter() - .key('include') - .value(options.get('include', None))) + .key('page') + .value(options.get('page', None))) .query_param(Parameter() - .key('in_use') - .value(options.get('in_use', None))) + .key('per_page') + .value(options.get('per_page', None))) .header_param(Parameter() .key('accept') .value('application/json')) - .array_serialization_format(SerializationFormats.CSV) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionComponentResponse.from_dictionary) + .deserialize_into(UsageResponse.from_dictionary) ).execute() - def bulk_update_subscription_components_price_points(self, - subscription_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/price_points.json. + def activate_event_based_component(self, + subscription_id, + component_id, + body=None): + """Does a POST request to /event_based_billing/subscriptions/{subscription_id}/components/{component_id}/activate.json. - Updates the price points on one or more of a subscription's - components. - The `price_point` key can take either a: - 1. Price point id (integer) - 2. Price point handle (string) - 3. `"_default"` string, which will reset the price point to the - component's current default price point. + In order to bill your subscribers on your Events data under the + Events-Based Billing feature, the components must be activated for the + subscriber. + Learn more about the role of activation in the [Events-Based Billing + docs](https://maxio.zendesk.com/hc/en-us/articles/24260323329805-Events + -Based-Billing-Overview). + Use this endpoint to activate an event-based component for a single + subscription. Activating an event-based component causes Advanced + Billing to bill for events when the subscription is renewed. + *Note: it is possible to stream events for a subscription at any time, + regardless of component activation status. The activation status only + determines if the subscription should be billed for event-based + component usage at renewal.* Args: - subscription_id (int): The Chargify id of the subscription - body (BulkComponentsPricePointAssignment, optional): TODO: type + subscription_id (int): The Advanced Billing id of the + subscription + component_id (int): The Advanced Billing id of the component + body (ActivateEventBasedComponent, optional): TODO: type description here. Returns: - BulkComponentsPricePointAssignment: Response from the API. OK + void: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -251,44 +244,485 @@ def bulk_update_subscription_components_price_points(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/price_points.json') + .path('/event_based_billing/subscriptions/{subscription_id}/components/{component_id}/activate.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('subscription_id') .value(subscription_id) .is_required(True) .should_encode(True)) + .template_param(Parameter() + .key('component_id') + .value(component_id) + .is_required(True) + .should_encode(True)) .header_param(Parameter() .key('Content-Type') .value('application/json')) .body_param(Parameter() .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) - ).response( + ).execute() + + def list_subscription_components_for_site(self, + options=dict()): + """Does a GET request to /subscriptions_components.json. + + This request will list components applied to each subscription. + + Args: + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + 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 + 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`. + per_page -- int -- 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`. + sort -- ListSubscriptionComponentsSort -- The attribute by + which to sort. Use in query: `sort=updated_at`. + direction -- SortingDirection -- Controls the order in + which results are returned. Use in query + `direction=asc`. + filter -- ListSubscriptionComponentsForSiteFilter -- + Filter to use for List Subscription Components For + Site operation + date_field -- SubscriptionListDateField -- The type of + filter you'd like to apply to your search. Use in + query: `date_field=updated_at`. + start_date -- str -- The start date (format YYYY-MM-DD) + with which to filter the date_field. Returns + components with a timestamp at or after midnight + (12:00:00 AM) in your site’s time zone on the date + specified. Use in query `start_date=2011-12-15`. + start_datetime -- str -- The start date and time (format + YYYY-MM-DD HH:MM:SS) with which to filter the + date_field. Returns components with a timestamp at or + after 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 start_date. Use in query + `start_datetime=2022-07-01 09:00:05`. + end_date -- str -- The end date (format YYYY-MM-DD) with + which to filter the date_field. Returns components + with a timestamp up to and including 11:59:59PM in + your site’s time zone on the date specified. Use in + query `end_date=2011-12-16`. + end_datetime -- str -- The end date and time (format + YYYY-MM-DD HH:MM:SS) with which to filter the + date_field. Returns components 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 + `end_datetime=2022-07-01 09:00:05`. + subscription_ids -- List[int] -- Allows fetching + components allocation with matching subscription id + based on provided ids. Use in query + `subscription_ids=1,2,3`. + price_point_ids -- IncludeNotNull -- Allows fetching + components allocation only if price point id is + present. Use in query `price_point_ids=not_null`. + product_family_ids -- List[int] -- Allows fetching + components allocation with matching product family id + based on provided ids. Use in query + `product_family_ids=1,2,3`. + include -- ListSubscriptionComponentsInclude -- Allows + including additional data in the response. Use in + query `include=subscription,historic_usages`. + + Returns: + ListSubscriptionComponentsResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions_components.json') + .http_method(HttpMethodEnum.GET) + .query_param(Parameter() + .key('page') + .value(options.get('page', None))) + .query_param(Parameter() + .key('per_page') + .value(options.get('per_page', None))) + .query_param(Parameter() + .key('sort') + .value(options.get('sort', None))) + .query_param(Parameter() + .key('direction') + .value(options.get('direction', None))) + .query_param(Parameter() + .key('filter') + .value(options.get('filter', None))) + .query_param(Parameter() + .key('date_field') + .value(options.get('date_field', None))) + .query_param(Parameter() + .key('start_date') + .value(options.get('start_date', None))) + .query_param(Parameter() + .key('start_datetime') + .value(options.get('start_datetime', None))) + .query_param(Parameter() + .key('end_date') + .value(options.get('end_date', None))) + .query_param(Parameter() + .key('end_datetime') + .value(options.get('end_datetime', None))) + .query_param(Parameter() + .key('subscription_ids') + .value(options.get('subscription_ids', None))) + .query_param(Parameter() + .key('price_point_ids') + .value(options.get('price_point_ids', None))) + .query_param(Parameter() + .key('product_family_ids') + .value(options.get('product_family_ids', None))) + .query_param(Parameter() + .key('include') + .value(options.get('include', None))) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .array_serialization_format(SerializationFormats.CSV) + .auth(Single('BasicAuth')) + ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(BulkComponentsPricePointAssignment.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ComponentPricePointErrorException) + .deserialize_into(ListSubscriptionComponentsResponse.from_dictionary) ).execute() - def bulk_reset_subscription_components_price_points(self, - subscription_id): - """Does a POST request to /subscriptions/{subscription_id}/price_points/reset.json. + def read_subscription_component(self, + subscription_id, + component_id): + """Does a GET request to /subscriptions/{subscription_id}/components/{component_id}.json. - Resets all of a subscription's components to use the current default. - **Note**: this will update the price point for all of the - subscription's components, even ones that have not been allocated - yet. + This request will list information regarding a specific component + owned by a subscription. + + Args: + subscription_id (int): The Chargify id of the subscription + component_id (int): The Advanced Billing id of the component. + Alternatively, the component's handle prefixed by `handle:` + + Returns: + SubscriptionComponentResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/components/{component_id}.json') + .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .template_param(Parameter() + .key('component_id') + .value(component_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(SubscriptionComponentResponse.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + ).execute() + + def allocate_components(self, + subscription_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/allocations.json. + + Creates multiple allocations, setting the current allocated quantity + for each of the components and recording a memo. The charges and/or + credits that are created will be rolled up into a single total which + is used to determine whether this is an upgrade or a downgrade. Be + aware of the Order of Resolutions explained below in determining the + proration scheme. + A `component_id` is required for each allocation. + This endpoint only responds to JSON. It is not available for XML. + + Args: + subscription_id (int): The Chargify id of the subscription + body (AllocateComponents, optional): TODO: type description here. + + Returns: + List[AllocationResponse]: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/allocations.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(AllocationResponse.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + ).execute() + + def preview_allocations(self, + subscription_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/allocations/preview.json. + + Advanced Billing offers the ability to preview a potential + subscription's **quantity-based** or **on/off** component allocation + in the middle of the current billing period. This is useful if you + want users to be able to see the effect of a component operation + before actually doing it. + ## Fine-grained Component Control: Use with multiple `upgrade_charge`s + or `downgrade_credits` + When the allocation uses multiple different types of `upgrade_charge`s + or `downgrade_credit`s, the Allocation is viewed as an Allocation + which uses "Fine-Grained Component Control". As a result, the response + will not include `direction` and `proration` within the + `allocation_preview`, but at the `line_items` and `allocations` level + respectfully. + See example below for Fine-Grained Component Control response. Args: subscription_id (int): The Chargify id of the subscription + body (PreviewAllocationsRequest, optional): TODO: type description + here. + + Returns: + AllocationPreviewResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/allocations/preview.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(AllocationPreviewResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ComponentAllocationErrorException) + ).execute() + + def record_event(self, + subdomain, + api_handle, + store_uid=None, + body=None): + """Does a POST request to /{subdomain}/events/{api_handle}.json. + + ## Documentation + Events-Based Billing is an evolved form of metered billing that is + based on data-rich events streamed in real-time from your system to + Advanced Billing. + These events can then be transformed, enriched, or analyzed to form + the computed totals of usage charges billed to your customers. + This API allows you to stream events into the Advanced Billing data + ingestion engine. + Learn more about the feature in general in the [Events-Based Billing + help + docs](https://maxio.zendesk.com/hc/en-us/articles/24260323329805-Events + -Based-Billing-Overview). + ## Record Event + Use this endpoint to record a single event. + *Note: this endpoint differs from the standard Chargify API endpoints + in that the URL subdomain will be `events` and your site subdomain + will be included in the URL path. For example:* + ``` + https://events.chargify.com/my-site-subdomain/events/my-stream-api-hand + le + ``` + + Args: + subdomain (str): Your site's subdomain + api_handle (str): Identifies the Stream for which the event should + be published. + store_uid (str, optional): If you've attached your own Keen + project as an Advanced Billing event data-store, use this + parameter to indicate the data-store. + body (EBBEvent, optional): TODO: type description here. + + Returns: + void: Response from the API. Created + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/{subdomain}/events/{api_handle}.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subdomain') + .value(subdomain) + .is_required(True) + .should_encode(True)) + .template_param(Parameter() + .key('api_handle') + .value(api_handle) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .query_param(Parameter() + .key('store_uid') + .value(store_uid)) + .body_param(Parameter() + .value(body)) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).execute() + + def list_subscription_components(self, + options=dict()): + """Does a GET request to /subscriptions/{subscription_id}/components.json. + + This request will list a subscription's applied components. + ## Archived Components + When requesting to list components for a given subscription, if the + subscription contains **archived** components they will be listed in + the server response. + + Args: + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + subscription_id -- int -- The Chargify id of the + subscription + date_field -- SubscriptionListDateField -- The type of + filter you'd like to apply to your search. Use in + query `date_field=updated_at`. + direction -- SortingDirection -- Controls the order in + which results are returned. Use in query + `direction=asc`. + filter -- ListSubscriptionComponentsFilter -- Filter to + use for List Subscription Components operation + end_date -- str -- The end date (format YYYY-MM-DD) with + which to filter the date_field. Returns components + with a timestamp up to and including 11:59:59PM in + your site’s time zone on the date specified. + end_datetime -- str -- The end date and time (format + YYYY-MM-DD HH:MM:SS) with which to filter the + date_field. Returns components 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. + price_point_ids -- IncludeNotNull -- Allows fetching + components allocation only if price point id is + present. Use in query `price_point_ids=not_null`. + product_family_ids -- List[int] -- Allows fetching + components allocation with matching product family id + based on provided ids. Use in query + `product_family_ids=1,2,3`. + sort -- ListSubscriptionComponentsSort -- The attribute by + which to sort. Use in query `sort=updated_at`. + start_date -- str -- The start date (format YYYY-MM-DD) + with which to filter the date_field. Returns + components with a timestamp at or after midnight + (12:00:00 AM) in your site’s time zone on the date + specified. + start_datetime -- str -- The start date and time (format + YYYY-MM-DD HH:MM:SS) with which to filter the + date_field. Returns components with a timestamp at or + after 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 start_date. + include -- List[ListSubscriptionComponentsInclude] -- + Allows including additional data in the response. Use + in query `include=subscription,historic_usages`. + in_use -- bool -- If in_use is set to true, it returns + only components that are currently in use. However, if + it's set to false or not provided, it returns all + components connected with the subscription. Returns: - SubscriptionResponse: Response from the API. Created + List[SubscriptionComponentResponse]: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -300,21 +734,58 @@ def bulk_reset_subscription_components_price_points(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/price_points/reset.json') - .http_method(HttpMethodEnum.POST) + .path('/subscriptions/{subscription_id}/components.json') + .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('subscription_id') - .value(subscription_id) + .value(options.get('subscription_id', None)) .is_required(True) .should_encode(True)) + .query_param(Parameter() + .key('date_field') + .value(options.get('date_field', None))) + .query_param(Parameter() + .key('direction') + .value(options.get('direction', None))) + .query_param(Parameter() + .key('filter') + .value(options.get('filter', None))) + .query_param(Parameter() + .key('end_date') + .value(options.get('end_date', None))) + .query_param(Parameter() + .key('end_datetime') + .value(options.get('end_datetime', None))) + .query_param(Parameter() + .key('price_point_ids') + .value(options.get('price_point_ids', None))) + .query_param(Parameter() + .key('product_family_ids') + .value(options.get('product_family_ids', None))) + .query_param(Parameter() + .key('sort') + .value(options.get('sort', None))) + .query_param(Parameter() + .key('start_date') + .value(options.get('start_date', None))) + .query_param(Parameter() + .key('start_datetime') + .value(options.get('start_datetime', None))) + .query_param(Parameter() + .key('include') + .value(options.get('include', None))) + .query_param(Parameter() + .key('in_use') + .value(options.get('in_use', None))) .header_param(Parameter() .key('accept') .value('application/json')) + .array_serialization_format(SerializationFormats.CSV) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionResponse.from_dictionary) + .deserialize_into(SubscriptionComponentResponse.from_dictionary) ).execute() def allocate_component(self, @@ -444,45 +915,40 @@ def allocate_component(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def list_allocations(self, - subscription_id, - component_id, - page=1): - """Does a GET request to /subscriptions/{subscription_id}/components/{component_id}/allocations.json. + def update_prepaid_usage_allocation_expiration_date(self, + subscription_id, + component_id, + allocation_id, + body=None): + """Does a PUT request to /subscriptions/{subscription_id}/components/{component_id}/allocations/{allocation_id}.json. - This endpoint returns the 50 most recent Allocations, ordered by most - recent first. - ## On/Off Components - When a subscription's on/off component has been toggled to on (`1`) or - off (`0`), usage will be logged in this response. - ## Querying data via Advanced Billing gem - You can also query the current quantity via the [official Advanced - Billing Gem.](http://github.com/chargify/chargify_api_ares) - ```# First way - component = Chargify::Subscription::Component.find(1, :params => - {:subscription_id => 7}) - puts component.allocated_quantity - # => 23 - # Second way - component = Chargify::Subscription.find(7).component(1) - puts component.allocated_quantity - # => 23 - ``` + When the expiration interval options are selected on a prepaid usage + component price point, all allocations will be created with an + expiration date. This expiration date can be changed after the fact to + allow for extending or shortening the allocation's active window. + In order to change a prepaid usage allocation's expiration date, a PUT + call must be made to the allocation's endpoint with a new expiration + date. + ## Limitations + A few limitations exist when changing an allocation's expiration + date: + - An expiration date can only be changed for an allocation that + belongs to a price point with expiration interval options explicitly + set. + - An expiration date can be changed towards the future with no + limitations. + - An expiration date can be changed towards the past (essentially + expiring it) up to the subscription's current period beginning date. Args: subscription_id (int): The Chargify id of the subscription component_id (int): The Advanced Billing id of the component - page (int, 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`. + allocation_id (int): The Advanced Billing id of the allocation + body (UpdateAllocationExpirationDate, optional): TODO: type + description here. Returns: - List[AllocationResponse]: Response from the API. OK + void: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -494,8 +960,8 @@ def list_allocations(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/components/{component_id}/allocations.json') - .http_method(HttpMethodEnum.GET) + .path('/subscriptions/{subscription_id}/components/{component_id}/allocations/{allocation_id}.json') + .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('subscription_id') .value(subscription_id) @@ -506,57 +972,9 @@ def list_allocations(self, .value(component_id) .is_required(True) .should_encode(True)) - .query_param(Parameter() - .key('page') - .value(page)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(AllocationResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) - ).execute() - - def allocate_components(self, - subscription_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/allocations.json. - - Creates multiple allocations, setting the current allocated quantity - for each of the components and recording a memo. The charges and/or - credits that are created will be rolled up into a single total which - is used to determine whether this is an upgrade or a downgrade. Be - aware of the Order of Resolutions explained below in determining the - proration scheme. - A `component_id` is required for each allocation. - This endpoint only responds to JSON. It is not available for XML. - - Args: - subscription_id (int): The Chargify id of the subscription - body (AllocateComponents, optional): TODO: type description here. - - Returns: - List[AllocationResponse]: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/allocations.json') - .http_method(HttpMethodEnum.POST) .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) + .key('allocation_id') + .value(allocation_id) .is_required(True) .should_encode(True)) .header_param(Parameter() @@ -564,46 +982,24 @@ def allocate_components(self, .value('application/json')) .body_param(Parameter() .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(AllocationResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def preview_allocations(self, - subscription_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/allocations/preview.json. + def bulk_reset_subscription_components_price_points(self, + subscription_id): + """Does a POST request to /subscriptions/{subscription_id}/price_points/reset.json. - Advanced Billing offers the ability to preview a potential - subscription's **quantity-based** or **on/off** component allocation - in the middle of the current billing period. This is useful if you - want users to be able to see the effect of a component operation - before actually doing it. - ## Fine-grained Component Control: Use with multiple `upgrade_charge`s - or `downgrade_credits` - When the allocation uses multiple different types of `upgrade_charge`s - or `downgrade_credit`s, the Allocation is viewed as an Allocation - which uses "Fine-Grained Component Control". As a result, the response - will not include `direction` and `proration` within the - `allocation_preview`, but at the `line_items` and `allocations` level - respectfully. - See example below for Fine-Grained Component Control response. + Resets all of a subscription's components to use the current default. + **Note**: this will update the price point for all of the + subscription's components, even ones that have not been allocated + yet. Args: subscription_id (int): The Chargify id of the subscription - body (PreviewAllocationsRequest, optional): TODO: type description - here. Returns: - AllocationPreviewResponse: Response from the API. OK + SubscriptionResponse: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -615,64 +1011,62 @@ def preview_allocations(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/allocations/preview.json') + .path('/subscriptions/{subscription_id}/price_points/reset.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('subscription_id') .value(subscription_id) .is_required(True) .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(AllocationPreviewResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ComponentAllocationErrorException) - ).execute() - - def update_prepaid_usage_allocation_expiration_date(self, - subscription_id, - component_id, - allocation_id, - body=None): - """Does a PUT request to /subscriptions/{subscription_id}/components/{component_id}/allocations/{allocation_id}.json. - - When the expiration interval options are selected on a prepaid usage - component price point, all allocations will be created with an - expiration date. This expiration date can be changed after the fact to - allow for extending or shortening the allocation's active window. - In order to change a prepaid usage allocation's expiration date, a PUT - call must be made to the allocation's endpoint with a new expiration - date. - ## Limitations - A few limitations exist when changing an allocation's expiration - date: - - An expiration date can only be changed for an allocation that - belongs to a price point with expiration interval options explicitly - set. - - An expiration date can be changed towards the future with no - limitations. - - An expiration date can be changed towards the past (essentially - expiring it) up to the subscription's current period beginning date. + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(SubscriptionResponse.from_dictionary) + ).execute() + + def list_allocations(self, + subscription_id, + component_id, + page=1): + """Does a GET request to /subscriptions/{subscription_id}/components/{component_id}/allocations.json. + + This endpoint returns the 50 most recent Allocations, ordered by most + recent first. + ## On/Off Components + When a subscription's on/off component has been toggled to on (`1`) or + off (`0`), usage will be logged in this response. + ## Querying data via Advanced Billing gem + You can also query the current quantity via the [official Advanced + Billing Gem.](http://github.com/chargify/chargify_api_ares) + ```# First way + component = Chargify::Subscription::Component.find(1, :params => + {:subscription_id => 7}) + puts component.allocated_quantity + # => 23 + # Second way + component = Chargify::Subscription.find(7).component(1) + puts component.allocated_quantity + # => 23 + ``` Args: subscription_id (int): The Chargify id of the subscription component_id (int): The Advanced Billing id of the component - allocation_id (int): The Advanced Billing id of the allocation - body (UpdateAllocationExpirationDate, optional): TODO: type - description here. + page (int, 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`. Returns: - void: Response from the API. OK + List[AllocationResponse]: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -684,8 +1078,8 @@ def update_prepaid_usage_allocation_expiration_date(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/components/{component_id}/allocations/{allocation_id}.json') - .http_method(HttpMethodEnum.PUT) + .path('/subscriptions/{subscription_id}/components/{component_id}/allocations.json') + .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('subscription_id') .value(subscription_id) @@ -696,18 +1090,19 @@ def update_prepaid_usage_allocation_expiration_date(self, .value(component_id) .is_required(True) .should_encode(True)) - .template_param(Parameter() - .key('allocation_id') - .value(allocation_id) - .is_required(True) - .should_encode(True)) + .query_param(Parameter() + .key('page') + .value(page)) .header_param(Parameter() - .key('Content-Type') + .key('accept') .value('application/json')) - .body_param(Parameter() - .value(body)) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(AllocationResponse.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() def delete_prepaid_usage_allocation(self, @@ -845,207 +1240,25 @@ def create_usage(self, "memo": "Deducting 5000 units" } } - ``` - 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 (int): The Chargify id of the subscription - component_id (int | str): Either the Advanced Billing id for the - component or the component's handle prefixed by `handle:` - body (CreateUsageRequest, optional): TODO: type description here. - - Returns: - UsageResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/components/{component_id}/usages.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .template_param(Parameter() - .key('component_id') - .value(component_id) - .is_required(True) - .should_encode(True) - .validator(lambda value: UnionTypeLookUp.get('CreateUsageComponentId').validate(value))) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(UsageResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) - ).execute() - - def list_usages(self, - options=dict()): - """Does a GET request to /subscriptions/{subscription_id}/components/{component_id}/usages.json. - - This request will return a list of the usages associated with a - subscription for a particular metered component. This will display the - previously recorded components for a subscription. - This endpoint is not compatible with quantity-based components. - ## Since Date and Until Date Usage - Note: The `since_date` and `until_date` attributes each default to - midnight on the date specified. For example, in order to list usages - for January 20th, you would need to append the following to the URL. - ``` - ?since_date=2016-01-20&until_date=2016-01-21 - ``` - ## Read Usage by Handle - Use this endpoint to read the previously recorded components for a - subscription. You can now specify either the component id (integer) - or the component handle prefixed by "handle:" to specify the unique - identifier for the component you are working with. - - Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - subscription_id -- int -- The Chargify id of the - subscription - component_id -- int | str -- Either the Advanced Billing - id for the component or the component's handle - prefixed by `handle:` - since_id -- long|int -- Returns usages with an id greater - than or equal to the one specified - max_id -- long|int -- Returns usages with an id less than - or equal to the one specified - since_date -- date -- Returns usages with a created_at - date greater than or equal to midnight (12:00 AM) on - the date specified. - until_date -- date -- Returns usages with a created_at - date less than or equal to midnight (12:00 AM) on the - date specified. - 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 - 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`. - per_page -- int -- 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`. - - Returns: - List[UsageResponse]: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/components/{component_id}/usages.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('subscription_id') - .value(options.get('subscription_id', None)) - .is_required(True) - .should_encode(True)) - .template_param(Parameter() - .key('component_id') - .value(options.get('component_id', None)) - .is_required(True) - .should_encode(True) - .validator(lambda value: UnionTypeLookUp.get('ListUsagesInputComponentId').validate(value))) - .query_param(Parameter() - .key('since_id') - .value(options.get('since_id', None))) - .query_param(Parameter() - .key('max_id') - .value(options.get('max_id', None))) - .query_param(Parameter() - .key('since_date') - .value(options.get('since_date', None))) - .query_param(Parameter() - .key('until_date') - .value(options.get('until_date', None))) - .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(UsageResponse.from_dictionary) - ).execute() - - def activate_event_based_component(self, - subscription_id, - component_id, - body=None): - """Does a POST request to /event_based_billing/subscriptions/{subscription_id}/components/{component_id}/activate.json. - - In order to bill your subscribers on your Events data under the - Events-Based Billing feature, the components must be activated for the - subscriber. - Learn more about the role of activation in the [Events-Based Billing - docs](https://maxio.zendesk.com/hc/en-us/articles/24260323329805-Events - -Based-Billing-Overview). - Use this endpoint to activate an event-based component for a single - subscription. Activating an event-based component causes Advanced - Billing to bill for events when the subscription is renewed. - *Note: it is possible to stream events for a subscription at any time, - regardless of component activation status. The activation status only - determines if the subscription should be billed for event-based - component usage at renewal.* + ``` + 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 (int): The Advanced Billing id of the - subscription - component_id (int): The Advanced Billing id of the component - body (ActivateEventBasedComponent, optional): TODO: type - description here. + subscription_id (int): The Chargify id of the subscription + component_id (int | str): Either the Advanced Billing id for the + component or the component's handle prefixed by `handle:` + body (CreateUsageRequest, optional): TODO: type description here. Returns: - void: Response from the API. OK + UsageResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -1057,7 +1270,7 @@ def activate_event_based_component(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/event_based_billing/subscriptions/{subscription_id}/components/{component_id}/activate.json') + .path('/subscriptions/{subscription_id}/components/{component_id}/usages.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('subscription_id') @@ -1068,14 +1281,23 @@ def activate_event_based_component(self, .key('component_id') .value(component_id) .is_required(True) - .should_encode(True)) + .should_encode(True) + .validator(lambda value: UnionTypeLookUp.get('CreateUsageComponentId').validate(value))) .header_param(Parameter() .key('Content-Type') .value('application/json')) .body_param(Parameter() .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(UsageResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() def deactivate_event_based_component(self, @@ -1120,81 +1342,6 @@ def deactivate_event_based_component(self, .auth(Single('BasicAuth')) ).execute() - def record_event(self, - subdomain, - api_handle, - store_uid=None, - body=None): - """Does a POST request to /{subdomain}/events/{api_handle}.json. - - ## Documentation - Events-Based Billing is an evolved form of metered billing that is - based on data-rich events streamed in real-time from your system to - Advanced Billing. - These events can then be transformed, enriched, or analyzed to form - the computed totals of usage charges billed to your customers. - This API allows you to stream events into the Advanced Billing data - ingestion engine. - Learn more about the feature in general in the [Events-Based Billing - help - docs](https://maxio.zendesk.com/hc/en-us/articles/24260323329805-Events - -Based-Billing-Overview). - ## Record Event - Use this endpoint to record a single event. - *Note: this endpoint differs from the standard Chargify API endpoints - in that the URL subdomain will be `events` and your site subdomain - will be included in the URL path. For example:* - ``` - https://events.chargify.com/my-site-subdomain/events/my-stream-api-hand - le - ``` - - Args: - subdomain (str): Your site's subdomain - api_handle (str): Identifies the Stream for which the event should - be published. - store_uid (str, optional): If you've attached your own Keen - project as an Advanced Billing event data-store, use this - parameter to indicate the data-store. - body (EBBEvent, optional): TODO: type description here. - - Returns: - void: Response from the API. Created - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/{subdomain}/events/{api_handle}.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('subdomain') - .value(subdomain) - .is_required(True) - .should_encode(True)) - .template_param(Parameter() - .key('api_handle') - .value(api_handle) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .query_param(Parameter() - .key('store_uid') - .value(store_uid)) - .body_param(Parameter() - .value(body)) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).execute() - def bulk_record_events(self, subdomain, api_handle, @@ -1254,150 +1401,3 @@ def bulk_record_events(self, .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).execute() - - def list_subscription_components_for_site(self, - options=dict()): - """Does a GET request to /subscriptions_components.json. - - This request will list components applied to each subscription. - - Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - 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 - 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`. - per_page -- int -- 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`. - sort -- ListSubscriptionComponentsSort -- The attribute by - which to sort. Use in query: `sort=updated_at`. - direction -- SortingDirection -- Controls the order in - which results are returned. Use in query - `direction=asc`. - filter -- ListSubscriptionComponentsForSiteFilter -- - Filter to use for List Subscription Components For - Site operation - date_field -- SubscriptionListDateField -- The type of - filter you'd like to apply to your search. Use in - query: `date_field=updated_at`. - start_date -- str -- The start date (format YYYY-MM-DD) - with which to filter the date_field. Returns - components with a timestamp at or after midnight - (12:00:00 AM) in your site’s time zone on the date - specified. Use in query `start_date=2011-12-15`. - start_datetime -- str -- The start date and time (format - YYYY-MM-DD HH:MM:SS) with which to filter the - date_field. Returns components with a timestamp at or - after 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 start_date. Use in query - `start_datetime=2022-07-01 09:00:05`. - end_date -- str -- The end date (format YYYY-MM-DD) with - which to filter the date_field. Returns components - with a timestamp up to and including 11:59:59PM in - your site’s time zone on the date specified. Use in - query `end_date=2011-12-16`. - end_datetime -- str -- The end date and time (format - YYYY-MM-DD HH:MM:SS) with which to filter the - date_field. Returns components 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 - `end_datetime=2022-07-01 09:00:05`. - subscription_ids -- List[int] -- Allows fetching - components allocation with matching subscription id - based on provided ids. Use in query - `subscription_ids=1,2,3`. - price_point_ids -- IncludeNotNull -- Allows fetching - components allocation only if price point id is - present. Use in query `price_point_ids=not_null`. - product_family_ids -- List[int] -- Allows fetching - components allocation with matching product family id - based on provided ids. Use in query - `product_family_ids=1,2,3`. - include -- ListSubscriptionComponentsInclude -- Allows - including additional data in the response. Use in - query `include=subscription,historic_usages`. - - Returns: - ListSubscriptionComponentsResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions_components.json') - .http_method(HttpMethodEnum.GET) - .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) - .query_param(Parameter() - .key('sort') - .value(options.get('sort', None))) - .query_param(Parameter() - .key('direction') - .value(options.get('direction', None))) - .query_param(Parameter() - .key('filter') - .value(options.get('filter', None))) - .query_param(Parameter() - .key('date_field') - .value(options.get('date_field', None))) - .query_param(Parameter() - .key('start_date') - .value(options.get('start_date', None))) - .query_param(Parameter() - .key('start_datetime') - .value(options.get('start_datetime', None))) - .query_param(Parameter() - .key('end_date') - .value(options.get('end_date', None))) - .query_param(Parameter() - .key('end_datetime') - .value(options.get('end_datetime', None))) - .query_param(Parameter() - .key('subscription_ids') - .value(options.get('subscription_ids', None))) - .query_param(Parameter() - .key('price_point_ids') - .value(options.get('price_point_ids', None))) - .query_param(Parameter() - .key('product_family_ids') - .value(options.get('product_family_ids', None))) - .query_param(Parameter() - .key('include') - .value(options.get('include', None))) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .array_serialization_format(SerializationFormats.CSV) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(ListSubscriptionComponentsResponse.from_dictionary) - ).execute() diff --git a/advancedbilling/controllers/subscription_group_invoice_account_controller.py b/advancedbilling/controllers/subscription_group_invoice_account_controller.py index b735ba74..f9a99965 100644 --- a/advancedbilling/controllers/subscription_group_invoice_account_controller.py +++ b/advancedbilling/controllers/subscription_group_invoice_account_controller.py @@ -16,10 +16,10 @@ from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.types.array_serialization_format import SerializationFormats from apimatic_core.authentication.multiple.single_auth import Single -from advancedbilling.models.subscription_group_prepayment_response import SubscriptionGroupPrepaymentResponse +from advancedbilling.models.service_credit import ServiceCredit from advancedbilling.models.list_subscription_group_prepayment_response import ListSubscriptionGroupPrepaymentResponse +from advancedbilling.models.subscription_group_prepayment_response import SubscriptionGroupPrepaymentResponse from advancedbilling.models.service_credit_response import ServiceCreditResponse -from advancedbilling.models.service_credit import ServiceCredit from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException from advancedbilling.exceptions.api_exception import APIException @@ -30,23 +30,22 @@ class SubscriptionGroupInvoiceAccountController(BaseController): def __init__(self, config): super(SubscriptionGroupInvoiceAccountController, self).__init__(config) - def create_subscription_group_prepayment(self, - uid, - body=None): - """Does a POST request to /subscription_groups/{uid}/prepayments.json. + def deduct_subscription_group_service_credit(self, + uid, + body=None): + """Does a POST request to /subscription_groups/{uid}/service_credit_deductions.json. - A prepayment can be added for a subscription group identified by the - group's `uid`. This endpoint requires a `amount`, `details`, `method`, - and `memo`. On success, the prepayment will be added to the group's - prepayment balance. + Credit can be deducted for a subscription group identified by the + group's `uid`. Credit will be deducted from the group in the amount + specified in the request body. Args: uid (str): The uid of the subscription group - body (SubscriptionGroupPrepaymentRequest, optional): TODO: type + body (DeductServiceCreditRequest, optional): TODO: type description here. Returns: - SubscriptionGroupPrepaymentResponse: Response from the API. OK + ServiceCredit: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -58,7 +57,7 @@ def create_subscription_group_prepayment(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/{uid}/prepayments.json') + .path('/subscription_groups/{uid}/service_credit_deductions.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('uid') @@ -78,7 +77,7 @@ def create_subscription_group_prepayment(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionGroupPrepaymentResponse.from_dictionary) + .deserialize_into(ServiceCredit.from_dictionary) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() @@ -155,23 +154,23 @@ def list_prepayments_for_subscription_group(self, .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) ).execute() - def issue_subscription_group_service_credit(self, - uid, - body=None): - """Does a POST request to /subscription_groups/{uid}/service_credits.json. + def create_subscription_group_prepayment(self, + uid, + body=None): + """Does a POST request to /subscription_groups/{uid}/prepayments.json. - Credit can be issued for a subscription group identified by the - group's `uid`. Credit will be added to the group in the amount - specified in the request body. The credit will be applied to group - member invoices as they are generated. + A prepayment can be added for a subscription group identified by the + group's `uid`. This endpoint requires a `amount`, `details`, `method`, + and `memo`. On success, the prepayment will be added to the group's + prepayment balance. Args: uid (str): The uid of the subscription group - body (IssueServiceCreditRequest, optional): TODO: type description - here. + body (SubscriptionGroupPrepaymentRequest, optional): TODO: type + description here. Returns: - ServiceCreditResponse: Response from the API. OK + SubscriptionGroupPrepaymentResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -183,7 +182,7 @@ def issue_subscription_group_service_credit(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/{uid}/service_credits.json') + .path('/subscription_groups/{uid}/prepayments.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('uid') @@ -203,26 +202,27 @@ def issue_subscription_group_service_credit(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ServiceCreditResponse.from_dictionary) + .deserialize_into(SubscriptionGroupPrepaymentResponse.from_dictionary) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def deduct_subscription_group_service_credit(self, - uid, - body=None): - """Does a POST request to /subscription_groups/{uid}/service_credit_deductions.json. + def issue_subscription_group_service_credit(self, + uid, + body=None): + """Does a POST request to /subscription_groups/{uid}/service_credits.json. - Credit can be deducted for a subscription group identified by the - group's `uid`. Credit will be deducted from the group in the amount - specified in the request body. + Credit can be issued for a subscription group identified by the + group's `uid`. Credit will be added to the group in the amount + specified in the request body. The credit will be applied to group + member invoices as they are generated. Args: uid (str): The uid of the subscription group - body (DeductServiceCreditRequest, optional): TODO: type - description here. + body (IssueServiceCreditRequest, optional): TODO: type description + here. Returns: - ServiceCredit: Response from the API. Created + ServiceCreditResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -234,7 +234,7 @@ def deduct_subscription_group_service_credit(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/{uid}/service_credit_deductions.json') + .path('/subscription_groups/{uid}/service_credits.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('uid') @@ -254,6 +254,6 @@ def deduct_subscription_group_service_credit(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ServiceCredit.from_dictionary) + .deserialize_into(ServiceCreditResponse.from_dictionary) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() diff --git a/advancedbilling/controllers/subscription_group_status_controller.py b/advancedbilling/controllers/subscription_group_status_controller.py index b0a642ff..09cff4fc 100644 --- a/advancedbilling/controllers/subscription_group_status_controller.py +++ b/advancedbilling/controllers/subscription_group_status_controller.py @@ -25,25 +25,19 @@ class SubscriptionGroupStatusController(BaseController): def __init__(self, config): super(SubscriptionGroupStatusController, self).__init__(config) - def cancel_subscriptions_in_group(self, - uid, - body=None): - """Does a POST request to /subscription_groups/{uid}/cancel.json. + def initiate_delayed_cancellation_for_group(self, + uid): + """Does a POST request to /subscription_groups/{uid}/delayed_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 - `charge_unbilled_usage=true` parameter must be included in the - request. + 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. + 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. Args: uid (str): The uid of the subscription group - body (CancelGroupedSubscriptionsRequest, optional): TODO: type - description here. Returns: void: Response from the API. OK @@ -58,35 +52,35 @@ def cancel_subscriptions_in_group(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/{uid}/cancel.json') + .path('/subscription_groups/{uid}/delayed_cancel.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('uid') .value(uid) .is_required(True) .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).execute() - def initiate_delayed_cancellation_for_group(self, - uid): - """Does a POST request to /subscription_groups/{uid}/delayed_cancel.json. + def cancel_subscriptions_in_group(self, + uid, + body=None): + """Does a POST request to /subscription_groups/{uid}/cancel.json. - 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. - 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. + 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 + `charge_unbilled_usage=true` parameter must be included in the + request. Args: uid (str): The uid of the subscription group + body (CancelGroupedSubscriptionsRequest, optional): TODO: type + description here. Returns: void: Response from the API. OK @@ -101,13 +95,19 @@ def initiate_delayed_cancellation_for_group(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/{uid}/delayed_cancel.json') + .path('/subscription_groups/{uid}/cancel.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('uid') .value(uid) .is_required(True) .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).execute() diff --git a/advancedbilling/controllers/subscription_groups_controller.py b/advancedbilling/controllers/subscription_groups_controller.py index d1cc6398..db7b2071 100644 --- a/advancedbilling/controllers/subscription_groups_controller.py +++ b/advancedbilling/controllers/subscription_groups_controller.py @@ -16,15 +16,15 @@ from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.types.array_serialization_format import SerializationFormats from apimatic_core.authentication.multiple.single_auth import Single -from advancedbilling.models.subscription_group_signup_response import SubscriptionGroupSignupResponse -from advancedbilling.models.subscription_group_response import SubscriptionGroupResponse from advancedbilling.models.list_subscription_groups_response import ListSubscriptionGroupsResponse from advancedbilling.models.full_subscription_group_response import FullSubscriptionGroupResponse +from advancedbilling.models.subscription_group_signup_response import SubscriptionGroupSignupResponse +from advancedbilling.models.subscription_group_response import SubscriptionGroupResponse from advancedbilling.models.delete_subscription_group_response import DeleteSubscriptionGroupResponse +from advancedbilling.exceptions.api_exception import APIException from advancedbilling.exceptions.subscription_group_signup_error_response_exception import SubscriptionGroupSignupErrorResponseException from advancedbilling.exceptions.subscription_group_create_error_response_exception import SubscriptionGroupCreateErrorResponseException from advancedbilling.exceptions.subscription_group_update_error_response_exception import SubscriptionGroupUpdateErrorResponseException -from advancedbilling.exceptions.api_exception import APIException from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException @@ -34,102 +34,6 @@ class SubscriptionGroupsController(BaseController): def __init__(self, config): super(SubscriptionGroupsController, self).__init__(config) - def signup_with_subscription_group(self, - body=None): - """Does a POST request to /subscription_groups/signup.json. - - Create multiple subscriptions at once under the same customer and - consolidate them into a subscription group. - You must provide one and only one of the - `payer_id`/`payer_reference`/`payer_attributes` for the customer - attached to the group. - You must provide one and only one of the - `payment_profile_id`/`credit_card_attributes`/`bank_account_attributes` - for the payment profile attached to the group. - 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. - - Args: - body (SubscriptionGroupSignupRequest, optional): TODO: type - description here. - - Returns: - SubscriptionGroupSignupResponse: Response from the API. Created - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/signup.json') - .http_method(HttpMethodEnum.POST) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionGroupSignupResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SubscriptionGroupSignupErrorResponseException) - ).execute() - - def create_subscription_group(self, - body=None): - """Does a POST request to /subscription_groups.json. - - Creates a subscription group with given members. - - Args: - body (CreateSubscriptionGroupRequest, optional): TODO: type - description here. - - Returns: - SubscriptionGroupResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups.json') - .http_method(HttpMethodEnum.POST) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionGroupResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SubscriptionGroupCreateErrorResponseException) - ).execute() - def list_subscription_groups(self, options=dict()): """Does a GET request to /subscription_groups.json. @@ -205,23 +109,17 @@ def list_subscription_groups(self, .deserialize_into(ListSubscriptionGroupsResponse.from_dictionary) ).execute() - def read_subscription_group(self, - uid, - include=None): - """Does a GET request to /subscription_groups/{uid}.json. + def find_subscription_group(self, + subscription_id): + """Does a GET request to /subscription_groups/lookup.json. - Use this endpoint to find subscription group details. - #### Current Billing Amount in Cents - Current billing amount for the subscription group is not returned by - default. If this information is desired, the - `include[]=current_billing_amount_in_cents` parameter must be provided - with the request. + Use this endpoint to find subscription group associated with + subscription. + If the subscription is not in a group endpoint will return 404 code. Args: - uid (str): The uid of the subscription group - include (List[SubscriptionGroupInclude], optional): Allows - including additional data in the response. Use in query: - `include[]=current_billing_amount_in_cents`. + subscription_id (str): The Advanced Billing id of the subscription + associated with the subscription group Returns: FullSubscriptionGroupResponse: Response from the API. OK @@ -236,45 +134,47 @@ def read_subscription_group(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/{uid}.json') + .path('/subscription_groups/lookup.json') .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('uid') - .value(uid) - .is_required(True) - .should_encode(True)) .query_param(Parameter() - .key('include') - .value(include)) + .key('subscription_id') + .value(subscription_id) + .is_required(True)) .header_param(Parameter() .key('accept') .value('application/json')) - .array_serialization_format(SerializationFormats.UN_INDEXED) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(FullSubscriptionGroupResponse.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) ).execute() - def update_subscription_group_members(self, - uid, - body=None): - """Does a PUT request to /subscription_groups/{uid}.json. + def signup_with_subscription_group(self, + body=None): + """Does a POST request to /subscription_groups/signup.json. - Use this endpoint to update subscription group members. - `"member_ids"` should contain an array of both subscription IDs to set - as group members and subscription IDs already present in the groups. - Not including them will result in removing them from subscription - group. To clean up members, just leave the array empty. + Create multiple subscriptions at once under the same customer and + consolidate them into a subscription group. + You must provide one and only one of the + `payer_id`/`payer_reference`/`payer_attributes` for the customer + attached to the group. + You must provide one and only one of the + `payment_profile_id`/`credit_card_attributes`/`bank_account_attributes` + for the payment profile attached to the group. + 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. Args: - uid (str): The uid of the subscription group - body (UpdateSubscriptionGroupRequest, optional): TODO: type + body (SubscriptionGroupSignupRequest, optional): TODO: type description here. Returns: - SubscriptionGroupResponse: Response from the API. OK + SubscriptionGroupSignupResponse: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -286,13 +186,8 @@ def update_subscription_group_members(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/{uid}.json') - .http_method(HttpMethodEnum.PUT) - .template_param(Parameter() - .key('uid') - .value(uid) - .is_required(True) - .should_encode(True)) + .path('/subscription_groups/signup.json') + .http_method(HttpMethodEnum.POST) .header_param(Parameter() .key('Content-Type') .value('application/json')) @@ -306,22 +201,22 @@ def update_subscription_group_members(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionGroupResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SubscriptionGroupUpdateErrorResponseException) + .deserialize_into(SubscriptionGroupSignupResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SubscriptionGroupSignupErrorResponseException) ).execute() - def delete_subscription_group(self, - uid): - """Does a DELETE request to /subscription_groups/{uid}.json. + def create_subscription_group(self, + body=None): + """Does a POST request to /subscription_groups.json. - Use this endpoint to delete subscription group. - Only groups without members can be deleted + Creates a subscription group with given members. Args: - uid (str): The uid of the subscription group + body (CreateSubscriptionGroupRequest, optional): TODO: type + description here. Returns: - DeleteSubscriptionGroupResponse: Response from the API. OK + SubscriptionGroupResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -333,38 +228,37 @@ def delete_subscription_group(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/{uid}.json') - .http_method(HttpMethodEnum.DELETE) - .template_param(Parameter() - .key('uid') - .value(uid) - .is_required(True) - .should_encode(True)) + .path('/subscription_groups.json') + .http_method(HttpMethodEnum.POST) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(DeleteSubscriptionGroupResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .deserialize_into(SubscriptionGroupResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SubscriptionGroupCreateErrorResponseException) ).execute() - def find_subscription_group(self, - subscription_id): - """Does a GET request to /subscription_groups/lookup.json. + def delete_subscription_group(self, + uid): + """Does a DELETE request to /subscription_groups/{uid}.json. - Use this endpoint to find subscription group associated with - subscription. - If the subscription is not in a group endpoint will return 404 code. + Use this endpoint to delete subscription group. + Only groups without members can be deleted Args: - subscription_id (str): The Advanced Billing id of the subscription - associated with the subscription group + uid (str): The uid of the subscription group Returns: - FullSubscriptionGroupResponse: Response from the API. OK + DeleteSubscriptionGroupResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -376,12 +270,13 @@ def find_subscription_group(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscription_groups/lookup.json') - .http_method(HttpMethodEnum.GET) - .query_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True)) + .path('/subscription_groups/{uid}.json') + .http_method(HttpMethodEnum.DELETE) + .template_param(Parameter() + .key('uid') + .value(uid) + .is_required(True) + .should_encode(True)) .header_param(Parameter() .key('accept') .value('application/json')) @@ -389,7 +284,7 @@ def find_subscription_group(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(FullSubscriptionGroupResponse.from_dictionary) + .deserialize_into(DeleteSubscriptionGroupResponse.from_dictionary) .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) ).execute() @@ -470,6 +365,111 @@ def add_subscription_to_group(self, .deserialize_into(SubscriptionGroupResponse.from_dictionary) ).execute() + def read_subscription_group(self, + uid, + include=None): + """Does a GET request to /subscription_groups/{uid}.json. + + Use this endpoint to find subscription group details. + #### Current Billing Amount in Cents + Current billing amount for the subscription group is not returned by + default. If this information is desired, the + `include[]=current_billing_amount_in_cents` parameter must be provided + with the request. + + Args: + uid (str): The uid of the subscription group + include (List[SubscriptionGroupInclude], optional): Allows + including additional data in the response. Use in query: + `include[]=current_billing_amount_in_cents`. + + Returns: + FullSubscriptionGroupResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscription_groups/{uid}.json') + .http_method(HttpMethodEnum.GET) + .template_param(Parameter() + .key('uid') + .value(uid) + .is_required(True) + .should_encode(True)) + .query_param(Parameter() + .key('include') + .value(include)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .array_serialization_format(SerializationFormats.UN_INDEXED) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(FullSubscriptionGroupResponse.from_dictionary) + ).execute() + + def update_subscription_group_members(self, + uid, + body=None): + """Does a PUT request to /subscription_groups/{uid}.json. + + Use this endpoint to update subscription group members. + `"member_ids"` should contain an array of both subscription IDs to set + as group members and subscription IDs already present in the groups. + Not including them will result in removing them from subscription + group. To clean up members, just leave the array empty. + + Args: + uid (str): The uid of the subscription group + body (UpdateSubscriptionGroupRequest, optional): TODO: type + description here. + + Returns: + SubscriptionGroupResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscription_groups/{uid}.json') + .http_method(HttpMethodEnum.PUT) + .template_param(Parameter() + .key('uid') + .value(uid) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(SubscriptionGroupResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SubscriptionGroupUpdateErrorResponseException) + ).execute() + def remove_subscription_from_group(self, subscription_id): """Does a DELETE request to /subscriptions/{subscription_id}/group.json. diff --git a/advancedbilling/controllers/subscription_invoice_account_controller.py b/advancedbilling/controllers/subscription_invoice_account_controller.py index 36157f70..ecf99278 100644 --- a/advancedbilling/controllers/subscription_invoice_account_controller.py +++ b/advancedbilling/controllers/subscription_invoice_account_controller.py @@ -16,11 +16,11 @@ from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.types.array_serialization_format import SerializationFormats from apimatic_core.authentication.multiple.single_auth import Single -from advancedbilling.models.account_balances import AccountBalances from advancedbilling.models.create_prepayment_response import CreatePrepaymentResponse from advancedbilling.models.prepayments_response import PrepaymentsResponse -from advancedbilling.models.service_credit import ServiceCredit from advancedbilling.models.prepayment_response import PrepaymentResponse +from advancedbilling.models.account_balances import AccountBalances +from advancedbilling.models.service_credit import ServiceCredit from advancedbilling.exceptions.api_exception import APIException from advancedbilling.exceptions.refund_prepayment_base_errors_response_exception import RefundPrepaymentBaseErrorsResponseException @@ -31,47 +31,6 @@ class SubscriptionInvoiceAccountController(BaseController): def __init__(self, config): super(SubscriptionInvoiceAccountController, self).__init__(config) - def read_account_balances(self, - subscription_id): - """Does a GET request to /subscriptions/{subscription_id}/account_balances.json. - - Returns the `balance_in_cents` of the Subscription's Pending Discount, - Service Credit, and Prepayment accounts, as well as the sum of the - Subscription's open, payable invoices. - - Args: - subscription_id (int): The Chargify id of the subscription - - Returns: - AccountBalances: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/account_balances.json') - .http_method(HttpMethodEnum.GET) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(AccountBalances.from_dictionary) - ).execute() - def create_prepayment(self, subscription_id, body=None): @@ -201,22 +160,27 @@ def list_prepayments(self, .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) ).execute() - def issue_service_credit(self, - subscription_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/service_credits.json. + def refund_prepayment(self, + subscription_id, + prepayment_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/prepayments/{prepayment_id}/refunds.json. - Credit will be added to the subscription in the amount specified in - the request body. The credit is subsequently applied to the next - generated invoice. + This endpoint will refund, completely or partially, a particular + prepayment applied to a subscription. The `prepayment_id` will be the + account transaction ID of the original payment. The prepayment must + have some amount remaining in order to be refunded. + The amount may be passed either as a decimal, with `amount`, or an + integer in cents, with `amount_in_cents`. Args: subscription_id (int): The Chargify id of the subscription - body (IssueServiceCreditRequest, optional): TODO: type description + prepayment_id (long|int): id of prepayment + body (RefundPrepaymentRequest, optional): TODO: type description here. Returns: - ServiceCredit: Response from the API. Created + PrepaymentResponse: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -228,13 +192,18 @@ def issue_service_credit(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/service_credits.json') + .path('/subscriptions/{subscription_id}/prepayments/{prepayment_id}/refunds.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('subscription_id') .value(subscription_id) .is_required(True) .should_encode(True)) + .template_param(Parameter() + .key('prepayment_id') + .value(prepayment_id) + .is_required(True) + .should_encode(True)) .header_param(Parameter() .key('Content-Type') .value('application/json')) @@ -248,26 +217,25 @@ def issue_service_credit(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ServiceCredit.from_dictionary) + .deserialize_into(PrepaymentResponse.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('400', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', RefundPrepaymentBaseErrorsResponseException) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', APIException) ).execute() - def deduct_service_credit(self, - subscription_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/service_credit_deductions.json. + def read_account_balances(self, + subscription_id): + """Does a GET request to /subscriptions/{subscription_id}/account_balances.json. - Credit will be removed from the subscription in the amount specified - in the request body. The credit amount being deducted must be equal to - or less than the current credit balance. + Returns the `balance_in_cents` of the Subscription's Pending Discount, + Service Credit, and Prepayment accounts, as well as the sum of the + Subscription's open, payable invoices. Args: subscription_id (int): The Chargify id of the subscription - body (DeductServiceCreditRequest, optional): TODO: type - description here. Returns: - void: Response from the API. OK + AccountBalances: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -279,43 +247,39 @@ def deduct_service_credit(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/service_credit_deductions.json') - .http_method(HttpMethodEnum.POST) + .path('/subscriptions/{subscription_id}/account_balances.json') + .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('subscription_id') .value(subscription_id) .is_required(True) .should_encode(True)) .header_param(Parameter() - .key('Content-Type') + .key('accept') .value('application/json')) - .body_param(Parameter() - .value(body)) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(AccountBalances.from_dictionary) ).execute() - def refund_prepayment(self, - subscription_id, - prepayment_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/prepayments/{prepayment_id}/refunds.json. + def issue_service_credit(self, + subscription_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/service_credits.json. - This endpoint will refund, completely or partially, a particular - prepayment applied to a subscription. The `prepayment_id` will be the - account transaction ID of the original payment. The prepayment must - have some amount remaining in order to be refunded. - The amount may be passed either as a decimal, with `amount`, or an - integer in cents, with `amount_in_cents`. + Credit will be added to the subscription in the amount specified in + the request body. The credit is subsequently applied to the next + generated invoice. Args: subscription_id (int): The Chargify id of the subscription - prepayment_id (long|int): id of prepayment - body (RefundPrepaymentRequest, optional): TODO: type description + body (IssueServiceCreditRequest, optional): TODO: type description here. Returns: - PrepaymentResponse: Response from the API. Created + ServiceCredit: Response from the API. Created Raises: APIException: When an error occurs while fetching the data from @@ -327,18 +291,13 @@ def refund_prepayment(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/prepayments/{prepayment_id}/refunds.json') + .path('/subscriptions/{subscription_id}/service_credits.json') .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('subscription_id') .value(subscription_id) .is_required(True) .should_encode(True)) - .template_param(Parameter() - .key('prepayment_id') - .value(prepayment_id) - .is_required(True) - .should_encode(True)) .header_param(Parameter() .key('Content-Type') .value('application/json')) @@ -352,8 +311,49 @@ def refund_prepayment(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(PrepaymentResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('400', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', RefundPrepaymentBaseErrorsResponseException) + .deserialize_into(ServiceCredit.from_dictionary) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', APIException) ).execute() + + def deduct_service_credit(self, + subscription_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/service_credit_deductions.json. + + Credit will be removed from the subscription in the amount specified + in the request body. The credit amount being deducted must be equal to + or less than the current credit balance. + + Args: + subscription_id (int): The Chargify id of the subscription + body (DeductServiceCreditRequest, optional): TODO: type + description here. + + Returns: + void: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/service_credit_deductions.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).execute() diff --git a/advancedbilling/controllers/subscription_notes_controller.py b/advancedbilling/controllers/subscription_notes_controller.py index bb2265ed..af14f698 100644 --- a/advancedbilling/controllers/subscription_notes_controller.py +++ b/advancedbilling/controllers/subscription_notes_controller.py @@ -24,63 +24,6 @@ class SubscriptionNotesController(BaseController): def __init__(self, config): super(SubscriptionNotesController, self).__init__(config) - def create_subscription_note(self, - subscription_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/notes.json. - - Use the following method to create a note for a subscription. - ## How to Use Subscription Notes - Notes allow you to record information about a particular Subscription - in a free text format. - If you have structured data such as birth date, color, etc., consider - using Metadata instead. - Full documentation on how to use Notes in the Advanced Billing UI can - be located - [here](https://maxio.zendesk.com/hc/en-us/articles/24251712214413-Subsc - ription-Summary-Overview). - - Args: - subscription_id (int): The Chargify id of the subscription - body (UpdateSubscriptionNoteRequest, optional): TODO: type - description here. - - Returns: - SubscriptionNoteResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/notes.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionNoteResponse.from_dictionary) - ).execute() - def list_subscription_notes(self, options=dict()): """Does a GET request to /subscriptions/{subscription_id}/notes.json. @@ -148,20 +91,19 @@ def list_subscription_notes(self, .deserialize_into(SubscriptionNoteResponse.from_dictionary) ).execute() - def read_subscription_note(self, - subscription_id, - note_id): - """Does a GET request to /subscriptions/{subscription_id}/notes/{note_id}.json. + def delete_subscription_note(self, + subscription_id, + note_id): + """Does a DELETE request to /subscriptions/{subscription_id}/notes/{note_id}.json. - Once you have obtained the ID of the note you wish to read, use this - method to show a particular note attached to a subscription. + Use the following method to delete a note for a Subscription. Args: subscription_id (int): The Chargify id of the subscription note_id (int): The Advanced Billing id of the note Returns: - SubscriptionNoteResponse: Response from the API. OK + void: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -174,7 +116,7 @@ def read_subscription_note(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/subscriptions/{subscription_id}/notes/{note_id}.json') - .http_method(HttpMethodEnum.GET) + .http_method(HttpMethodEnum.DELETE) .template_param(Parameter() .key('subscription_id') .value(subscription_id) @@ -185,9 +127,59 @@ def read_subscription_note(self, .value(note_id) .is_required(True) .should_encode(True)) + .auth(Single('BasicAuth')) + ).execute() + + def create_subscription_note(self, + subscription_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/notes.json. + + Use the following method to create a note for a subscription. + ## How to Use Subscription Notes + Notes allow you to record information about a particular Subscription + in a free text format. + If you have structured data such as birth date, color, etc., consider + using Metadata instead. + Full documentation on how to use Notes in the Advanced Billing UI can + be located + [here](https://maxio.zendesk.com/hc/en-us/articles/24251712214413-Subsc + ription-Summary-Overview). + + Args: + subscription_id (int): The Chargify id of the subscription + body (UpdateSubscriptionNoteRequest, optional): TODO: type + description here. + + Returns: + SubscriptionNoteResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/notes.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() @@ -195,19 +187,17 @@ def read_subscription_note(self, .deserialize_into(SubscriptionNoteResponse.from_dictionary) ).execute() - def update_subscription_note(self, - subscription_id, - note_id, - body=None): - """Does a PUT request to /subscriptions/{subscription_id}/notes/{note_id}.json. + def read_subscription_note(self, + subscription_id, + note_id): + """Does a GET request to /subscriptions/{subscription_id}/notes/{note_id}.json. - Use the following method to update a note for a Subscription. + Once you have obtained the ID of the note you wish to read, use this + method to show a particular note attached to a subscription. Args: subscription_id (int): The Chargify id of the subscription note_id (int): The Advanced Billing id of the note - body (UpdateSubscriptionNoteRequest, optional): TODO: type - description here. Returns: SubscriptionNoteResponse: Response from the API. OK @@ -223,7 +213,7 @@ def update_subscription_note(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/subscriptions/{subscription_id}/notes/{note_id}.json') - .http_method(HttpMethodEnum.PUT) + .http_method(HttpMethodEnum.GET) .template_param(Parameter() .key('subscription_id') .value(subscription_id) @@ -234,15 +224,9 @@ def update_subscription_note(self, .value(note_id) .is_required(True) .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() @@ -250,19 +234,22 @@ def update_subscription_note(self, .deserialize_into(SubscriptionNoteResponse.from_dictionary) ).execute() - def delete_subscription_note(self, + def update_subscription_note(self, subscription_id, - note_id): - """Does a DELETE request to /subscriptions/{subscription_id}/notes/{note_id}.json. + note_id, + body=None): + """Does a PUT request to /subscriptions/{subscription_id}/notes/{note_id}.json. - Use the following method to delete a note for a Subscription. + Use the following method to update a note for a Subscription. Args: subscription_id (int): The Chargify id of the subscription note_id (int): The Advanced Billing id of the note + body (UpdateSubscriptionNoteRequest, optional): TODO: type + description here. Returns: - void: Response from the API. OK + SubscriptionNoteResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -275,7 +262,7 @@ def delete_subscription_note(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/subscriptions/{subscription_id}/notes/{note_id}.json') - .http_method(HttpMethodEnum.DELETE) + .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('subscription_id') .value(subscription_id) @@ -286,5 +273,18 @@ def delete_subscription_note(self, .value(note_id) .is_required(True) .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(SubscriptionNoteResponse.from_dictionary) ).execute() diff --git a/advancedbilling/controllers/subscription_status_controller.py b/advancedbilling/controllers/subscription_status_controller.py index 3b26159f..4e5b17af 100644 --- a/advancedbilling/controllers/subscription_status_controller.py +++ b/advancedbilling/controllers/subscription_status_controller.py @@ -28,20 +28,22 @@ class SubscriptionStatusController(BaseController): def __init__(self, config): super(SubscriptionStatusController, self).__init__(config) - def retry_subscription(self, - subscription_id): - """Does a PUT request to /subscriptions/{subscription_id}/retry.json. + def update_automatic_subscription_resumption(self, + subscription_id, + body=None): + """Does a PUT request to /subscriptions/{subscription_id}/hold.json. - Advanced Billing offers the ability to retry collecting the balance - due on a past due Subscription without waiting for the next scheduled - attempt. - ## Successful Reactivation - The response will be `200 OK` with the updated Subscription. - ## Failed Reactivation - The response will be `422 "Unprocessable Entity`. + Once a subscription has been paused / put on hold, you can update the + date which was specified to automatically resume the subscription. + To update a subscription's resume date, use this method to change or + update the `automatically_resume_at` date. + ### Remove the resume date + Alternately, you can change the `automatically_resume_at` to `null` if + you would like the subscription to not have a resume date. Args: subscription_id (int): The Chargify id of the subscription + body (PauseRequest, optional): TODO: type description here. Returns: SubscriptionResponse: Response from the API. OK @@ -56,16 +58,22 @@ def retry_subscription(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/retry.json') + .path('/subscriptions/{subscription_id}/hold.json') .http_method(HttpMethodEnum.PUT) .template_param(Parameter() .key('subscription_id') .value(subscription_id) .is_required(True) .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() @@ -74,13 +82,18 @@ def retry_subscription(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def cancel_subscription(self, - subscription_id, - body=None): - """Does a DELETE request to /subscriptions/{subscription_id}.json. + def initiate_delayed_cancellation(self, + subscription_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/delayed_cancel.json. - The DELETE action causes the cancellation of the Subscription. This - means, the method sets the Subscription state to "canceled". + Advanced Billing offers the ability to cancel a subscription at the + end of the current billing period. This period is set by its current + product. + Requesting to cancel the subscription at the end of the period sets + the `cancel_at_end_of_period` flag to true. + Note that you cannot set `cancel_at_end_of_period` at subscription + creation, or if the subscription is past due. Args: subscription_id (int): The Chargify id of the subscription @@ -88,7 +101,7 @@ def cancel_subscription(self, here. Returns: - SubscriptionResponse: Response from the API. OK + DelayedCancellationResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -100,8 +113,8 @@ def cancel_subscription(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}.json') - .http_method(HttpMethodEnum.DELETE) + .path('/subscriptions/{subscription_id}/delayed_cancel.json') + .http_method(HttpMethodEnum.POST) .template_param(Parameter() .key('subscription_id') .value(subscription_id) @@ -120,9 +133,133 @@ def cancel_subscription(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionResponse.from_dictionary) + .deserialize_into(DelayedCancellationResponse.from_dictionary) .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', APIException) + ).execute() + + def cancel_delayed_cancellation(self, + subscription_id): + """Does a DELETE request to /subscriptions/{subscription_id}/delayed_cancel.json. + + Removing the delayed cancellation on a subscription will ensure that + it doesn't get canceled at the end of the period that it is in. The + request will reset the `cancel_at_end_of_period` flag to `false`. + This endpoint is idempotent. If the subscription was not set to cancel + in the future, removing the delayed cancellation has no effect and the + call will be successful. + + Args: + subscription_id (int): The Chargify id of the subscription + + Returns: + DelayedCancellationResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/delayed_cancel.json') + .http_method(HttpMethodEnum.DELETE) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(DelayedCancellationResponse.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + ).execute() + + def preview_renewal(self, + subscription_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/renewals/preview.json. + + 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-Subsc + riber-Interface-Overview). + ## Optional Component Fields + This endpoint is particularly useful due to the fact that it will + return the computed billing amount for the base product and the + components which are in use by a subscriber. + By default, the preview will include billing details for all + components _at their **current** quantities_. This means: + * Current `allocated_quantity` for quantity-based components + * Current enabled/disabled status for on/off components + * Current metered usage `unit_balance` for metered components + * Current metric quantity value for events recorded thus far for + events-based components + In the above statements, "current" means the quantity or value as of + the call to the renewal preview endpoint. We do not predict + end-of-period values for components, so metered or events-based usage + may be less than it will eventually be at the end of the period. + Optionally, **you may provide your own custom quantities** for any + component to see a billing preview for non-current quantities. This is + accomplished by sending a request body with data under the + `components` key. See the request body documentation below. + ## Subscription Side Effects + You can request a `POST` to obtain this data from the endpoint without + any side effects. Plain and simple, this will preview data, not log + any changes against a subscription. + + Args: + subscription_id (int): The Chargify id of the subscription + body (RenewalPreviewRequest, optional): TODO: type description + here. + + Returns: + RenewalPreviewResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/renewals/preview.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(RenewalPreviewResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() def resume_subscription(self, @@ -227,22 +364,20 @@ def pause_subscription(self, .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def update_automatic_subscription_resumption(self, - subscription_id, - body=None): - """Does a PUT request to /subscriptions/{subscription_id}/hold.json. + def retry_subscription(self, + subscription_id): + """Does a PUT request to /subscriptions/{subscription_id}/retry.json. - Once a subscription has been paused / put on hold, you can update the - date which was specified to automatically resume the subscription. - To update a subscription's resume date, use this method to change or - update the `automatically_resume_at` date. - ### Remove the resume date - Alternately, you can change the `automatically_resume_at` to `null` if - you would like the subscription to not have a resume date. + Advanced Billing offers the ability to retry collecting the balance + due on a past due Subscription without waiting for the next scheduled + attempt. + ## Successful Reactivation + The response will be `200 OK` with the updated Subscription. + ## Failed Reactivation + The response will be `422 "Unprocessable Entity`. Args: subscription_id (int): The Chargify id of the subscription - body (PauseRequest, optional): TODO: type description here. Returns: SubscriptionResponse: Response from the API. OK @@ -257,8 +392,52 @@ def update_automatic_subscription_resumption(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/hold.json') + .path('/subscriptions/{subscription_id}/retry.json') .http_method(HttpMethodEnum.PUT) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(SubscriptionResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + ).execute() + + def cancel_subscription(self, + subscription_id, + body=None): + """Does a DELETE request to /subscriptions/{subscription_id}.json. + + The DELETE action causes the cancellation of the Subscription. This + means, the method sets the Subscription state to "canceled". + + Args: + subscription_id (int): The Chargify id of the subscription + body (CancellationRequest, optional): TODO: type description + here. + + Returns: + SubscriptionResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}.json') + .http_method(HttpMethodEnum.DELETE) .template_param(Parameter() .key('subscription_id') .value(subscription_id) @@ -278,7 +457,48 @@ def update_automatic_subscription_resumption(self, ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(SubscriptionResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', APIException) + ).execute() + + def cancel_dunning(self, + subscription_id): + """Does a POST request to /subscriptions/{subscription_id}/cancel_dunning.json. + + If a subscription is currently in dunning, the subscription will be + set to active and the active Dunner will be resolved. + + Args: + subscription_id (int): The Chargify id of the subscription + + Returns: + SubscriptionResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/cancel_dunning.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(SubscriptionResponse.from_dictionary) ).execute() def reactivate_subscription(self, @@ -469,223 +689,3 @@ def reactivate_subscription(self, .deserialize_into(SubscriptionResponse.from_dictionary) .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - - def initiate_delayed_cancellation(self, - subscription_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/delayed_cancel.json. - - Advanced Billing offers the ability to cancel a subscription at the - end of the current billing period. This period is set by its current - product. - Requesting to cancel the subscription at the end of the period sets - the `cancel_at_end_of_period` flag to true. - Note that you cannot set `cancel_at_end_of_period` at subscription - creation, or if the subscription is past due. - - Args: - subscription_id (int): The Chargify id of the subscription - body (CancellationRequest, optional): TODO: type description - here. - - Returns: - DelayedCancellationResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/delayed_cancel.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(DelayedCancellationResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - ).execute() - - def cancel_delayed_cancellation(self, - subscription_id): - """Does a DELETE request to /subscriptions/{subscription_id}/delayed_cancel.json. - - Removing the delayed cancellation on a subscription will ensure that - it doesn't get canceled at the end of the period that it is in. The - request will reset the `cancel_at_end_of_period` flag to `false`. - This endpoint is idempotent. If the subscription was not set to cancel - in the future, removing the delayed cancellation has no effect and the - call will be successful. - - Args: - subscription_id (int): The Chargify id of the subscription - - Returns: - DelayedCancellationResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/delayed_cancel.json') - .http_method(HttpMethodEnum.DELETE) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(DelayedCancellationResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - ).execute() - - def cancel_dunning(self, - subscription_id): - """Does a POST request to /subscriptions/{subscription_id}/cancel_dunning.json. - - If a subscription is currently in dunning, the subscription will be - set to active and the active Dunner will be resolved. - - Args: - subscription_id (int): The Chargify id of the subscription - - Returns: - SubscriptionResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/cancel_dunning.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionResponse.from_dictionary) - ).execute() - - def preview_renewal(self, - subscription_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/renewals/preview.json. - - 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-Subsc - riber-Interface-Overview). - ## Optional Component Fields - This endpoint is particularly useful due to the fact that it will - return the computed billing amount for the base product and the - components which are in use by a subscriber. - By default, the preview will include billing details for all - components _at their **current** quantities_. This means: - * Current `allocated_quantity` for quantity-based components - * Current enabled/disabled status for on/off components - * Current metered usage `unit_balance` for metered components - * Current metric quantity value for events recorded thus far for - events-based components - In the above statements, "current" means the quantity or value as of - the call to the renewal preview endpoint. We do not predict - end-of-period values for components, so metered or events-based usage - may be less than it will eventually be at the end of the period. - Optionally, **you may provide your own custom quantities** for any - component to see a billing preview for non-current quantities. This is - accomplished by sending a request body with data under the - `components` key. See the request body documentation below. - ## Subscription Side Effects - You can request a `POST` to obtain this data from the endpoint without - any side effects. Plain and simple, this will preview data, not log - any changes against a subscription. - - Args: - subscription_id (int): The Chargify id of the subscription - body (RenewalPreviewRequest, optional): TODO: type description - here. - - Returns: - RenewalPreviewResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/renewals/preview.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(RenewalPreviewResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) - ).execute() diff --git a/advancedbilling/controllers/subscriptions_controller.py b/advancedbilling/controllers/subscriptions_controller.py index 9e25e9dc..5d884d1f 100644 --- a/advancedbilling/controllers/subscriptions_controller.py +++ b/advancedbilling/controllers/subscriptions_controller.py @@ -19,18 +19,427 @@ from advancedbilling.models.subscription_response import SubscriptionResponse from advancedbilling.models.prepaid_configuration_response import PrepaidConfigurationResponse from advancedbilling.models.subscription_preview_response import SubscriptionPreviewResponse +from advancedbilling.exceptions.subscription_add_coupon_error_exception import SubscriptionAddCouponErrorException from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException from advancedbilling.exceptions.single_error_response_exception import SingleErrorResponseException -from advancedbilling.exceptions.subscription_add_coupon_error_exception import SubscriptionAddCouponErrorException from advancedbilling.exceptions.subscription_remove_coupon_errors_exception import SubscriptionRemoveCouponErrorsException from advancedbilling.exceptions.error_array_map_response_exception import ErrorArrayMapResponseException -class SubscriptionsController(BaseController): +class SubscriptionsController(BaseController): + + """A Controller to access Endpoints in the advancedbilling API.""" + def __init__(self, config): + super(SubscriptionsController, self).__init__(config) + + def list_subscriptions(self, + options=dict()): + """Does a GET request to /subscriptions.json. + + This method will return an array of subscriptions from a Site. Pay + close attention to query string filters and pagination in order to + control responses from the server. + ## Search for a subscription + Use the query strings below to search for a subscription using the + criteria available. The return value will be an array. + ## Self-Service Page token + Self-Service Page token for the subscriptions is not returned by + default. If this information is desired, the + include[]=self_service_page_token parameter must be provided with the + request. + + Args: + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + 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 + 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`. + per_page -- int -- 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`. + state -- SubscriptionStateFilter -- The current state of + the subscription + product -- int -- The product id of the subscription. + (Note that the product handle cannot be used.) + product_price_point_id -- int -- The ID of the product + price point. If supplied, product is required + coupon -- int -- The numeric id of the coupon currently + applied to the subscription. (This can be found in the + URL when editing a coupon. Note that the coupon code + cannot be used.) + date_field -- SubscriptionDateField -- The type of filter + you'd like to apply to your search. Allowed Values: , + current_period_ends_at, current_period_starts_at, + created_at, activated_at, canceled_at, expires_at, + trial_started_at, trial_ended_at, updated_at + start_date -- date -- The start date (format YYYY-MM-DD) + with which to filter the date_field. Returns + subscriptions with a timestamp at or after midnight + (12:00:00 AM) in your site’s time zone on the date + specified. Use in query `start_date=2022-07-01`. + end_date -- date -- The end date (format YYYY-MM-DD) with + which to filter the date_field. Returns subscriptions + with a timestamp up to and including 11:59:59PM in + your site’s time zone on the date specified. Use in + query `end_date=2022-08-01`. + start_datetime -- datetime -- The start date and time + (format YYYY-MM-DD HH:MM:SS) with which to filter the + date_field. Returns subscriptions with a timestamp at + or after 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 start_date. Use in query + `start_datetime=2022-07-01 09:00:05`. + end_datetime -- datetime -- The end date and time (format + YYYY-MM-DD HH:MM:SS) with which to filter the + date_field. Returns subscriptions 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 + `end_datetime=2022-08-01 10:00:05`. + metadata -- Dict[str, str] -- The value of the metadata + field specified in the parameter. Use in query + `metadata[my-field]=value&metadata[other-field]=another + _value`. + direction -- SortingDirection -- Controls the order in + which results are returned. Use in query + `direction=asc`. + sort -- SubscriptionSort -- The attribute by which to + sort + include -- List[SubscriptionListInclude] -- Allows + including additional data in the response. Use in + query: `include[]=self_service_page_token`. + + Returns: + List[SubscriptionResponse]: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions.json') + .http_method(HttpMethodEnum.GET) + .query_param(Parameter() + .key('page') + .value(options.get('page', None))) + .query_param(Parameter() + .key('per_page') + .value(options.get('per_page', None))) + .query_param(Parameter() + .key('state') + .value(options.get('state', None))) + .query_param(Parameter() + .key('product') + .value(options.get('product', None))) + .query_param(Parameter() + .key('product_price_point_id') + .value(options.get('product_price_point_id', None))) + .query_param(Parameter() + .key('coupon') + .value(options.get('coupon', None))) + .query_param(Parameter() + .key('date_field') + .value(options.get('date_field', None))) + .query_param(Parameter() + .key('start_date') + .value(options.get('start_date', None))) + .query_param(Parameter() + .key('end_date') + .value(options.get('end_date', None))) + .query_param(Parameter() + .key('start_datetime') + .value(APIHelper.when_defined(APIHelper.RFC3339DateTime, options.get('start_datetime', None)))) + .query_param(Parameter() + .key('end_datetime') + .value(APIHelper.when_defined(APIHelper.RFC3339DateTime, options.get('end_datetime', None)))) + .query_param(Parameter() + .key('metadata') + .value(options.get('metadata', None))) + .query_param(Parameter() + .key('direction') + .value(options.get('direction', None))) + .query_param(Parameter() + .key('sort') + .value(options.get('sort', None))) + .query_param(Parameter() + .key('include') + .value(options.get('include', None))) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .array_serialization_format(SerializationFormats.UN_INDEXED) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(SubscriptionResponse.from_dictionary) + ).execute() + + def purge_subscription(self, + subscription_id, + ack, + cascade=None): + """Does a POST request to /subscriptions/{subscription_id}/purge.json. + + 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. + ### Delete customer and payment profile + The query params will be: + `?ack={customer_id}&cascade[]=customer&cascade[]=payment_profile` + + Args: + subscription_id (int): The Chargify id of the subscription + ack (int): id of the customer. + cascade (List[SubscriptionPurgeType], optional): Options are + "customer" or "payment_profile". Use in query: + `cascade[]=customer&cascade[]=payment_profile`. + + Returns: + void: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/purge.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .query_param(Parameter() + .key('ack') + .value(ack) + .is_required(True)) + .query_param(Parameter() + .key('cascade') + .value(cascade)) + .array_serialization_format(SerializationFormats.CSV) + .auth(Single('BasicAuth')) + ).execute() + + def apply_coupons_to_subscription(self, + subscription_id, + code=None, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/add_coupon.json. + + An existing subscription can accommodate multiple discounts/coupon + codes. This is only applicable if each coupon is stackable. For more + information on stackable coupons, we recommend reviewing our [coupon + documentation.](https://maxio.zendesk.com/hc/en-us/articles/24261259337 + 101-Coupons-and-Subscriptions#stackability-rules) + ## Query Parameters vs Request Body Parameters + Passing in a coupon code as a query parameter will add the code to the + subscription, completely replacing all existing coupon codes on the + subscription. + For this reason, using this query parameter on this endpoint has been + deprecated in favor of using the request body parameters as described + below. When passing in request body parameters, the list of coupon + codes will simply be added to any existing list of codes on the + subscription. + + Args: + subscription_id (int): The Chargify id of the subscription + code (str, optional): A code for the coupon that would be applied + to a subscription + body (AddCouponsRequest, optional): TODO: type description here. + + Returns: + SubscriptionResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/add_coupon.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .query_param(Parameter() + .key('code') + .value(code)) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(SubscriptionResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SubscriptionAddCouponErrorException) + ).execute() + + def update_prepaid_subscription_configuration(self, + subscription_id, + body=None): + """Does a POST request to /subscriptions/{subscription_id}/prepaid_configurations.json. + + Use this endpoint to update a subscription's prepaid configuration. + + Args: + subscription_id (int): The Chargify id of the subscription + body (UpsertPrepaidConfigurationRequest, optional): TODO: type + description here. + + Returns: + PrepaidConfigurationResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/{subscription_id}/prepaid_configurations.json') + .http_method(HttpMethodEnum.POST) + .template_param(Parameter() + .key('subscription_id') + .value(subscription_id) + .is_required(True) + .should_encode(True)) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(PrepaidConfigurationResponse.from_dictionary) + ).execute() + + def preview_subscription(self, + body=None): + """Does a POST request to /subscriptions/preview.json. + + The Chargify API allows you to preview a subscription by POSTing the + same JSON or XML as for a subscription creation. + The "Next Billing" amount and "Next Billing" date are represented in + each Subscriber's Summary. For more information, please see our + documentation + [here](https://maxio.zendesk.com/hc/en-us/articles/24252493695757-Subsc + riber-Interface-Overview). + ## Side effects + A subscription will not be created by sending a POST to this endpoint. + It is meant to serve as a prediction. + ## Taxable Subscriptions + This endpoint will preview taxes applicable to a purchase. In order + for taxes to be previewed, the following conditions must be met: + + Taxes must be configured on the subscription + + 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/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. + 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. - """A Controller to access Endpoints in the advancedbilling API.""" - def __init__(self, config): - super(SubscriptionsController, self).__init__(config) + Args: + body (CreateSubscriptionRequest, optional): TODO: type description + here. + + Returns: + SubscriptionPreviewResponse: Response from the API. OK + + Raises: + APIException: When an error occurs while fetching the data from + the remote API. This exception includes the HTTP Response + code, an error message, and the HTTP body that was received in + the request. + + """ + + return super().new_api_call_builder.request( + RequestBuilder().server(Server.DEFAULT) + .path('/subscriptions/preview.json') + .http_method(HttpMethodEnum.POST) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) + .header_param(Parameter() + .key('accept') + .value('application/json')) + .body_serializer(APIHelper.json_serialize) + .auth(Single('BasicAuth')) + ).response( + ResponseHandler() + .deserializer(APIHelper.json_deserialize) + .deserialize_into(SubscriptionPreviewResponse.from_dictionary) + ).execute() def create_subscription(self, body=None): @@ -868,184 +1277,22 @@ def create_subscription(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/subscriptions.json') - .http_method(HttpMethodEnum.POST) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) - ).execute() - - def list_subscriptions(self, - options=dict()): - """Does a GET request to /subscriptions.json. - - This method will return an array of subscriptions from a Site. Pay - close attention to query string filters and pagination in order to - control responses from the server. - ## Search for a subscription - Use the query strings below to search for a subscription using the - criteria available. The return value will be an array. - ## Self-Service Page token - Self-Service Page token for the subscriptions is not returned by - default. If this information is desired, the - include[]=self_service_page_token parameter must be provided with the - request. - - Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - 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 - 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`. - per_page -- int -- 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`. - state -- SubscriptionStateFilter -- The current state of - the subscription - product -- int -- The product id of the subscription. - (Note that the product handle cannot be used.) - product_price_point_id -- int -- The ID of the product - price point. If supplied, product is required - coupon -- int -- The numeric id of the coupon currently - applied to the subscription. (This can be found in the - URL when editing a coupon. Note that the coupon code - cannot be used.) - date_field -- SubscriptionDateField -- The type of filter - you'd like to apply to your search. Allowed Values: , - current_period_ends_at, current_period_starts_at, - created_at, activated_at, canceled_at, expires_at, - trial_started_at, trial_ended_at, updated_at - start_date -- date -- The start date (format YYYY-MM-DD) - with which to filter the date_field. Returns - subscriptions with a timestamp at or after midnight - (12:00:00 AM) in your site’s time zone on the date - specified. Use in query `start_date=2022-07-01`. - end_date -- date -- The end date (format YYYY-MM-DD) with - which to filter the date_field. Returns subscriptions - with a timestamp up to and including 11:59:59PM in - your site’s time zone on the date specified. Use in - query `end_date=2022-08-01`. - start_datetime -- datetime -- The start date and time - (format YYYY-MM-DD HH:MM:SS) with which to filter the - date_field. Returns subscriptions with a timestamp at - or after 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 start_date. Use in query - `start_datetime=2022-07-01 09:00:05`. - end_datetime -- datetime -- The end date and time (format - YYYY-MM-DD HH:MM:SS) with which to filter the - date_field. Returns subscriptions 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 - `end_datetime=2022-08-01 10:00:05`. - metadata -- Dict[str, str] -- The value of the metadata - field specified in the parameter. Use in query - `metadata[my-field]=value&metadata[other-field]=another - _value`. - direction -- SortingDirection -- Controls the order in - which results are returned. Use in query - `direction=asc`. - sort -- SubscriptionSort -- The attribute by which to - sort - include -- List[SubscriptionListInclude] -- Allows - including additional data in the response. Use in - query: `include[]=self_service_page_token`. - - Returns: - List[SubscriptionResponse]: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions.json') - .http_method(HttpMethodEnum.GET) - .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) - .query_param(Parameter() - .key('state') - .value(options.get('state', None))) - .query_param(Parameter() - .key('product') - .value(options.get('product', None))) - .query_param(Parameter() - .key('product_price_point_id') - .value(options.get('product_price_point_id', None))) - .query_param(Parameter() - .key('coupon') - .value(options.get('coupon', None))) - .query_param(Parameter() - .key('date_field') - .value(options.get('date_field', None))) - .query_param(Parameter() - .key('start_date') - .value(options.get('start_date', None))) - .query_param(Parameter() - .key('end_date') - .value(options.get('end_date', None))) - .query_param(Parameter() - .key('start_datetime') - .value(APIHelper.when_defined(APIHelper.RFC3339DateTime, options.get('start_datetime', None)))) - .query_param(Parameter() - .key('end_datetime') - .value(APIHelper.when_defined(APIHelper.RFC3339DateTime, options.get('end_datetime', None)))) - .query_param(Parameter() - .key('metadata') - .value(options.get('metadata', None))) - .query_param(Parameter() - .key('direction') - .value(options.get('direction', None))) - .query_param(Parameter() - .key('sort') - .value(options.get('sort', None))) - .query_param(Parameter() - .key('include') - .value(options.get('include', None))) + .http_method(HttpMethodEnum.POST) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) - .array_serialization_format(SerializationFormats.UN_INDEXED) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) .deserialize_into(SubscriptionResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() def update_subscription(self, @@ -1324,253 +1571,6 @@ def find_subscription(self, .deserialize_into(SubscriptionResponse.from_dictionary) ).execute() - def purge_subscription(self, - subscription_id, - ack, - cascade=None): - """Does a POST request to /subscriptions/{subscription_id}/purge.json. - - 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. - ### Delete customer and payment profile - The query params will be: - `?ack={customer_id}&cascade[]=customer&cascade[]=payment_profile` - - Args: - subscription_id (int): The Chargify id of the subscription - ack (int): id of the customer. - cascade (List[SubscriptionPurgeType], optional): Options are - "customer" or "payment_profile". Use in query: - `cascade[]=customer&cascade[]=payment_profile`. - - Returns: - void: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/purge.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .query_param(Parameter() - .key('ack') - .value(ack) - .is_required(True)) - .query_param(Parameter() - .key('cascade') - .value(cascade)) - .array_serialization_format(SerializationFormats.CSV) - .auth(Single('BasicAuth')) - ).execute() - - def update_prepaid_subscription_configuration(self, - subscription_id, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/prepaid_configurations.json. - - Use this endpoint to update a subscription's prepaid configuration. - - Args: - subscription_id (int): The Chargify id of the subscription - body (UpsertPrepaidConfigurationRequest, optional): TODO: type - description here. - - Returns: - PrepaidConfigurationResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/prepaid_configurations.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(PrepaidConfigurationResponse.from_dictionary) - ).execute() - - def preview_subscription(self, - body=None): - """Does a POST request to /subscriptions/preview.json. - - The Chargify API allows you to preview a subscription by POSTing the - same JSON or XML as for a subscription creation. - The "Next Billing" amount and "Next Billing" date are represented in - each Subscriber's Summary. For more information, please see our - documentation - [here](https://maxio.zendesk.com/hc/en-us/articles/24252493695757-Subsc - riber-Interface-Overview). - ## Side effects - A subscription will not be created by sending a POST to this endpoint. - It is meant to serve as a prediction. - ## Taxable Subscriptions - This endpoint will preview taxes applicable to a purchase. In order - for taxes to be previewed, the following conditions must be met: - + Taxes must be configured on the subscription - + 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/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. - 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. - - Args: - body (CreateSubscriptionRequest, optional): TODO: type description - here. - - Returns: - SubscriptionPreviewResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/preview.json') - .http_method(HttpMethodEnum.POST) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionPreviewResponse.from_dictionary) - ).execute() - - def apply_coupons_to_subscription(self, - subscription_id, - code=None, - body=None): - """Does a POST request to /subscriptions/{subscription_id}/add_coupon.json. - - An existing subscription can accommodate multiple discounts/coupon - codes. This is only applicable if each coupon is stackable. For more - information on stackable coupons, we recommend reviewing our [coupon - documentation.](https://maxio.zendesk.com/hc/en-us/articles/24261259337 - 101-Coupons-and-Subscriptions#stackability-rules) - ## Query Parameters vs Request Body Parameters - Passing in a coupon code as a query parameter will add the code to the - subscription, completely replacing all existing coupon codes on the - subscription. - For this reason, using this query parameter on this endpoint has been - deprecated in favor of using the request body parameters as described - below. When passing in request body parameters, the list of coupon - codes will simply be added to any existing list of codes on the - subscription. - - Args: - subscription_id (int): The Chargify id of the subscription - code (str, optional): A code for the coupon that would be applied - to a subscription - body (AddCouponsRequest, optional): TODO: type description here. - - Returns: - SubscriptionResponse: Response from the API. OK - - Raises: - APIException: When an error occurs while fetching the data from - the remote API. This exception includes the HTTP Response - code, an error message, and the HTTP body that was received in - the request. - - """ - - return super().new_api_call_builder.request( - RequestBuilder().server(Server.DEFAULT) - .path('/subscriptions/{subscription_id}/add_coupon.json') - .http_method(HttpMethodEnum.POST) - .template_param(Parameter() - .key('subscription_id') - .value(subscription_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .query_param(Parameter() - .key('code') - .value(code)) - .body_param(Parameter() - .value(body)) - .header_param(Parameter() - .key('accept') - .value('application/json')) - .body_serializer(APIHelper.json_serialize) - .auth(Single('BasicAuth')) - ).response( - ResponseHandler() - .deserializer(APIHelper.json_deserialize) - .deserialize_into(SubscriptionResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', SubscriptionAddCouponErrorException) - ).execute() - def remove_coupon_from_subscription(self, subscription_id, coupon_code=None): diff --git a/advancedbilling/controllers/webhooks_controller.py b/advancedbilling/controllers/webhooks_controller.py index 80239d48..24e1d43d 100644 --- a/advancedbilling/controllers/webhooks_controller.py +++ b/advancedbilling/controllers/webhooks_controller.py @@ -15,11 +15,11 @@ from apimatic_core.types.parameter import Parameter from advancedbilling.http.http_method_enum import HttpMethodEnum from apimatic_core.authentication.multiple.single_auth import Single -from advancedbilling.models.webhook_response import WebhookResponse -from advancedbilling.models.enable_webhooks_response import EnableWebhooksResponse -from advancedbilling.models.replay_webhooks_response import ReplayWebhooksResponse from advancedbilling.models.endpoint_response import EndpointResponse +from advancedbilling.models.enable_webhooks_response import EnableWebhooksResponse from advancedbilling.models.endpoint import Endpoint +from advancedbilling.models.replay_webhooks_response import ReplayWebhooksResponse +from advancedbilling.models.webhook_response import WebhookResponse from advancedbilling.exceptions.error_list_response_exception import ErrorListResponseException from advancedbilling.exceptions.api_exception import APIException @@ -30,72 +30,23 @@ class WebhooksController(BaseController): def __init__(self, config): super(WebhooksController, self).__init__(config) - def list_webhooks(self, - options=dict()): - """Does a GET request to /webhooks.json. + def create_endpoint(self, + body=None): + """Does a POST request to /endpoints.json. - ## Webhooks Intro - The Webhooks API allows you to view a list of all webhooks and to - selectively resend individual or groups of webhooks. Webhooks will be - sent on endpoints specified by you. Endpoints can be added via API or - Web UI. There is also an option to enable / disable webhooks via API - request. - We recommend that you review Advanced Billing's webhook documentation - located in our help site. The following resources will help guide you - on how to use webhooks in Advanced Billing, in addition to these - webhook endpoints: - + [Adding/editing new - webhooks](https://maxio.zendesk.com/hc/en-us/articles/24286723085197-We - bhooks#configure-webhook-url) - + [Webhooks introduction and delivery - information](https://maxio.zendesk.com/hc/en-us/articles/24266143173901 - -Webhooks-Overview) - + [Main webhook - reference](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-W - ebhooks-Reference) - + [Available webhooks and - payloads](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-We - bhooks-Reference#events) - ## List Webhooks for a Site - This method allows you to fetch data about webhooks. You can pass - query parameters if you want to filter webhooks. + The Chargify API allows you to create an endpoint and assign a list of + webhooks subscriptions (events) to it. + You can check available events here. + [Event + keys](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhoo + ks-Reference#events) Args: - options (dict, optional): Key-value pairs for any of the - parameters to this API Endpoint. All parameters to the - endpoint are supplied through the dictionary with their names - being the key and their desired values being the value. A list - of parameters that can be used are:: - - status -- WebhookStatus -- Webhooks with matching status - would be returned. - since_date -- str -- Format YYYY-MM-DD. Returns Webhooks - with the created_at date greater than or equal to the - one specified. - until_date -- str -- Format YYYY-MM-DD. Returns Webhooks - with the created_at date less than or equal to the one - specified. - 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 - 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`. - per_page -- int -- 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`. - order -- WebhookOrder -- The order in which the Webhooks - are returned. - subscription -- int -- The Advanced Billing id of a - subscription you'd like to filter for + body (CreateOrUpdateEndpointRequest, optional): TODO: type + description here. Returns: - List[WebhookResponse]: Response from the API. OK + EndpointResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -107,51 +58,51 @@ def list_webhooks(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/webhooks.json') - .http_method(HttpMethodEnum.GET) - .query_param(Parameter() - .key('status') - .value(options.get('status', None))) - .query_param(Parameter() - .key('since_date') - .value(options.get('since_date', None))) - .query_param(Parameter() - .key('until_date') - .value(options.get('until_date', None))) - .query_param(Parameter() - .key('page') - .value(options.get('page', None))) - .query_param(Parameter() - .key('per_page') - .value(options.get('per_page', None))) - .query_param(Parameter() - .key('order') - .value(options.get('order', None))) - .query_param(Parameter() - .key('subscription') - .value(options.get('subscription', None))) + .path('/endpoints.json') + .http_method(HttpMethodEnum.POST) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(WebhookResponse.from_dictionary) + .deserialize_into(EndpointResponse.from_dictionary) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def enable_webhooks(self, + def update_endpoint(self, + endpoint_id, body=None): - """Does a PUT request to /webhooks/settings.json. + """Does a PUT request to /endpoints/{endpoint_id}.json. - This method allows you to enable webhooks via API for your site + You can update an Endpoint via the API with a PUT request to the + resource endpoint. + You can change the `url` of your endpoint which consumes webhooks or + list of `webhook_subscriptions`. + Check available [Event + keys](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhoo + ks-Reference#events). + Always send a complete list of events which you want subscribe/watch. + Sending an PUT request for existing endpoint with empty list of + `webhook_subscriptions` will end with unsubscribe from all events. + If you want unsubscribe from specific event, just send a list of + `webhook_subscriptions` without the specific event key. Args: - body (EnableWebhooksRequest, optional): TODO: type description - here. + endpoint_id (int): The Advanced Billing id for the endpoint that + should be updated + body (CreateOrUpdateEndpointRequest, optional): TODO: type + description here. Returns: - EnableWebhooksResponse: Response from the API. OK + EndpointResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -163,8 +114,13 @@ def enable_webhooks(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/webhooks/settings.json') + .path('/endpoints/{endpoint_id}.json') .http_method(HttpMethodEnum.PUT) + .template_param(Parameter() + .key('endpoint_id') + .value(endpoint_id) + .is_required(True) + .should_encode(True)) .header_param(Parameter() .key('Content-Type') .value('application/json')) @@ -178,25 +134,23 @@ def enable_webhooks(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(EnableWebhooksResponse.from_dictionary) + .deserialize_into(EndpointResponse.from_dictionary) + .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) + .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) ).execute() - def replay_webhooks(self, + def enable_webhooks(self, body=None): - """Does a POST request to /webhooks/replay.json. + """Does a PUT request to /webhooks/settings.json. - Posting to the replay endpoint does not immediately resend the - webhooks. They are added to a queue and will be sent as soon as - possible, depending on available system resources. - You may submit an array of up to 1000 webhook IDs to replay in the - request. + This method allows you to enable webhooks via API for your site Args: - body (ReplayWebhooksRequest, optional): TODO: type description + body (EnableWebhooksRequest, optional): TODO: type description here. Returns: - ReplayWebhooksResponse: Response from the API. OK + EnableWebhooksResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -208,8 +162,8 @@ def replay_webhooks(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/webhooks/replay.json') - .http_method(HttpMethodEnum.POST) + .path('/webhooks/settings.json') + .http_method(HttpMethodEnum.PUT) .header_param(Parameter() .key('Content-Type') .value('application/json')) @@ -223,26 +177,16 @@ def replay_webhooks(self, ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(ReplayWebhooksResponse.from_dictionary) + .deserialize_into(EnableWebhooksResponse.from_dictionary) ).execute() - def create_endpoint(self, - body=None): - """Does a POST request to /endpoints.json. - - The Chargify API allows you to create an endpoint and assign a list of - webhooks subscriptions (events) to it. - You can check available events here. - [Event - keys](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhoo - ks-Reference#events) + def list_endpoints(self): + """Does a GET request to /endpoints.json. - Args: - body (CreateOrUpdateEndpointRequest, optional): TODO: type - description here. + This method returns created endpoints for site. Returns: - EndpointResponse: Response from the API. OK + List[Endpoint]: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -255,31 +199,33 @@ def create_endpoint(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) .path('/endpoints.json') - .http_method(HttpMethodEnum.POST) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) + .http_method(HttpMethodEnum.GET) .header_param(Parameter() .key('accept') .value('application/json')) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(EndpointResponse.from_dictionary) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + .deserialize_into(Endpoint.from_dictionary) ).execute() - def list_endpoints(self): - """Does a GET request to /endpoints.json. + def replay_webhooks(self, + body=None): + """Does a POST request to /webhooks/replay.json. - This method returns created endpoints for site. + Posting to the replay endpoint does not immediately resend the + webhooks. They are added to a queue and will be sent as soon as + possible, depending on available system resources. + You may submit an array of up to 1000 webhook IDs to replay in the + request. + + Args: + body (ReplayWebhooksRequest, optional): TODO: type description + here. Returns: - List[Endpoint]: Response from the API. OK + ReplayWebhooksResponse: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -291,44 +237,90 @@ def list_endpoints(self): return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/endpoints.json') - .http_method(HttpMethodEnum.GET) + .path('/webhooks/replay.json') + .http_method(HttpMethodEnum.POST) + .header_param(Parameter() + .key('Content-Type') + .value('application/json')) + .body_param(Parameter() + .value(body)) .header_param(Parameter() .key('accept') .value('application/json')) + .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(Endpoint.from_dictionary) + .deserialize_into(ReplayWebhooksResponse.from_dictionary) ).execute() - def update_endpoint(self, - endpoint_id, - body=None): - """Does a PUT request to /endpoints/{endpoint_id}.json. + def list_webhooks(self, + options=dict()): + """Does a GET request to /webhooks.json. - You can update an Endpoint via the API with a PUT request to the - resource endpoint. - You can change the `url` of your endpoint which consumes webhooks or - list of `webhook_subscriptions`. - Check available [Event - keys](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhoo - ks-Reference#events). - Always send a complete list of events which you want subscribe/watch. - Sending an PUT request for existing endpoint with empty list of - `webhook_subscriptions` will end with unsubscribe from all events. - If you want unsubscribe from specific event, just send a list of - `webhook_subscriptions` without the specific event key. + ## Webhooks Intro + The Webhooks API allows you to view a list of all webhooks and to + selectively resend individual or groups of webhooks. Webhooks will be + sent on endpoints specified by you. Endpoints can be added via API or + Web UI. There is also an option to enable / disable webhooks via API + request. + We recommend that you review Advanced Billing's webhook documentation + located in our help site. The following resources will help guide you + on how to use webhooks in Advanced Billing, in addition to these + webhook endpoints: + + [Adding/editing new + webhooks](https://maxio.zendesk.com/hc/en-us/articles/24286723085197-We + bhooks#configure-webhook-url) + + [Webhooks introduction and delivery + information](https://maxio.zendesk.com/hc/en-us/articles/24266143173901 + -Webhooks-Overview) + + [Main webhook + reference](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-W + ebhooks-Reference) + + [Available webhooks and + payloads](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-We + bhooks-Reference#events) + ## List Webhooks for a Site + This method allows you to fetch data about webhooks. You can pass + query parameters if you want to filter webhooks. Args: - endpoint_id (int): The Advanced Billing id for the endpoint that - should be updated - body (CreateOrUpdateEndpointRequest, optional): TODO: type - description here. + options (dict, optional): Key-value pairs for any of the + parameters to this API Endpoint. All parameters to the + endpoint are supplied through the dictionary with their names + being the key and their desired values being the value. A list + of parameters that can be used are:: + + status -- WebhookStatus -- Webhooks with matching status + would be returned. + since_date -- str -- Format YYYY-MM-DD. Returns Webhooks + with the created_at date greater than or equal to the + one specified. + until_date -- str -- Format YYYY-MM-DD. Returns Webhooks + with the created_at date less than or equal to the one + specified. + 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 + 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`. + per_page -- int -- 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`. + order -- WebhookOrder -- The order in which the Webhooks + are returned. + subscription -- int -- The Advanced Billing id of a + subscription you'd like to filter for Returns: - EndpointResponse: Response from the API. OK + List[WebhookResponse]: Response from the API. OK Raises: APIException: When an error occurs while fetching the data from @@ -340,27 +332,35 @@ def update_endpoint(self, return super().new_api_call_builder.request( RequestBuilder().server(Server.DEFAULT) - .path('/endpoints/{endpoint_id}.json') - .http_method(HttpMethodEnum.PUT) - .template_param(Parameter() - .key('endpoint_id') - .value(endpoint_id) - .is_required(True) - .should_encode(True)) - .header_param(Parameter() - .key('Content-Type') - .value('application/json')) - .body_param(Parameter() - .value(body)) + .path('/webhooks.json') + .http_method(HttpMethodEnum.GET) + .query_param(Parameter() + .key('status') + .value(options.get('status', None))) + .query_param(Parameter() + .key('since_date') + .value(options.get('since_date', None))) + .query_param(Parameter() + .key('until_date') + .value(options.get('until_date', None))) + .query_param(Parameter() + .key('page') + .value(options.get('page', None))) + .query_param(Parameter() + .key('per_page') + .value(options.get('per_page', None))) + .query_param(Parameter() + .key('order') + .value(options.get('order', None))) + .query_param(Parameter() + .key('subscription') + .value(options.get('subscription', None))) .header_param(Parameter() .key('accept') .value('application/json')) - .body_serializer(APIHelper.json_serialize) .auth(Single('BasicAuth')) ).response( ResponseHandler() .deserializer(APIHelper.json_deserialize) - .deserialize_into(EndpointResponse.from_dictionary) - .local_error_template('404', 'Not Found:\'{$response.body}\'', APIException) - .local_error_template('422', 'HTTP Response Not OK. Status code: {$statusCode}. Response: \'{$response.body}\'.', ErrorListResponseException) + .deserialize_into(WebhookResponse.from_dictionary) ).execute() diff --git a/advancedbilling/exceptions/__init__.py b/advancedbilling/exceptions/__init__.py index f57f6d63..6a67ea16 100644 --- a/advancedbilling/exceptions/__init__.py +++ b/advancedbilling/exceptions/__init__.py @@ -3,23 +3,23 @@ 'component_allocation_error_exception', 'component_price_point_error_exception', 'customer_error_response_exception', - 'error_array_map_response_exception', 'error_list_response_exception', - 'error_string_map_response_exception', - 'event_based_billing_list_segments_errors_exception', - 'event_based_billing_segment_exception', 'event_based_billing_segment_errors_exception', - 'product_price_point_error_response_exception', + 'event_based_billing_segment_exception', + 'error_array_map_response_exception', + 'event_based_billing_list_segments_errors_exception', + 'error_string_map_response_exception', 'proforma_bad_request_error_response_exception', + 'product_price_point_error_response_exception', 'refund_prepayment_base_errors_response_exception', - 'single_error_response_exception', - 'single_string_error_response_exception', 'subscription_add_coupon_error_exception', 'subscription_component_allocation_error_exception', - 'subscription_group_create_error_response_exception', + 'single_error_response_exception', + 'single_string_error_response_exception', 'subscription_group_signup_error_response_exception', 'subscription_group_update_error_response_exception', 'subscription_remove_coupon_errors_exception', 'subscriptions_mrr_error_response_exception', + 'subscription_group_create_error_response_exception', 'too_many_management_link_requests_error_exception', ] diff --git a/advancedbilling/models/__init__.py b/advancedbilling/models/__init__.py index 82bfa158..dd5564d4 100644 --- a/advancedbilling/models/__init__.py +++ b/advancedbilling/models/__init__.py @@ -1,578 +1,578 @@ __all__ = [ 'payment_method_apple_pay', 'payment_method_bank_account', - 'payment_method_credit_card', 'payment_method_external', + 'change_chargeback_status_event', + 'issue_invoice_event', + 'account_balance', + 'ach_agreement', + 'add_subscription_to_a_group', 'payment_method_paypal', - 'apply_credit_note_event', + 'backport_invoice_event', + 'create_debit_note_event', + 'refund_invoice_event', + 'void_invoice_event', + 'list_invoice_events_response', + 'add_coupons_request', + 'allocation_expiration_date', + 'allocation_preview_line_item', + 'payment_method_credit_card', 'apply_debit_note_event', + 'change_invoice_status_event', + 'remove_payment_event', + 'activate_subscription_request', + 'agreement_acceptance', + 'allocate_components', + 'allocation_preview_item', + 'applied_credit_note_data', + 'apply_credit_note_event', 'apply_payment_event', - 'backport_invoice_event', - 'change_chargeback_status_event', 'change_invoice_collection_method_event', - 'change_invoice_status_event', 'create_credit_note_event', - 'create_debit_note_event', 'failed_payment_event', - 'issue_invoice_event', - 'refund_invoice_event', - 'remove_payment_event', - 'void_invoice_event', 'void_remainder_event', - 'list_invoice_events_response', 'apple_pay_payment_profile', 'bank_account_payment_profile', 'credit_card_payment_profile', 'paypal_payment_profile', - 'account_balance', 'account_balances', - 'ach_agreement', 'activate_event_based_component', - 'activate_subscription_request', - 'add_coupons_request', - 'add_subscription_to_a_group', 'address_change', - 'agreement_acceptance', - 'allocate_components', 'allocation', - 'allocation_expiration_date', 'allocation_preview', - 'allocation_preview_item', - 'allocation_preview_line_item', 'allocation_preview_response', 'allocation_response', 'allocation_settings', - 'applied_credit_note_data', 'apply_credit_note_event_data', - 'apply_debit_note_event_data', 'apply_payment_event_data', - 'attribute_error', + 'base_refund_error', + 'bulk_create_product_price_points_request', + 'cancellation_options', + 'change_invoice_status_event_data', + 'component', + 'component_currency_price', + 'component_price', + 'component_price_point_item', 'auto_resume', - 'bank_account_attributes', 'bank_account_response', - 'bank_account_verification', 'bank_account_verification_request', - 'base_refund_error', - 'base_string_error', 'batch_job_response', + 'bulk_create_product_price_points_response', + 'calendar_billing', + 'component_cost_data', + 'component_price_point_assignment', + 'consolidated_invoice', + 'base_string_error', 'batch_job', 'billing_manifest', 'billing_manifest_item', - 'billing_schedule', - 'breakouts', - 'bulk_components_price_point_assignment', - 'bulk_create_product_price_points_request', - 'bulk_create_product_price_points_response', 'bulk_create_segments', 'bulk_update_segments', - 'bulk_update_segments_item', - 'calendar_billing', 'cancel_grouped_subscriptions_request', - 'cancellation_options', - 'cancellation_request', 'change_chargeback_status_event_data', 'change_invoice_collection_method_event_data', - 'change_invoice_status_event_data', - 'chargify_ebb', - 'component', 'component_allocation_change', - 'component_allocation_error_item', - 'component_cost_data', 'component_cost_data_rate_tier', - 'component_currency_price', 'component_currency_prices_response', - 'component_custom_price', - 'component_price', 'component_price_point', - 'component_price_point_assignment', - 'component_price_point_item', - 'component_price_point_response', 'component_price_points_response', - 'component_price_point_error_item', 'component_response', - 'consolidated_invoice', + 'apply_debit_note_event_data', + 'attribute_error', + 'bank_account_attributes', + 'bank_account_verification', + 'billing_schedule', + 'breakouts', + 'bulk_components_price_point_assignment', + 'bulk_update_segments_item', + 'cancellation_request', + 'chargify_ebb', + 'component_allocation_error_item', + 'component_custom_price', + 'component_price_point_response', + 'component_price_point_error_item', 'count_response', - 'coupon', - 'coupon_currency', - 'coupon_currency_request', 'coupon_currency_response', - 'coupon_response', - 'coupon_restriction', 'coupon_subcodes', + 'create_currency_price', + 'create_metadata_request', + 'create_metafields_request', + 'create_multi_invoice_payment', + 'create_offer_component', + 'create_or_update_coupon', + 'create_or_update_endpoint', + 'create_or_update_product', + 'create_payment_profile', + 'create_prepaid_component', + 'create_product_family_request', + 'coupon_response', 'coupon_subcodes_response', - 'coupon_usage', 'create_allocation', 'create_allocation_request', - 'create_component_price_point', - 'create_component_price_point_request', - 'create_component_price_points_request', - 'create_currency_price', 'create_currency_prices_request', - 'create_customer', 'create_customer_request', - 'create_ebb_component', - 'create_invoice', 'create_invoice_address', 'create_invoice_coupon', - 'create_invoice_item', - 'create_invoice_payment', 'create_invoice_payment_application', 'create_invoice_payment_request', 'create_invoice_request', - 'create_metadata', - 'create_metadata_request', - 'create_metafield', - 'create_metafields_request', - 'create_metered_component', - 'create_multi_invoice_payment', - 'create_multi_invoice_payment_request', 'create_offer', - 'create_offer_component', 'create_offer_request', - 'create_on_off_component', - 'create_or_update_coupon', - 'create_or_update_endpoint', - 'create_or_update_endpoint_request', - 'create_or_update_flat_amount_coupon', 'create_or_update_percentage_coupon', - 'create_or_update_product', + 'create_payment_profile_request', + 'create_prepayment_request', + 'create_product_family', + 'coupon_currency', + 'coupon_restriction', + 'coupon_usage', + 'create_component_price_point', + 'create_component_price_point_request', + 'create_component_price_points_request', + 'create_customer', + 'create_invoice', + 'create_invoice_item', + 'create_metafield', + 'create_multi_invoice_payment_request', 'create_or_update_product_request', - 'create_or_update_segment_price', 'create_payment', - 'create_payment_profile', - 'create_payment_profile_request', - 'create_prepaid_component', - 'create_prepaid_usage_component_price_point', 'create_prepayment', - 'create_prepayment_request', 'create_prepayment_response', 'create_product_currency_price', 'create_product_currency_prices_request', - 'create_product_family', - 'create_product_family_request', - 'create_product_price_point', + 'coupon', + 'coupon_currency_request', + 'create_ebb_component', + 'create_invoice_payment', + 'create_metadata', + 'create_metered_component', + 'create_on_off_component', + 'create_or_update_endpoint_request', + 'create_or_update_flat_amount_coupon', + 'create_or_update_segment_price', + 'create_prepaid_usage_component_price_point', + 'create_subscription_group', + 'created_prepayment', + 'credit_note_application', + 'customer', + 'customer_attributes', + 'customer_payer_change', + 'debit_note', 'create_product_price_point_request', - 'create_quantity_based_component', 'create_reason_code', - 'create_reason_code_request', - 'create_segment', 'create_segment_request', 'create_subscription', - 'create_subscription_component', - 'create_subscription_group', 'create_subscription_group_request', 'create_subscription_request', - 'create_usage', - 'create_usage_request', - 'created_prepayment', - 'credit_account_balance_changed', 'credit_card_attributes', - 'credit_note', - 'credit_note_application', 'credit_note_line_item', 'credit_scheme_request', - 'currency_price', 'currency_prices_response', + 'customer_custom_fields_change', + 'create_product_price_point', + 'create_reason_code_request', + 'create_quantity_based_component', + 'create_usage_request', + 'currency_price', 'custom_field_value_change', - 'customer', - 'customer_attributes', + 'customer_response', + 'create_segment', + 'create_subscription_component', + 'create_usage', + 'credit_account_balance_changed', + 'credit_note', 'customer_change', 'customer_changes_preview_response', - 'customer_custom_fields_change', 'customer_error', - 'customer_payer_change', - 'customer_response', - 'debit_note', - 'deduct_service_credit', - 'deduct_service_credit_request', - 'delayed_cancellation_response', - 'delete_subscription_group_response', 'dunner_data', - 'dunning_step_data', 'dunning_step_reached', 'ebb_component', 'ebb_event', - 'enable_webhooks_request', 'enable_webhooks_response', - 'endpoint', - 'endpoint_response', - 'errors', - 'event', - 'event_based_billing_segment_error', 'event_response', 'failed_payment_event_data', 'full_subscription_group_response', - 'get_one_time_token_payment_profile', - 'get_one_time_token_request', - 'group_billing', - 'group_settings', 'group_target', - 'historic_usage', - 'invoice', - 'invoice_address', - 'invoice_balance_item', - 'invoice_credit', 'invoice_custom_field', 'invoice_customer', 'invoice_discount', 'invoice_discount_breakout', + 'deduct_service_credit', + 'enable_webhooks_request', + 'get_one_time_token_request', 'invoice_display_settings', - 'invoice_issued', - 'invoice_line_item', - 'invoice_line_item_component_cost_data', + 'delayed_cancellation_response', + 'deduct_service_credit_request', + 'dunning_step_data', + 'endpoint_response', + 'event', + 'event_based_billing_segment_error', + 'group_billing', + 'invoice_address', + 'invoice_balance_item', + 'invoice_credit', + 'delete_subscription_group_response', + 'endpoint', + 'errors', + 'get_one_time_token_payment_profile', + 'group_settings', + 'historic_usage', + 'invoice', 'invoice_line_item_event_data', + 'invoice_issued', + 'invoice_tax_breakout', + 'issue_invoice_event_data', + 'issue_service_credit_request', + 'list_invoices_response', + 'list_mrr_filter', + 'list_public_keys_meta', + 'list_segments_response', + 'list_subcription_group_prepayment_item', + 'list_subscription_components_filter', 'invoice_line_item_pricing_detail', - 'invoice_payer', - 'invoice_payer_change', - 'invoice_payment', 'invoice_payment_application', - 'invoice_payment_method', - 'invoice_pre_payment', - 'invoice_previous_balance', 'invoice_refund', - 'invoice_response', - 'invoice_seller', - 'invoice_tax', - 'invoice_tax_breakout', 'invoice_tax_component_breakout', 'issue_advance_invoice_request', - 'issue_invoice_event_data', - 'issue_invoice_request', 'issue_service_credit', - 'issue_service_credit_request', 'item_price_point_changed', - 'item_price_point_data', - 'list_components_filter', - 'list_components_price_points_response', 'list_coupons_filter', 'list_credit_notes_response', - 'list_invoices_response', - 'list_metafields_response', - 'list_mrr_filter', - 'list_mrr_response', - 'list_mrr_response_result', 'list_offers_response', 'list_prepayments_filter', 'list_price_points_filter', - 'list_product_price_points_response', - 'list_products_filter', 'list_proforma_invoices_meta', 'list_proforma_invoices_response', - 'list_public_keys_meta', - 'list_public_keys_response', 'list_sale_rep_item', - 'list_segments_filter', - 'list_segments_response', - 'list_subcription_group_prepayment_item', - 'list_subscription_components_filter', 'list_subscription_components_for_site_filter', - 'list_subscription_components_response', - 'list_subscription_group_prepayment', + 'invoice_line_item_component_cost_data', + 'invoice_payer_change', + 'invoice_payment', + 'invoice_payment_method', + 'invoice_response', + 'invoice_tax', + 'issue_invoice_request', + 'item_price_point_data', + 'list_components_filter', + 'list_components_price_points_response', + 'list_metafields_response', + 'list_mrr_response', + 'list_mrr_response_result', + 'list_products_filter', + 'list_public_keys_response', + 'list_segments_filter', + 'invoice_line_item', + 'invoice_payer', + 'invoice_pre_payment', + 'invoice_previous_balance', + 'invoice_seller', + 'list_product_price_points_response', 'list_subscription_group_prepayment_response', - 'list_subscription_groups_item', - 'list_subscription_groups_meta', 'list_subscription_groups_response', - 'metadata', - 'metafield', 'metafield_scope', - 'metered_component', 'metered_usage', - 'movement', - 'movement_line_item', - 'mrr', - 'mrr_movement', - 'mrr_response', - 'multi_invoice_payment', - 'multi_invoice_payment_response', - 'nested_subscription_group', - 'net_terms', - 'offer', 'offer_discount', - 'offer_item', - 'offer_response', - 'offer_signup_page', 'on_off_component', - 'organization_address', - 'origin_invoice', 'overage_pricing', - 'override_subscription', 'override_subscription_request', - 'paginated_metadata', 'paid_invoice', - 'pause_request', - 'payer_attributes', 'payer_error', 'payment_collection_method_changed', - 'payment_for_allocation', 'payment_profile_attributes', - 'payment_profile_response', 'payment_related_events', - 'pending_cancellation_change', 'portal_management_link', - 'prepaid_component_price_point', - 'prepaid_configuration', 'prepaid_configuration_response', - 'prepaid_product_price_point_filter', 'prepaid_subscription_balance_changed', 'prepaid_usage', + 'movement', + 'nested_subscription_group', + 'paginated_metadata', + 'pause_request', + 'payer_attributes', + 'pending_cancellation_change', + 'prepaid_product_price_point_filter', 'prepaid_usage_allocation_detail', + 'list_subscription_components_response', + 'list_subscription_group_prepayment', + 'metadata', + 'metered_component', + 'movement_line_item', + 'mrr', + 'multi_invoice_payment', + 'offer', + 'offer_item', + 'offer_response', + 'payment_profile_response', + 'prepaid_component_price_point', + 'prepaid_configuration', 'prepaid_usage_component', + 'list_subscription_groups_item', + 'list_subscription_groups_meta', + 'metafield', + 'mrr_movement', + 'mrr_response', + 'multi_invoice_payment_response', + 'net_terms', + 'offer_signup_page', + 'organization_address', + 'origin_invoice', + 'override_subscription', + 'payment_for_allocation', 'prepayment', + 'product_price_point_errors', + 'proforma_error', + 'proforma_invoice', + 'reason_codes_json_response', + 'record_payment_request', + 'referral_code', + 'refund_invoice', + 'prepayment_response', + 'prepayments_response', + 'product_response', + 'proforma_invoice_credit', + 'proforma_invoice_payment', + 'proforma_invoice_tax', + 'public_key', + 'public_signup_page', + 'reason_code', + 'reason_code_response', + 'record_payment_response', + 'refund_success', 'prepayment_account_balance_changed', - 'prepayment_response', - 'prepayments_response', 'preview_allocations_request', - 'price', 'product', 'product_family', - 'product_family_response', 'product_price_point', - 'product_price_point_errors', 'product_price_point_response', - 'product_response', - 'proforma_error', - 'proforma_invoice', - 'proforma_invoice_credit', - 'proforma_invoice_discount', 'proforma_invoice_issued', - 'proforma_invoice_payment', - 'proforma_invoice_tax', - 'proration', - 'public_key', - 'public_signup_page', 'quantity_based_component', 'reactivate_subscription_group_request', - 'reactivate_subscription_group_response', - 'reactivate_subscription_request', 'reactivation_billing', - 'reason_code', - 'reason_code_response', - 'reason_codes_json_response', - 'record_payment_request', - 'record_payment_response', - 'referral_code', - 'referral_validation_response', 'refund_consolidated_invoice', - 'refund_invoice', - 'refund_invoice_event_data', 'refund_invoice_request', - 'refund_prepayment', 'refund_prepayment_base_refund_error', 'refund_prepayment_request', - 'refund_success', + 'price', + 'product_family_response', + 'proforma_invoice_discount', + 'proration', + 'reactivate_subscription_group_response', + 'reactivate_subscription_request', + 'referral_validation_response', + 'refund_invoice_event_data', + 'refund_prepayment', 'remove_payment_event_data', - 'renewal_preview', - 'renewal_preview_component', - 'renewal_preview_line_item', - 'renewal_preview_request', - 'renewal_preview_response', 'replay_webhooks_request', - 'replay_webhooks_response', 'resent_invitation', 'resume_options', - 'revoked_invitation', 'sale_rep', 'sale_rep_item_mrr', 'sale_rep_settings', - 'sale_rep_subscription', + 'service_credit', + 'signup_proforma_preview_response', + 'site_summary', + 'subscription', + 'subscription_component_response', + 'subscription_component_subscription', + 'subscription_custom_price', + 'replay_webhooks_response', 'segment', 'segment_price', - 'segment_response', 'send_invoice_request', - 'service_credit', - 'service_credit_response', 'signup_proforma_preview', - 'signup_proforma_preview_response', 'site', + 'subscription_component_allocation_error_item', + 'renewal_preview', + 'renewal_preview_component', + 'renewal_preview_request', + 'sale_rep_subscription', 'site_response', 'site_statistics', - 'site_summary', - 'subscription', 'subscription_component', - 'subscription_component_allocation_error_item', - 'subscription_component_response', - 'subscription_component_subscription', - 'subscription_custom_price', - 'subscription_filter', 'subscription_group', - 'subscription_group_balances', 'subscription_group_bank_account', - 'subscription_group_component_custom_price', + 'renewal_preview_line_item', + 'renewal_preview_response', + 'revoked_invitation', + 'segment_response', + 'service_credit_response', + 'subscription_filter', + 'subscription_group_balances', + 'subscription_group_member_error', + 'subscription_group_response', + 'subscription_group_signup_request', + 'subscription_group_signup_success_data', + 'subscription_group_update_error', + 'subscription_migration_preview_response', + 'subscription_mrr_response', + 'subscription_note_response', 'subscription_group_credit_card', 'subscription_group_customer', + 'subscription_group_prepayment', + 'subscription_group_signup_failure', + 'subscription_group_signup_response', + 'subscription_group_single_error', + 'subscription_group_subscription_error', + 'subscription_included_coupon', + 'subscription_migration_preview_options', + 'subscription_mrr_breakout', + 'subscription_product_migration', + 'subscription_response', + 'subscription_state_change', 'subscription_group_item', - 'subscription_group_member_error', 'subscription_group_members_array_error', 'subscription_group_payment_profile', - 'subscription_group_prepayment', 'subscription_group_prepayment_request', 'subscription_group_prepayment_response', - 'subscription_group_response', - 'subscription_group_signup', - 'subscription_group_signup_component', 'subscription_group_signup_error', - 'subscription_group_signup_failure', 'subscription_group_signup_failure_data', 'subscription_group_signup_item', - 'subscription_group_signup_request', - 'subscription_group_signup_response', - 'subscription_group_signup_success', - 'subscription_group_signup_success_data', - 'subscription_group_single_error', - 'subscription_group_subscription_error', - 'subscription_group_update_error', - 'subscription_included_coupon', 'subscription_migration_preview', - 'subscription_migration_preview_options', - 'subscription_migration_preview_request', - 'subscription_migration_preview_response', 'subscription_mrr', - 'subscription_mrr_breakout', - 'subscription_mrr_response', - 'subscription_note', - 'subscription_note_response', 'subscription_preview', - 'subscription_preview_response', 'subscription_product_change', - 'subscription_product_migration', + 'subscription_group_component_custom_price', + 'subscription_group_signup', + 'subscription_group_signup_component', + 'subscription_group_signup_success', + 'subscription_migration_preview_request', + 'subscription_note', + 'subscription_preview_response', 'subscription_product_migration_request', - 'subscription_response', - 'subscription_state_change', 'tax_configuration', - 'too_many_management_link_requests', + 'update_currency_price', + 'update_currency_prices_request', + 'update_metadata', + 'update_product_price_point', + 'update_product_price_point_request', + 'update_segment', + 'update_subscription_group', + 'upsert_prepaid_configuration_request', + 'webhook', 'update_allocation_expiration_date', 'update_component', 'update_component_price_point', + 'update_metadata_request', + 'update_subscription', + 'update_subscription_note', + 'update_subscription_note_request', + 'update_subscription_request', + 'void_invoice', + 'void_invoice_event_data', + 'too_many_management_link_requests', 'update_component_price_point_request', - 'update_component_request', 'update_coupon_currency', - 'update_currency_price', - 'update_currency_prices_request', 'update_customer', 'update_customer_request', - 'update_metadata', - 'update_metadata_request', - 'update_metafield', - 'update_metafields_request', 'update_payment_profile', 'update_payment_profile_request', 'update_price', - 'update_product_price_point', - 'update_product_price_point_request', - 'update_reason_code', 'update_reason_code_request', - 'update_segment', + 'upsert_prepaid_configuration', + 'usage', + 'void_invoice_request', + 'update_component_request', + 'update_metafield', + 'update_metafields_request', + 'update_reason_code', 'update_segment_request', - 'update_subscription', 'update_subscription_component', - 'update_subscription_group', 'update_subscription_group_request', - 'update_subscription_note', - 'update_subscription_note_request', - 'update_subscription_request', - 'upsert_prepaid_configuration', - 'upsert_prepaid_configuration_request', - 'usage', 'usage_response', - 'void_invoice', - 'void_invoice_event_data', - 'void_invoice_request', 'void_remainder_event_data', - 'webhook', 'webhook_response', - 'all_vaults', 'allocation_preview_direction', - 'allocation_preview_line_item_kind', + 'all_vaults', 'apple_pay_vault', + 'allocation_preview_line_item_kind', 'auto_invite', - 'bank_account_holder_type', 'bank_account_type', - 'bank_account_vault', 'basic_date_field', - 'billing_manifest_line_item_kind', + 'cleanup_scope', + 'bank_account_holder_type', 'cancellation_method', + 'component_kind', + 'compounding_strategy', 'card_type', 'chargeback_status', - 'cleanup_scope', + 'bank_account_vault', + 'billing_manifest_line_item_kind', 'collection_method', - 'component_kind', - 'compounding_strategy', 'create_invoice_status', 'create_prepayment_method', - 'create_signup_proforma_preview_include', 'credit_card_vault', 'credit_note_status', + 'debit_note_role', 'credit_scheme', + 'create_signup_proforma_preview_include', 'credit_type', 'currency_price_role', 'custom_field_owner', - 'debit_note_role', 'debit_note_status', - 'direction', - 'discount_type', 'event_type', - 'expiration_interval_unit', - 'failed_payment_action', 'first_charge_type', - 'group_target_type', 'group_type', + 'invoice_consolidation_level', + 'invoice_discount_source_type', + 'expiration_interval_unit', + 'failed_payment_action', + 'interval_unit', + 'invoice_date_field', + 'discount_type', 'include_not_null', 'include_null_or_not_null', 'include_option', - 'interval_unit', - 'invoice_consolidation_level', - 'invoice_date_field', - 'invoice_discount_source_type', + 'direction', + 'group_target_type', 'invoice_discount_type', 'invoice_event_payment_method', - 'invoice_event_type', - 'invoice_payment_method_type', 'invoice_payment_type', - 'invoice_role', - 'invoice_sort_field', 'invoice_status', - 'item_category', 'line_item_kind', 'line_item_transaction_type', 'list_components_price_points_include', 'list_events_date_field', + 'invoice_event_type', + 'invoice_payment_method_type', + 'invoice_sort_field', + 'item_category', + 'invoice_role', 'list_prepayment_date_field', 'list_products_include', 'list_products_price_points_include', 'list_subscription_components_include', + 'payment_type', 'list_subscription_components_sort', 'metafield_input', - 'payment_type', 'pay_pal_vault', - 'prepayment_method', 'price_point_type', - 'pricing_scheme', - 'proforma_invoice_discount_source_type', - 'proforma_invoice_role', - 'proforma_invoice_status', 'proforma_invoice_tax_source_type', 'reactivation_charge', 'recurring_scheme', + 'proforma_invoice_discount_source_type', + 'proforma_invoice_status', + 'prepayment_method', + 'pricing_scheme', + 'proforma_invoice_role', 'resource_type', 'restriction_type', + 'subscription_date_field', 'resumption_charge', 'service_credit_type', 'snap_day', 'sorting_direction', - 'subscription_date_field', + 'subscription_state_filter', 'subscription_group_include', - 'subscription_group_prepayment_method', 'subscription_groups_list_include', - 'subscription_include', 'subscription_list_date_field', - 'subscription_list_include', 'subscription_purge_type', - 'subscription_sort', 'subscription_state', - 'subscription_state_filter', + 'subscription_group_prepayment_method', + 'subscription_include', + 'subscription_list_include', 'tax_configuration_kind', 'tax_destination_address', + 'subscription_sort', 'webhook_order', - 'webhook_status', 'webhook_subscription', + 'webhook_status', ] diff --git a/advancedbilling/utilities/union_type_lookup.py b/advancedbilling/utilities/union_type_lookup.py index 3b2e89d1..cdad4b7e 100644 --- a/advancedbilling/utilities/union_type_lookup.py +++ b/advancedbilling/utilities/union_type_lookup.py @@ -114,37 +114,37 @@ class UnionTypeLookUp: LeafType(str) ] ), - 'CreateProductPricePointProductId': OneOf( + 'ListProductPricePointsInputProductId': OneOf( [ LeafType(int), LeafType(str) ] ), - 'ListProductPricePointsInputProductId': OneOf( + 'ReadProductPricePointProductId': OneOf( [ LeafType(int), LeafType(str) ] ), - 'UpdateProductPricePointProductId': OneOf( + 'ReadProductPricePointPricePointId': OneOf( [ LeafType(int), LeafType(str) ] ), - 'UpdateProductPricePointPricePointId': OneOf( + 'CreateProductPricePointProductId': OneOf( [ LeafType(int), LeafType(str) ] ), - 'ReadProductPricePointProductId': OneOf( + 'UpdateProductPricePointProductId': OneOf( [ LeafType(int), LeafType(str) ] ), - 'ReadProductPricePointPricePointId': OneOf( + 'UpdateProductPricePointPricePointId': OneOf( [ LeafType(int), LeafType(str) @@ -162,18 +162,27 @@ class UnionTypeLookUp: LeafType(str) ] ), - 'CreateUsageComponentId': OneOf( + 'ListUsagesInputComponentId': OneOf( [ LeafType(int), LeafType(str) ] ), - 'ListUsagesInputComponentId': OneOf( + 'CreateUsageComponentId': OneOf( [ LeafType(int), LeafType(str) ] ), + 'AddSubscriptionToAGroupGroup': OneOf( + [ + LeafType(GroupSettings), + LeafType(bool) + ], + Context.create( + is_optional=True + ) + ), 'Invoice-Event': AnyOf( [ LeafType(ApplyCreditNoteEvent, @@ -257,16 +266,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'AddSubscriptionToAGroupGroup': OneOf( - [ - LeafType(GroupSettings), - LeafType(bool) - ], - Context.create( - is_optional=True - ) - ), - 'AllocationQuantity': OneOf( + 'AllocationPreviewItemQuantity': OneOf( [ LeafType(int), LeafType(str) @@ -275,7 +275,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'AllocationPreviousQuantity': OneOf( + 'AllocationPreviewItemPreviousQuantity': OneOf( [ LeafType(int), LeafType(str) @@ -284,7 +284,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'AllocationPreviewItemQuantity': OneOf( + 'AllocationQuantity': OneOf( [ LeafType(int), LeafType(str) @@ -293,7 +293,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'AllocationPreviewItemPreviousQuantity': OneOf( + 'AllocationPreviousQuantity': OneOf( [ LeafType(int), LeafType(str) @@ -340,6 +340,15 @@ class UnionTypeLookUp: is_optional=True ) ), + 'ComponentPricePointAssignmentPricePoint': OneOf( + [ + LeafType(str), + LeafType(int) + ], + Context.create( + is_optional=True + ) + ), 'ComponentAllocationChangeAllocatedQuantity': OneOf( [ LeafType(int), @@ -349,38 +358,56 @@ class UnionTypeLookUp: is_optional=True ) ), - 'ComponentPricePointAssignmentPricePoint': OneOf( + 'CreateMetafieldsRequestMetafields': OneOf( + [ + LeafType(CreateMetafield), + LeafType(CreateMetafield, + Context.create( + is_array=True + )) + ] + ), + 'CreateMultiInvoicePaymentAmount': OneOf( [ LeafType(str), - LeafType(int) + LeafType(float) + ] + ), + 'CreateOrUpdateCouponCoupon': OneOf( + [ + LeafType(CreateOrUpdatePercentageCoupon), + LeafType(CreateOrUpdateFlatAmountCoupon) ], Context.create( is_optional=True ) ), - 'CreateAllocationPricePointId': OneOf( + 'CreatePaymentProfileExpirationMonth': OneOf( [ - LeafType(str), - LeafType(int) + LeafType(int), + LeafType(str) ], Context.create( - is_optional=True, - is_nullable=True + is_optional=True ) ), - 'CreateComponentPricePointRequestPricePoint': AnyOf( + 'CreatePaymentProfileExpirationYear': OneOf( [ - LeafType(CreateComponentPricePoint), - LeafType(CreatePrepaidUsageComponentPricePoint) - ] + LeafType(int), + LeafType(str) + ], + Context.create( + is_optional=True + ) ), - 'CreateComponentPricePointsRequestPricePoints': AnyOf( + 'CreateAllocationPricePointId': OneOf( [ - LeafType(CreateComponentPricePoint), - LeafType(CreatePrepaidUsageComponentPricePoint) + LeafType(str), + LeafType(int) ], Context.create( - is_array=True + is_optional=True, + is_nullable=True ) ), 'CreateInvoiceCouponPercentage': OneOf( @@ -410,6 +437,27 @@ class UnionTypeLookUp: is_optional=True ) ), + 'CreateOrUpdatePercentageCouponPercentage': OneOf( + [ + LeafType(str), + LeafType(float) + ] + ), + 'CreateComponentPricePointRequestPricePoint': AnyOf( + [ + LeafType(CreateComponentPricePoint), + LeafType(CreatePrepaidUsageComponentPricePoint) + ] + ), + 'CreateComponentPricePointsRequestPricePoints': AnyOf( + [ + LeafType(CreateComponentPricePoint), + LeafType(CreatePrepaidUsageComponentPricePoint) + ], + Context.create( + is_array=True + ) + ), 'CreateInvoiceItemQuantity': OneOf( [ LeafType(float), @@ -473,55 +521,28 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateMetafieldsRequestMetafields': OneOf( - [ - LeafType(CreateMetafield), - LeafType(CreateMetafield, - Context.create( - is_array=True - )) - ] - ), - 'CreateMultiInvoicePaymentAmount': OneOf( - [ - LeafType(str), - LeafType(float) - ] - ), - 'CreateOrUpdateCouponCoupon': OneOf( - [ - LeafType(CreateOrUpdatePercentageCoupon), - LeafType(CreateOrUpdateFlatAmountCoupon) - ], - Context.create( - is_optional=True - ) - ), - 'CreateOrUpdatePercentageCouponPercentage': OneOf( - [ - LeafType(str), - LeafType(float) - ] - ), 'CreateOrUpdateSegmentPriceUnitPrice': OneOf( [ LeafType(str), LeafType(float) ] ), - 'CreatePaymentProfileExpirationMonth': OneOf( + 'CustomerErrorResponseErrors': OneOf( [ - LeafType(int), - LeafType(str) + LeafType(CustomerError), + LeafType(str, + Context.create( + is_array=True + )) ], Context.create( is_optional=True ) ), - 'CreatePaymentProfileExpirationYear': OneOf( + 'CreateSubscriptionOfferId': OneOf( [ - LeafType(int), - LeafType(str) + LeafType(str), + LeafType(int) ], Context.create( is_optional=True @@ -571,15 +592,6 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CreateSubscriptionOfferId': OneOf( - [ - LeafType(str), - LeafType(int) - ], - Context.create( - is_optional=True - ) - ), 'CreateSubscriptionComponentComponentId': OneOf( [ LeafType(int), @@ -607,13 +619,10 @@ class UnionTypeLookUp: is_optional=True ) ), - 'CustomerErrorResponseErrors': OneOf( + 'EBBComponentUnitPrice': OneOf( [ - LeafType(CustomerError), - LeafType(str, - Context.create( - is_array=True - )) + LeafType(str), + LeafType(float) ], Context.create( is_optional=True @@ -625,15 +634,6 @@ class UnionTypeLookUp: LeafType(float) ] ), - 'EBBComponentUnitPrice': OneOf( - [ - LeafType(str), - LeafType(float) - ], - Context.create( - is_optional=True - ) - ), 'EventEventSpecificData': OneOf( [ LeafType(SubscriptionProductChange), @@ -666,20 +666,7 @@ class UnionTypeLookUp: LeafType(str) ] ), - 'MetafieldEnum': OneOf( - [ - LeafType(str), - LeafType(str, - Context.create( - is_array=True - )) - ], - Context.create( - is_optional=True, - is_nullable=True - ) - ), - 'MeteredComponentUnitPrice': OneOf( + 'OnOffComponentUnitPrice': OneOf( [ LeafType(str), LeafType(float) @@ -688,16 +675,16 @@ class UnionTypeLookUp: is_optional=True ) ), - 'OnOffComponentUnitPrice': OneOf( + 'PaymentProfileAttributesExpirationMonth': OneOf( [ - LeafType(str), - LeafType(float) + LeafType(int), + LeafType(str) ], Context.create( is_optional=True ) ), - 'PaymentProfileAttributesExpirationMonth': OneOf( + 'PaymentProfileAttributesExpirationYear': OneOf( [ LeafType(int), LeafType(str) @@ -706,10 +693,10 @@ class UnionTypeLookUp: is_optional=True ) ), - 'PaymentProfileAttributesExpirationYear': OneOf( + 'MeteredComponentUnitPrice': OneOf( [ - LeafType(int), - LeafType(str) + LeafType(str), + LeafType(float) ], Context.create( is_optional=True @@ -748,6 +735,43 @@ class UnionTypeLookUp: is_optional=True ) ), + 'MetafieldEnum': OneOf( + [ + LeafType(str), + LeafType(str, + Context.create( + is_array=True + )) + ], + Context.create( + is_optional=True, + is_nullable=True + ) + ), + 'QuantityBasedComponentUnitPrice': OneOf( + [ + LeafType(str), + LeafType(float) + ], + Context.create( + is_optional=True + ) + ), + 'RefundConsolidatedInvoiceSegmentUids': OneOf( + [ + LeafType(str, + Context.create( + is_array=True + )), + LeafType(str) + ] + ), + 'RefundInvoiceRequestRefund': AnyOf( + [ + LeafType(RefundInvoice), + LeafType(RefundConsolidatedInvoice) + ] + ), 'PriceStartingQuantity': OneOf( [ LeafType(int), @@ -770,15 +794,6 @@ class UnionTypeLookUp: LeafType(str) ] ), - 'QuantityBasedComponentUnitPrice': OneOf( - [ - LeafType(str), - LeafType(float) - ], - Context.create( - is_optional=True - ) - ), 'ReactivateSubscriptionRequestResume': OneOf( [ LeafType(bool), @@ -788,28 +803,25 @@ class UnionTypeLookUp: is_optional=True ) ), - 'RefundConsolidatedInvoiceSegmentUids': OneOf( + 'RefundPrepaymentAmount': OneOf( [ - LeafType(str, - Context.create( - is_array=True - )), - LeafType(str) + LeafType(str), + LeafType(float) ] ), - 'RefundInvoiceRequestRefund': AnyOf( + 'SubscriptionCustomPricePriceInCents': OneOf( [ - LeafType(RefundInvoice), - LeafType(RefundConsolidatedInvoice) + LeafType(str), + LeafType(int) ] ), - 'RefundPrepaymentAmount': OneOf( + 'SubscriptionCustomPriceInterval': OneOf( [ LeafType(str), - LeafType(float) + LeafType(int) ] ), - 'RenewalPreviewComponentComponentId': OneOf( + 'SubscriptionCustomPriceTrialPriceInCents': OneOf( [ LeafType(str), LeafType(int) @@ -818,7 +830,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'RenewalPreviewComponentPricePointId': OneOf( + 'SubscriptionCustomPriceTrialInterval': OneOf( [ LeafType(str), LeafType(int) @@ -827,29 +839,25 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SegmentSegmentProperty1Value': OneOf( + 'SubscriptionCustomPriceInitialChargeInCents': OneOf( [ LeafType(str), - LeafType(float), - LeafType(int), - LeafType(bool) + LeafType(int) ], Context.create( is_optional=True ) ), - 'SegmentSegmentProperty2Value': OneOf( + 'SubscriptionCustomPriceExpirationInterval': OneOf( [ LeafType(str), - LeafType(float), - LeafType(int), - LeafType(bool) + LeafType(int) ], Context.create( is_optional=True ) ), - 'SegmentSegmentProperty3Value': OneOf( + 'SegmentSegmentProperty1Value': OneOf( [ LeafType(str), LeafType(float), @@ -860,7 +868,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SegmentSegmentProperty4Value': OneOf( + 'SegmentSegmentProperty2Value': OneOf( [ LeafType(str), LeafType(float), @@ -871,37 +879,29 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionComponentAllocatedQuantity': OneOf( + 'SegmentSegmentProperty3Value': OneOf( [ + LeafType(str), + LeafType(float), LeafType(int), - LeafType(str) + LeafType(bool) ], Context.create( is_optional=True ) ), - 'SubscriptionCustomPricePriceInCents': OneOf( - [ - LeafType(str), - LeafType(int) - ] - ), - 'SubscriptionCustomPriceInterval': OneOf( - [ - LeafType(str), - LeafType(int) - ] - ), - 'SubscriptionCustomPriceTrialPriceInCents': OneOf( + 'SegmentSegmentProperty4Value': OneOf( [ LeafType(str), - LeafType(int) + LeafType(float), + LeafType(int), + LeafType(bool) ], Context.create( is_optional=True ) ), - 'SubscriptionCustomPriceTrialInterval': OneOf( + 'RenewalPreviewComponentComponentId': OneOf( [ LeafType(str), LeafType(int) @@ -910,7 +910,7 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionCustomPriceInitialChargeInCents': OneOf( + 'RenewalPreviewComponentPricePointId': OneOf( [ LeafType(str), LeafType(int) @@ -919,22 +919,15 @@ class UnionTypeLookUp: is_optional=True ) ), - 'SubscriptionCustomPriceExpirationInterval': OneOf( + 'SubscriptionComponentAllocatedQuantity': OneOf( [ - LeafType(str), - LeafType(int) + LeafType(int), + LeafType(str) ], Context.create( is_optional=True ) ), - 'SubscriptionGroupCreateErrorResponseErrors': OneOf( - [ - LeafType(SubscriptionGroupMembersArrayError), - LeafType(SubscriptionGroupSingleError), - LeafType(str) - ] - ), 'SubscriptionGroupCreditCardFullNumber': OneOf( [ LeafType(str), @@ -962,6 +955,13 @@ class UnionTypeLookUp: is_optional=True ) ), + 'SubscriptionGroupCreateErrorResponseErrors': OneOf( + [ + LeafType(SubscriptionGroupMembersArrayError), + LeafType(SubscriptionGroupSingleError), + LeafType(str) + ] + ), 'SubscriptionGroupSignupComponentComponentId': OneOf( [ LeafType(str), @@ -998,13 +998,19 @@ class UnionTypeLookUp: is_optional=True ) ), - 'UpdateMetafieldsRequestMetafields': OneOf( + 'UpdateSubscriptionSnapDay': OneOf( [ - LeafType(UpdateMetafield), - LeafType(UpdateMetafield, - Context.create( - is_array=True - )) + LeafType(SnapDay), + LeafType(int) + ], + Context.create( + is_optional=True + ) + ), + 'UpdateSubscriptionNetTerms': OneOf( + [ + LeafType(str), + LeafType(int) ], Context.create( is_optional=True @@ -1037,28 +1043,22 @@ class UnionTypeLookUp: is_optional=True ) ), - 'UpdateSubscriptionSnapDay': OneOf( - [ - LeafType(SnapDay), - LeafType(int) - ], - Context.create( - is_optional=True - ) - ), - 'UpdateSubscriptionNetTerms': OneOf( + 'UsageQuantity': OneOf( [ - LeafType(str), - LeafType(int) + LeafType(int), + LeafType(str) ], Context.create( is_optional=True ) ), - 'UsageQuantity': OneOf( + 'UpdateMetafieldsRequestMetafields': OneOf( [ - LeafType(int), - LeafType(str) + LeafType(UpdateMetafield), + LeafType(UpdateMetafield, + Context.create( + is_array=True + )) ], Context.create( is_optional=True diff --git a/doc/controllers/advance-invoice.md b/doc/controllers/advance-invoice.md index 3fe1b0dd..833b99f4 100644 --- a/doc/controllers/advance-invoice.md +++ b/doc/controllers/advance-invoice.md @@ -10,22 +10,20 @@ advance_invoice_controller = client.advance_invoice ## Methods +* [Void Advance Invoice](../../doc/controllers/advance-invoice.md#void-advance-invoice) * [Issue Advance Invoice](../../doc/controllers/advance-invoice.md#issue-advance-invoice) * [Read Advance Invoice](../../doc/controllers/advance-invoice.md#read-advance-invoice) -* [Void Advance Invoice](../../doc/controllers/advance-invoice.md#void-advance-invoice) -# Issue Advance Invoice +# Void 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. -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. +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). ```python -def issue_advance_invoice(self, - subscription_id, - body=None) +def void_advance_invoice(self, + subscription_id, + body=None) ``` ## Parameters @@ -33,7 +31,7 @@ def issue_advance_invoice(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `body` | [`IssueAdvanceInvoiceRequest`](../../doc/models/issue-advance-invoice-request.md) | Body, Optional | - | +| `body` | [`VoidInvoiceRequest`](../../doc/models/void-invoice-request.md) | Body, Optional | - | ## Response Type @@ -44,14 +42,7 @@ def issue_advance_invoice(self, ```python subscription_id = 222 -body = IssueAdvanceInvoiceRequest( - force=True -) - -result = advance_invoice_controller.issue_advance_invoice( - subscription_id, - body=body -) +result = advance_invoice_controller.void_advance_invoice(subscription_id) ``` ## Errors @@ -59,16 +50,19 @@ result = advance_invoice_controller.issue_advance_invoice( | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | | 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Read Advance Invoice +# Issue Advance Invoice -Once an advance invoice has been generated for a subscription's upcoming renewal, it can be viewed through this endpoint. There can only be one advance invoice per subscription per billing cycle. +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. +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. ```python -def read_advance_invoice(self, - subscription_id) +def issue_advance_invoice(self, + subscription_id, + body=None) ``` ## Parameters @@ -76,6 +70,7 @@ def read_advance_invoice(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `body` | [`IssueAdvanceInvoiceRequest`](../../doc/models/issue-advance-invoice-request.md) | Body, Optional | - | ## Response Type @@ -86,7 +81,14 @@ def read_advance_invoice(self, ```python subscription_id = 222 -result = advance_invoice_controller.read_advance_invoice(subscription_id) +body = IssueAdvanceInvoiceRequest( + force=True +) + +result = advance_invoice_controller.issue_advance_invoice( + subscription_id, + body=body +) ``` ## Errors @@ -94,17 +96,16 @@ result = advance_invoice_controller.read_advance_invoice(subscription_id) | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | | 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Void Advance Invoice +# Read 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). +Once an advance invoice has been generated for a subscription's upcoming renewal, it can be viewed through this endpoint. There can only be one advance invoice per subscription per billing cycle. ```python -def void_advance_invoice(self, - subscription_id, - body=None) +def read_advance_invoice(self, + subscription_id) ``` ## Parameters @@ -112,7 +113,6 @@ def void_advance_invoice(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `body` | [`VoidInvoiceRequest`](../../doc/models/void-invoice-request.md) | Body, Optional | - | ## Response Type @@ -123,7 +123,7 @@ def void_advance_invoice(self, ```python subscription_id = 222 -result = advance_invoice_controller.void_advance_invoice(subscription_id) +result = advance_invoice_controller.read_advance_invoice(subscription_id) ``` ## Errors diff --git a/doc/controllers/api-exports.md b/doc/controllers/api-exports.md index 1bb6bd13..59cfada9 100644 --- a/doc/controllers/api-exports.md +++ b/doc/controllers/api-exports.md @@ -10,56 +10,15 @@ api_exports_controller = client.api_exports ## Methods -* [List Exported Proforma Invoices](../../doc/controllers/api-exports.md#list-exported-proforma-invoices) * [List Exported Invoices](../../doc/controllers/api-exports.md#list-exported-invoices) * [List Exported Subscriptions](../../doc/controllers/api-exports.md#list-exported-subscriptions) * [Export Proforma Invoices](../../doc/controllers/api-exports.md#export-proforma-invoices) -* [Export Invoices](../../doc/controllers/api-exports.md#export-invoices) -* [Export Subscriptions](../../doc/controllers/api-exports.md#export-subscriptions) * [Read Proforma Invoices Export](../../doc/controllers/api-exports.md#read-proforma-invoices-export) +* [List Exported Proforma Invoices](../../doc/controllers/api-exports.md#list-exported-proforma-invoices) +* [Export Subscriptions](../../doc/controllers/api-exports.md#export-subscriptions) * [Read Invoices Export](../../doc/controllers/api-exports.md#read-invoices-export) * [Read Subscriptions Export](../../doc/controllers/api-exports.md#read-subscriptions-export) - - -# List Exported Proforma Invoices - -This API returns an array of exported proforma invoices for a provided `batch_id`. Pay close attention to pagination in order to control responses from the server. - -Example: `GET https://{subdomain}.chargify.com/api_exports/proforma_invoices/123/rows?per_page=10000&page=1`. - -```python -def list_exported_proforma_invoices(self, - options=dict()) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `batch_id` | `str` | Template, Required | Id of a Batch Job. | -| `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request.
Default value is 100.
The maximum allowed values is 10000; any per_page value over 10000 will be changed to 10000. | -| `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`. | - -## Response Type - -[`List[ProformaInvoice]`](../../doc/models/proforma-invoice.md) - -## Example Usage - -```python -collect = { - 'batch_id': 'batch_id8', - 'per_page': 100, - 'page': 2 -} -result = api_exports_controller.list_exported_proforma_invoices(collect) -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | +* [Export Invoices](../../doc/controllers/api-exports.md#export-invoices) # List Exported Invoices @@ -172,14 +131,21 @@ result = api_exports_controller.export_proforma_invoices() | 409 | Conflict | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | -# Export Invoices +# Read Proforma Invoices Export -This API creates an invoices export and returns a batchjob object. +This API returns a batchjob object for proforma invoices export. ```python -def export_invoices(self) +def read_proforma_invoices_export(self, + batch_id) ``` +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `batch_id` | `str` | Template, Required | Id of a Batch Job. | + ## Response Type [`BatchJobResponse`](../../doc/models/batch-job-response.md) @@ -187,7 +153,9 @@ def export_invoices(self) ## Example Usage ```python -result = api_exports_controller.export_invoices() +batch_id = 'batch_id8' + +result = api_exports_controller.read_proforma_invoices_export(batch_id) ``` ## Errors @@ -195,49 +163,57 @@ result = api_exports_controller.export_invoices() | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | | 404 | Not Found | `APIException` | -| 409 | Conflict | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | -# Export Subscriptions +# List Exported Proforma Invoices -This API creates a subscriptions export and returns a batchjob object. +This API returns an array of exported proforma invoices for a provided `batch_id`. Pay close attention to pagination in order to control responses from the server. + +Example: `GET https://{subdomain}.chargify.com/api_exports/proforma_invoices/123/rows?per_page=10000&page=1`. ```python -def export_subscriptions(self) +def list_exported_proforma_invoices(self, + options=dict()) ``` +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `batch_id` | `str` | Template, Required | Id of a Batch Job. | +| `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request.
Default value is 100.
The maximum allowed values is 10000; any per_page value over 10000 will be changed to 10000. | +| `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`. | + ## Response Type -[`BatchJobResponse`](../../doc/models/batch-job-response.md) +[`List[ProformaInvoice]`](../../doc/models/proforma-invoice.md) ## Example Usage ```python -result = api_exports_controller.export_subscriptions() +collect = { + 'batch_id': 'batch_id8', + 'per_page': 100, + 'page': 2 +} +result = api_exports_controller.list_exported_proforma_invoices(collect) ``` ## Errors | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 409 | Conflict | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | +| 404 | Not Found | `APIException` | -# Read Proforma Invoices Export +# Export Subscriptions -This API returns a batchjob object for proforma invoices export. +This API creates a subscriptions export and returns a batchjob object. ```python -def read_proforma_invoices_export(self, - batch_id) +def export_subscriptions(self) ``` -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `batch_id` | `str` | Template, Required | Id of a Batch Job. | - ## Response Type [`BatchJobResponse`](../../doc/models/batch-job-response.md) @@ -245,16 +221,14 @@ def read_proforma_invoices_export(self, ## Example Usage ```python -batch_id = 'batch_id8' - -result = api_exports_controller.read_proforma_invoices_export(batch_id) +result = api_exports_controller.export_subscriptions() ``` ## Errors | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 404 | Not Found | `APIException` | +| 409 | Conflict | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | # Read Invoices Export @@ -324,3 +298,29 @@ result = api_exports_controller.read_subscriptions_export(batch_id) | --- | --- | --- | | 404 | Not Found | `APIException` | + +# Export Invoices + +This API creates an invoices export and returns a batchjob object. + +```python +def export_invoices(self) +``` + +## Response Type + +[`BatchJobResponse`](../../doc/models/batch-job-response.md) + +## Example Usage + +```python +result = api_exports_controller.export_invoices() +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | +| 409 | Conflict | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | + diff --git a/doc/controllers/billing-portal.md b/doc/controllers/billing-portal.md index 9003432c..79aad1fe 100644 --- a/doc/controllers/billing-portal.md +++ b/doc/controllers/billing-portal.md @@ -11,9 +11,9 @@ billing_portal_controller = client.billing_portal ## Methods * [Enable Billing Portal for Customer](../../doc/controllers/billing-portal.md#enable-billing-portal-for-customer) -* [Read Billing Portal Link](../../doc/controllers/billing-portal.md#read-billing-portal-link) * [Resend Billing Portal Invitation](../../doc/controllers/billing-portal.md#resend-billing-portal-invitation) * [Revoke Billing Portal Access](../../doc/controllers/billing-portal.md#revoke-billing-portal-access) +* [Read Billing Portal Link](../../doc/controllers/billing-portal.md#read-billing-portal-link) # Enable Billing Portal for Customer @@ -66,62 +66,6 @@ result = billing_portal_controller.enable_billing_portal_for_customer(customer_i | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Read Billing Portal Link - -This method will provide to the API user the exact URL required for a subscriber to access the Billing Portal. - -## Rules for Management Link API - -+ When retrieving a management URL, multiple requests for the same customer in a short period will return the **same** URL -+ We will not generate a new URL for 15 days -+ You must cache and remember this URL if you are going to need it again within 15 days -+ Only request a new URL after the `new_link_available_at` date -+ You are limited to 15 requests for the same URL. If you make more than 15 requests before `new_link_available_at`, you will be blocked from further Management URL requests (with a response code `429`) - -```python -def read_billing_portal_link(self, - customer_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `customer_id` | `int` | Template, Required | The Chargify id of the customer | - -## Response Type - -[`PortalManagementLink`](../../doc/models/portal-management-link.md) - -## Example Usage - -```python -customer_id = 150 - -result = billing_portal_controller.read_billing_portal_link(customer_id) -``` - -## Example Response *(as JSON)* - -```json -{ - "url": "https://www.billingportal.com/manage/19804639/1517596469/bd16498719a7d3e6", - "fetch_count": 1, - "created_at": "2018-02-02T18:34:29Z", - "new_link_available_at": "2018-02-17T18:34:29Z", - "expires_at": "2018-04-08T17:34:29Z", - "last_invite_sent_at": "2018-02-02T18:34:29Z" -} -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -| 429 | Too Many Requests | [`TooManyManagementLinkRequestsErrorException`](../../doc/models/too-many-management-link-requests-error-exception.md) | - - # Resend Billing Portal Invitation You can resend a customer's Billing Portal invitation. @@ -223,3 +167,59 @@ result = billing_portal_controller.revoke_billing_portal_access(customer_id) } ``` + +# Read Billing Portal Link + +This method will provide to the API user the exact URL required for a subscriber to access the Billing Portal. + +## Rules for Management Link API + ++ When retrieving a management URL, multiple requests for the same customer in a short period will return the **same** URL ++ We will not generate a new URL for 15 days ++ You must cache and remember this URL if you are going to need it again within 15 days ++ Only request a new URL after the `new_link_available_at` date ++ You are limited to 15 requests for the same URL. If you make more than 15 requests before `new_link_available_at`, you will be blocked from further Management URL requests (with a response code `429`) + +```python +def read_billing_portal_link(self, + customer_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `customer_id` | `int` | Template, Required | The Chargify id of the customer | + +## Response Type + +[`PortalManagementLink`](../../doc/models/portal-management-link.md) + +## Example Usage + +```python +customer_id = 150 + +result = billing_portal_controller.read_billing_portal_link(customer_id) +``` + +## Example Response *(as JSON)* + +```json +{ + "url": "https://www.billingportal.com/manage/19804639/1517596469/bd16498719a7d3e6", + "fetch_count": 1, + "created_at": "2018-02-02T18:34:29Z", + "new_link_available_at": "2018-02-17T18:34:29Z", + "expires_at": "2018-04-08T17:34:29Z", + "last_invite_sent_at": "2018-02-02T18:34:29Z" +} +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +| 429 | Too Many Requests | [`TooManyManagementLinkRequestsErrorException`](../../doc/models/too-many-management-link-requests-error-exception.md) | + diff --git a/doc/controllers/component-price-points.md b/doc/controllers/component-price-points.md index cbc3573f..075574b6 100644 --- a/doc/controllers/component-price-points.md +++ b/doc/controllers/component-price-points.md @@ -12,15 +12,15 @@ component_price_points_controller = client.component_price_points * [Promote Component Price Point to Default](../../doc/controllers/component-price-points.md#promote-component-price-point-to-default) * [Create Component Price Point](../../doc/controllers/component-price-points.md#create-component-price-point) -* [List Component Price Points](../../doc/controllers/component-price-points.md#list-component-price-points) -* [Bulk Create Component Price Points](../../doc/controllers/component-price-points.md#bulk-create-component-price-points) * [Update Component Price Point](../../doc/controllers/component-price-points.md#update-component-price-point) * [Read Component Price Point](../../doc/controllers/component-price-points.md#read-component-price-point) +* [Update Currency Prices](../../doc/controllers/component-price-points.md#update-currency-prices) * [Archive Component Price Point](../../doc/controllers/component-price-points.md#archive-component-price-point) -* [Unarchive Component Price Point](../../doc/controllers/component-price-points.md#unarchive-component-price-point) * [Create Currency Prices](../../doc/controllers/component-price-points.md#create-currency-prices) -* [Update Currency Prices](../../doc/controllers/component-price-points.md#update-currency-prices) * [List All Component Price Points](../../doc/controllers/component-price-points.md#list-all-component-price-points) +* [List Component Price Points](../../doc/controllers/component-price-points.md#list-component-price-points) +* [Bulk Create Component Price Points](../../doc/controllers/component-price-points.md#bulk-create-component-price-points) +* [Unarchive Component Price Point](../../doc/controllers/component-price-points.md#unarchive-component-price-point) # Promote Component Price Point to Default @@ -148,216 +148,6 @@ result = component_price_points_controller.create_component_price_point( ``` -# List Component Price Points - -Use this endpoint to read current price points that are associated with a component. - -You may specify the component by using either the numeric id or the `handle:gold` syntax. - -When fetching a component's price points, if you have defined multiple currencies at the site level, you can optionally pass the `?currency_prices=true` query param to include an array of currency price data in the response. - -If the price point 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_component_price_points(self, - options=dict()) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `component_id` | `int` | Template, Required | The Advanced Billing id of the component | -| `currency_prices` | `bool` | Query, Optional | Include an array of currency price data | -| `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`. | -| `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`. | -| `filter_type` | [`List[PricePointType]`](../../doc/models/price-point-type.md) | Query, Optional | Use in query: `filter[type]=catalog,default`. | - -## Response Type - -[`ComponentPricePointsResponse`](../../doc/models/component-price-points-response.md) - -## Example Usage - -```python -collect = {Liquid error: Value cannot be null. (Parameter 'key') - 'component_id': 222, - 'page': 2, - 'per_page': 50 -} -result = component_price_points_controller.list_component_price_points(collect) -``` - -## Example Response *(as JSON)* - -```json -{ - "price_points": [ - { - "id": 80, - "default": false, - "name": "Wholesale Two", - "pricing_scheme": "per_unit", - "component_id": 74, - "handle": "wholesale-two", - "archived_at": null, - "created_at": "2017-07-05T13:55:40-04:00", - "updated_at": "2017-07-05T13:55:40-04:00", - "prices": [ - { - "id": 121, - "component_id": 74, - "starting_quantity": 1, - "ending_quantity": null, - "unit_price": "5.0" - } - ] - }, - { - "id": 81, - "default": false, - "name": "MSRP", - "pricing_scheme": "per_unit", - "component_id": 74, - "handle": "msrp", - "archived_at": null, - "created_at": "2017-07-05T13:55:40-04:00", - "updated_at": "2017-07-05T13:55:40-04:00", - "prices": [ - { - "id": 122, - "component_id": 74, - "starting_quantity": 1, - "ending_quantity": null, - "unit_price": "4.0" - } - ] - } - ] -} -``` - - -# Bulk Create Component Price Points - -Use this endpoint to create multiple component price points in one request. - -```python -def bulk_create_component_price_points(self, - component_id, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `component_id` | `str` | Template, Required | The Advanced Billing id of the component for which you want to fetch price points. | -| `body` | [`CreateComponentPricePointsRequest`](../../doc/models/create-component-price-points-request.md) | Body, Optional | - | - -## Response Type - -[`ComponentPricePointsResponse`](../../doc/models/component-price-points-response.md) - -## Example Usage - -```python -component_id = 'component_id8' - -body = CreateComponentPricePointsRequest( - price_points=[ - CreateComponentPricePoint( - name='Wholesale', - pricing_scheme=PricingScheme.PER_UNIT, - prices=[ - Price( - starting_quantity=1, - unit_price=5 - ) - ], - handle='wholesale' - ), - CreateComponentPricePoint( - name='MSRP', - pricing_scheme=PricingScheme.PER_UNIT, - prices=[ - Price( - starting_quantity=1, - unit_price=4 - ) - ], - handle='msrp' - ), - CreateComponentPricePoint( - name='Special Pricing', - pricing_scheme=PricingScheme.PER_UNIT, - prices=[ - Price( - starting_quantity=1, - unit_price=5 - ) - ], - handle='special' - ) - ] -) - -result = component_price_points_controller.bulk_create_component_price_points( - component_id, - body=body -) -``` - -## Example Response *(as JSON)* - -```json -{ - "price_points": [ - { - "id": 80, - "default": false, - "name": "Wholesale Two", - "pricing_scheme": "per_unit", - "component_id": 74, - "handle": "wholesale-two", - "archived_at": null, - "created_at": "2017-07-05T13:55:40-04:00", - "updated_at": "2017-07-05T13:55:40-04:00", - "prices": [ - { - "id": 121, - "component_id": 74, - "starting_quantity": 1, - "ending_quantity": null, - "unit_price": "5.0" - } - ] - }, - { - "id": 81, - "default": false, - "name": "MSRP", - "pricing_scheme": "per_unit", - "component_id": 74, - "handle": "msrp", - "archived_at": null, - "created_at": "2017-07-05T13:55:40-04:00", - "updated_at": "2017-07-05T13:55:40-04:00", - "prices": [ - { - "id": 122, - "component_id": 74, - "starting_quantity": 1, - "ending_quantity": null, - "unit_price": "4.0" - } - ] - } - ] -} -``` - - # 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. @@ -464,71 +254,67 @@ result = component_price_points_controller.read_component_price_point( ``` -# Archive Component Price Point +# Update Currency Prices -A price point can be archived at any time. Subscriptions using a price point that has been archived will continue using it until they're moved to another price point. +This endpoint allows you to update currency prices for a given currency that has been defined on the site level in your settings. + +Note: Currency Prices are not able to be updated for custom price points. ```python -def archive_component_price_point(self, - component_id, - price_point_id) +def update_currency_prices(self, + price_point_id, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `component_id` | int \| str | Template, Required | This is a container for one-of cases. | -| `price_point_id` | int \| str | Template, Required | This is a container for one-of cases. | +| `price_point_id` | `int` | Template, Required | The Advanced Billing id of the price point | +| `body` | [`UpdateCurrencyPricesRequest`](../../doc/models/update-currency-prices-request.md) | Body, Optional | - | ## Response Type -[`ComponentPricePointResponse`](../../doc/models/component-price-point-response.md) +[`ComponentCurrencyPricesResponse`](../../doc/models/component-currency-prices-response.md) ## Example Usage ```python -component_id = 144 - -price_point_id = 188 +price_point_id = 10 -result = component_price_points_controller.archive_component_price_point( - component_id, - price_point_id +body = UpdateCurrencyPricesRequest( + currency_prices=[ + UpdateCurrencyPrice( + id=100, + price=51 + ), + UpdateCurrencyPrice( + id=101, + price=41 + ) + ] ) -``` -## Example Response *(as JSON)* +result = component_price_points_controller.update_currency_prices( + price_point_id, + body=body +) +``` + +## Example Response *(as JSON)* ```json { - "price_point": { - "id": 79, - "default": false, - "name": "Wholesale", - "pricing_scheme": "stairstep", - "component_id": 74, - "handle": "wholesale-handle", - "archived_at": "2017-07-06T15:04:00-04:00", - "created_at": "2017-07-05T13:44:30-04:00", - "updated_at": "2017-07-05T13:44:30-04:00", - "prices": [ - { - "id": 119, - "component_id": 74, - "starting_quantity": 1, - "ending_quantity": 100, - "unit_price": "5.0" - }, - { - "id": 120, - "component_id": 74, - "starting_quantity": 101, - "ending_quantity": null, - "unit_price": "4.0" - } - ] - } + "currency_prices": [ + { + "id": 100, + "currency": "EUR", + "price": "123", + "formatted_price": "€123,00", + "price_id": 32669, + "price_point_id": 25554 + } + ] } ``` @@ -536,25 +322,25 @@ result = component_price_points_controller.archive_component_price_point( | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorArrayMapResponseException`](../../doc/models/error-array-map-response-exception.md) | -# Unarchive Component Price Point +# Archive Component Price Point -Use this endpoint to unarchive a component price point. +A price point can be archived at any time. Subscriptions using a price point that has been archived will continue using it until they're moved to another price point. ```python -def unarchive_component_price_point(self, - component_id, - price_point_id) +def archive_component_price_point(self, + component_id, + price_point_id) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `component_id` | `int` | Template, Required | The Advanced Billing id of the component to which the price point belongs | -| `price_point_id` | `int` | Template, Required | The Advanced Billing id of the price point | +| `component_id` | int \| str | Template, Required | This is a container for one-of cases. | +| `price_point_id` | int \| str | Template, Required | This is a container for one-of cases. | ## Response Type @@ -563,11 +349,11 @@ def unarchive_component_price_point(self, ## Example Usage ```python -component_id = 222 +component_id = 144 -price_point_id = 10 +price_point_id = 188 -result = component_price_points_controller.unarchive_component_price_point( +result = component_price_points_controller.archive_component_price_point( component_id, price_point_id ) @@ -584,7 +370,7 @@ result = component_price_points_controller.unarchive_component_price_point( "pricing_scheme": "stairstep", "component_id": 74, "handle": "wholesale-handle", - "archived_at": null, + "archived_at": "2017-07-06T15:04:00-04:00", "created_at": "2017-07-05T13:44:30-04:00", "updated_at": "2017-07-05T13:44:30-04:00", "prices": [ @@ -607,6 +393,12 @@ result = component_price_points_controller.unarchive_component_price_point( } ``` +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + # Create Currency Prices @@ -683,77 +475,6 @@ result = component_price_points_controller.create_currency_prices( | 422 | Unprocessable Entity (WebDAV) | [`ErrorArrayMapResponseException`](../../doc/models/error-array-map-response-exception.md) | -# Update Currency Prices - -This endpoint allows you to update currency prices for a given currency that has been defined on the site level in your settings. - -Note: Currency Prices are not able to be updated for custom price points. - -```python -def update_currency_prices(self, - price_point_id, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `price_point_id` | `int` | Template, Required | The Advanced Billing id of the price point | -| `body` | [`UpdateCurrencyPricesRequest`](../../doc/models/update-currency-prices-request.md) | Body, Optional | - | - -## Response Type - -[`ComponentCurrencyPricesResponse`](../../doc/models/component-currency-prices-response.md) - -## Example Usage - -```python -price_point_id = 10 - -body = UpdateCurrencyPricesRequest( - currency_prices=[ - UpdateCurrencyPrice( - id=100, - price=51 - ), - UpdateCurrencyPrice( - id=101, - price=41 - ) - ] -) - -result = component_price_points_controller.update_currency_prices( - price_point_id, - body=body -) -``` - -## Example Response *(as JSON)* - -```json -{ - "currency_prices": [ - { - "id": 100, - "currency": "EUR", - "price": "123", - "formatted_price": "€123,00", - "price_id": 32669, - "price_point_id": 25554 - } - ] -} -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorArrayMapResponseException`](../../doc/models/error-array-map-response-exception.md) | - - # List All Component Price Points This method allows to retrieve a list of Components Price Points belonging to a Site. @@ -843,3 +564,282 @@ result = component_price_points_controller.list_all_component_price_points(colle | --- | --- | --- | | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + +# List Component Price Points + +Use this endpoint to read current price points that are associated with a component. + +You may specify the component by using either the numeric id or the `handle:gold` syntax. + +When fetching a component's price points, if you have defined multiple currencies at the site level, you can optionally pass the `?currency_prices=true` query param to include an array of currency price data in the response. + +If the price point 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_component_price_points(self, + options=dict()) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `component_id` | `int` | Template, Required | The Advanced Billing id of the component | +| `currency_prices` | `bool` | Query, Optional | Include an array of currency price data | +| `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`. | +| `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`. | +| `filter_type` | [`List[PricePointType]`](../../doc/models/price-point-type.md) | Query, Optional | Use in query: `filter[type]=catalog,default`. | + +## Response Type + +[`ComponentPricePointsResponse`](../../doc/models/component-price-points-response.md) + +## Example Usage + +```python +collect = {Liquid error: Value cannot be null. (Parameter 'key') + 'component_id': 222, + 'page': 2, + 'per_page': 50 +} +result = component_price_points_controller.list_component_price_points(collect) +``` + +## Example Response *(as JSON)* + +```json +{ + "price_points": [ + { + "id": 80, + "default": false, + "name": "Wholesale Two", + "pricing_scheme": "per_unit", + "component_id": 74, + "handle": "wholesale-two", + "archived_at": null, + "created_at": "2017-07-05T13:55:40-04:00", + "updated_at": "2017-07-05T13:55:40-04:00", + "prices": [ + { + "id": 121, + "component_id": 74, + "starting_quantity": 1, + "ending_quantity": null, + "unit_price": "5.0" + } + ] + }, + { + "id": 81, + "default": false, + "name": "MSRP", + "pricing_scheme": "per_unit", + "component_id": 74, + "handle": "msrp", + "archived_at": null, + "created_at": "2017-07-05T13:55:40-04:00", + "updated_at": "2017-07-05T13:55:40-04:00", + "prices": [ + { + "id": 122, + "component_id": 74, + "starting_quantity": 1, + "ending_quantity": null, + "unit_price": "4.0" + } + ] + } + ] +} +``` + + +# Bulk Create Component Price Points + +Use this endpoint to create multiple component price points in one request. + +```python +def bulk_create_component_price_points(self, + component_id, + body=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `component_id` | `str` | Template, Required | The Advanced Billing id of the component for which you want to fetch price points. | +| `body` | [`CreateComponentPricePointsRequest`](../../doc/models/create-component-price-points-request.md) | Body, Optional | - | + +## Response Type + +[`ComponentPricePointsResponse`](../../doc/models/component-price-points-response.md) + +## Example Usage + +```python +component_id = 'component_id8' + +body = CreateComponentPricePointsRequest( + price_points=[ + CreateComponentPricePoint( + name='Wholesale', + pricing_scheme=PricingScheme.PER_UNIT, + prices=[ + Price( + starting_quantity=1, + unit_price=5 + ) + ], + handle='wholesale' + ), + CreateComponentPricePoint( + name='MSRP', + pricing_scheme=PricingScheme.PER_UNIT, + prices=[ + Price( + starting_quantity=1, + unit_price=4 + ) + ], + handle='msrp' + ), + CreateComponentPricePoint( + name='Special Pricing', + pricing_scheme=PricingScheme.PER_UNIT, + prices=[ + Price( + starting_quantity=1, + unit_price=5 + ) + ], + handle='special' + ) + ] +) + +result = component_price_points_controller.bulk_create_component_price_points( + component_id, + body=body +) +``` + +## Example Response *(as JSON)* + +```json +{ + "price_points": [ + { + "id": 80, + "default": false, + "name": "Wholesale Two", + "pricing_scheme": "per_unit", + "component_id": 74, + "handle": "wholesale-two", + "archived_at": null, + "created_at": "2017-07-05T13:55:40-04:00", + "updated_at": "2017-07-05T13:55:40-04:00", + "prices": [ + { + "id": 121, + "component_id": 74, + "starting_quantity": 1, + "ending_quantity": null, + "unit_price": "5.0" + } + ] + }, + { + "id": 81, + "default": false, + "name": "MSRP", + "pricing_scheme": "per_unit", + "component_id": 74, + "handle": "msrp", + "archived_at": null, + "created_at": "2017-07-05T13:55:40-04:00", + "updated_at": "2017-07-05T13:55:40-04:00", + "prices": [ + { + "id": 122, + "component_id": 74, + "starting_quantity": 1, + "ending_quantity": null, + "unit_price": "4.0" + } + ] + } + ] +} +``` + + +# Unarchive Component Price Point + +Use this endpoint to unarchive a component price point. + +```python +def unarchive_component_price_point(self, + component_id, + price_point_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `component_id` | `int` | Template, Required | The Advanced Billing id of the component to which the price point belongs | +| `price_point_id` | `int` | Template, Required | The Advanced Billing id of the price point | + +## Response Type + +[`ComponentPricePointResponse`](../../doc/models/component-price-point-response.md) + +## Example Usage + +```python +component_id = 222 + +price_point_id = 10 + +result = component_price_points_controller.unarchive_component_price_point( + component_id, + price_point_id +) +``` + +## Example Response *(as JSON)* + +```json +{ + "price_point": { + "id": 79, + "default": false, + "name": "Wholesale", + "pricing_scheme": "stairstep", + "component_id": 74, + "handle": "wholesale-handle", + "archived_at": null, + "created_at": "2017-07-05T13:44:30-04:00", + "updated_at": "2017-07-05T13:44:30-04:00", + "prices": [ + { + "id": 119, + "component_id": 74, + "starting_quantity": 1, + "ending_quantity": 100, + "unit_price": "5.0" + }, + { + "id": 120, + "component_id": 74, + "starting_quantity": 101, + "ending_quantity": null, + "unit_price": "4.0" + } + ] + } +} +``` + diff --git a/doc/controllers/components.md b/doc/controllers/components.md index e55e9ac4..7a4aa795 100644 --- a/doc/controllers/components.md +++ b/doc/controllers/components.md @@ -10,34 +10,32 @@ components_controller = client.components ## Methods -* [Create Metered Component](../../doc/controllers/components.md#create-metered-component) +* [Create Prepaid Usage Component](../../doc/controllers/components.md#create-prepaid-usage-component) * [Create Quantity Based Component](../../doc/controllers/components.md#create-quantity-based-component) * [Create on Off Component](../../doc/controllers/components.md#create-on-off-component) -* [Create Prepaid Usage Component](../../doc/controllers/components.md#create-prepaid-usage-component) * [Create Event Based Component](../../doc/controllers/components.md#create-event-based-component) * [Find Component](../../doc/controllers/components.md#find-component) +* [Create Metered Component](../../doc/controllers/components.md#create-metered-component) * [Read Component](../../doc/controllers/components.md#read-component) -* [Update Product Family Component](../../doc/controllers/components.md#update-product-family-component) * [Archive Component](../../doc/controllers/components.md#archive-component) +* [Update Product Family Component](../../doc/controllers/components.md#update-product-family-component) * [List Components](../../doc/controllers/components.md#list-components) * [Update Component](../../doc/controllers/components.md#update-component) * [List Components for Product Family](../../doc/controllers/components.md#list-components-for-product-family) -# Create Metered Component - -This request will create a component definition of kind **metered_component** under the specified product family. Metered component can then be added and “allocated” for a subscription. +# Create Prepaid Usage Component -Metered components are used to bill for any type of unit that resets to 0 at the end of the billing period (think daily Google Adwords clicks or monthly cell phone minutes). This is most commonly associated with usage-based billing and many other pricing schemes. +This request will create a component definition of kind **prepaid_usage_component** under the specified product family. Prepaid component can then be added and “allocated” for a subscription. -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. +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). ```python -def create_metered_component(self, - product_family_id, - body=None) +def create_prepaid_usage_component(self, + product_family_id, + body=None) ``` ## Parameters @@ -45,7 +43,7 @@ def create_metered_component(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `product_family_id` | `str` | Template, Required | Either the product family's id or its handle prefixed with `handle:` | -| `body` | [`CreateMeteredComponent`](../../doc/models/create-metered-component.md) | Body, Optional | - | +| `body` | [`CreatePrepaidComponent`](../../doc/models/create-prepaid-component.md) | Body, Optional | - | ## Response Type @@ -56,22 +54,34 @@ def create_metered_component(self, ```python product_family_id = 'product_family_id4' -body = CreateMeteredComponent( - metered_component=MeteredComponent( - name='Text messages', - unit_name='text message', +body = CreatePrepaidComponent( + prepaid_usage_component=PrepaidUsageComponent( + name='Minutes', + unit_name='minutes', pricing_scheme=PricingScheme.PER_UNIT, - taxable=False, - prices=[ - Price( - starting_quantity=1, - unit_price=1 - ) - ] + unit_price=2, + overage_pricing=OveragePricing( + pricing_scheme=PricingScheme.STAIRSTEP, + prices=[ + Price( + starting_quantity=1, + unit_price=3, + ending_quantity=100 + ), + Price( + starting_quantity=101, + unit_price=5 + ) + ] + ), + rollover_prepaid_remainder=True, + renew_prepaid_allocation=True, + expiration_interval=15, + expiration_interval_unit=ExpirationIntervalUnit.DAY ) ) -result = components_controller.create_metered_component( +result = components_controller.create_prepaid_usage_component( product_family_id, body=body ) @@ -83,28 +93,40 @@ result = components_controller.create_metered_component( { "component": { "id": 292609, - "name": "Text messages", - "handle": "text-messages", + "name": "Test Prepaid Component 98505", + "handle": "test-prepaid-component-9850584842", "pricing_scheme": "per_unit", "unit_name": "unit", "unit_price": "10.0", "product_family_id": 528484, - "product_family_name": "Cloud Compute Servers", + "product_family_name": "Test Product Family 27791", "price_per_unit_in_cents": null, - "kind": "metered_component", + "kind": "prepaid_usage_component", "archived": false, "taxable": false, - "description": null, + "description": "Description for: Test Prepaid Component 98505", "default_price_point_id": 2944263, + "overage_prices": [ + { + "id": 55964, + "component_id": 30427, + "starting_quantity": 1, + "ending_quantity": null, + "unit_price": "1.0", + "price_point_id": 2944756, + "formatted_unit_price": "$1.00", + "segment_id": null + } + ], "prices": [ { - "id": 55423, - "component_id": 30002, + "id": 55963, + "component_id": 30427, "starting_quantity": 1, "ending_quantity": null, - "unit_price": "10.0", - "price_point_id": 2944263, - "formatted_unit_price": "$10.00", + "unit_price": "1.0", + "price_point_id": 2944756, + "formatted_unit_price": "$1.00", "segment_id": null } ], @@ -112,7 +134,7 @@ result = components_controller.create_metered_component( "price_points_url": "https://demo-3238403362.chargify.com/components/30002/price_points", "default_price_point_name": "Original", "tax_code": null, - "recurring": false, + "recurring": true, "upgrade_charge": null, "downgrade_credit": null, "created_at": "2024-01-23T06:08:05-05:00", @@ -355,139 +377,6 @@ result = components_controller.create_on_off_component( | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Create Prepaid Usage Component - -This request will create a component definition of kind **prepaid_usage_component** under the specified product family. Prepaid component can then be added and “allocated” for a subscription. - -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). - -```python -def create_prepaid_usage_component(self, - product_family_id, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `product_family_id` | `str` | Template, Required | Either the product family's id or its handle prefixed with `handle:` | -| `body` | [`CreatePrepaidComponent`](../../doc/models/create-prepaid-component.md) | Body, Optional | - | - -## Response Type - -[`ComponentResponse`](../../doc/models/component-response.md) - -## Example Usage - -```python -product_family_id = 'product_family_id4' - -body = CreatePrepaidComponent( - prepaid_usage_component=PrepaidUsageComponent( - name='Minutes', - unit_name='minutes', - pricing_scheme=PricingScheme.PER_UNIT, - unit_price=2, - overage_pricing=OveragePricing( - pricing_scheme=PricingScheme.STAIRSTEP, - prices=[ - Price( - starting_quantity=1, - unit_price=3, - ending_quantity=100 - ), - Price( - starting_quantity=101, - unit_price=5 - ) - ] - ), - rollover_prepaid_remainder=True, - renew_prepaid_allocation=True, - expiration_interval=15, - expiration_interval_unit=ExpirationIntervalUnit.DAY - ) -) - -result = components_controller.create_prepaid_usage_component( - product_family_id, - body=body -) -``` - -## Example Response *(as JSON)* - -```json -{ - "component": { - "id": 292609, - "name": "Test Prepaid Component 98505", - "handle": "test-prepaid-component-9850584842", - "pricing_scheme": "per_unit", - "unit_name": "unit", - "unit_price": "10.0", - "product_family_id": 528484, - "product_family_name": "Test Product Family 27791", - "price_per_unit_in_cents": null, - "kind": "prepaid_usage_component", - "archived": false, - "taxable": false, - "description": "Description for: Test Prepaid Component 98505", - "default_price_point_id": 2944263, - "overage_prices": [ - { - "id": 55964, - "component_id": 30427, - "starting_quantity": 1, - "ending_quantity": null, - "unit_price": "1.0", - "price_point_id": 2944756, - "formatted_unit_price": "$1.00", - "segment_id": null - } - ], - "prices": [ - { - "id": 55963, - "component_id": 30427, - "starting_quantity": 1, - "ending_quantity": null, - "unit_price": "1.0", - "price_point_id": 2944756, - "formatted_unit_price": "$1.00", - "segment_id": null - } - ], - "price_point_count": 1, - "price_points_url": "https://demo-3238403362.chargify.com/components/30002/price_points", - "default_price_point_name": "Original", - "tax_code": null, - "recurring": true, - "upgrade_charge": null, - "downgrade_credit": null, - "created_at": "2024-01-23T06:08:05-05:00", - "updated_at": "2024-01-23T06:08:05-05:00", - "archived_at": null, - "hide_date_range_on_invoice": false, - "allow_fractional_quantities": false, - "use_site_exchange_rate": true, - "item_category": null, - "accounting_code": null - } -} -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - - # Create Event Based Component This request will create a component definition of kind **event_based_component** under the specified product family. Event-based component can then be added and “allocated” for a subscription. @@ -649,24 +538,28 @@ result = components_controller.find_component(handle) ``` -# Read Component +# Create Metered Component -This request will return information regarding a component from a specific product family. +This request will create a component definition of kind **metered_component** under the specified product family. Metered component can then be added and “allocated” for a subscription. -You may read the component by either the component's id or handle. When using the handle, it must be prefixed with `handle:`. +Metered components are used to bill for any type of unit that resets to 0 at the end of the billing period (think daily Google Adwords clicks or monthly cell phone minutes). This is most commonly associated with usage-based billing and many other pricing schemes. + +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). ```python -def read_component(self, - product_family_id, - component_id) +def create_metered_component(self, + product_family_id, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `product_family_id` | `int` | Template, Required | The Advanced Billing id of the product family to which the component belongs | -| `component_id` | `str` | Template, Required | Either the Advanced Billing id of the component or the handle for the component prefixed with `handle:` | +| `product_family_id` | `str` | Template, Required | Either the product family's id or its handle prefixed with `handle:` | +| `body` | [`CreateMeteredComponent`](../../doc/models/create-metered-component.md) | Body, Optional | - | ## Response Type @@ -675,13 +568,26 @@ def read_component(self, ## Example Usage ```python -product_family_id = 140 +product_family_id = 'product_family_id4' -component_id = 'component_id8' +body = CreateMeteredComponent( + metered_component=MeteredComponent( + name='Text messages', + unit_name='text message', + pricing_scheme=PricingScheme.PER_UNIT, + taxable=False, + prices=[ + Price( + starting_quantity=1, + unit_price=1 + ) + ] + ) +) -result = components_controller.read_component( +result = components_controller.create_metered_component( product_family_id, - component_id + body=body ) ``` @@ -690,43 +596,69 @@ result = components_controller.read_component( ```json { "component": { - "id": 399853, - "name": "Annual Support Services", - "pricing_scheme": null, - "unit_name": "on/off", - "unit_price": "100.0", - "product_family_id": 997233, + "id": 292609, + "name": "Text messages", + "handle": "text-messages", + "pricing_scheme": "per_unit", + "unit_name": "unit", + "unit_price": "10.0", + "product_family_id": 528484, + "product_family_name": "Cloud Compute Servers", "price_per_unit_in_cents": null, - "kind": "on_off_component", + "kind": "metered_component", "archived": false, - "taxable": true, - "description": "Prepay for support services", - "default_price_point_id": 121003, - "price_point_count": 4, - "price_points_url": "https://general-goods.chargify.com/components/399853/price_points", - "tax_code": "D0000000", - "recurring": true, + "taxable": false, + "description": null, + "default_price_point_id": 2944263, + "prices": [ + { + "id": 55423, + "component_id": 30002, + "starting_quantity": 1, + "ending_quantity": null, + "unit_price": "10.0", + "price_point_id": 2944263, + "formatted_unit_price": "$10.00", + "segment_id": null + } + ], + "price_point_count": 1, + "price_points_url": "https://demo-3238403362.chargify.com/components/30002/price_points", + "default_price_point_name": "Original", + "tax_code": null, + "recurring": false, "upgrade_charge": null, "downgrade_credit": null, - "created_at": "2019-08-02T05:54:53-04:00", - "default_price_point_name": "Original", - "product_family_name": "Chargify" + "created_at": "2024-01-23T06:08:05-05:00", + "updated_at": "2024-01-23T06:08:05-05:00", + "archived_at": null, + "hide_date_range_on_invoice": false, + "allow_fractional_quantities": false, + "use_site_exchange_rate": true, + "item_category": null, + "accounting_code": null } } ``` +## Errors -# Update Product Family Component +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -This request will update a component from a specific product family. + +# Read Component + +This request will return information regarding a component from a specific product family. You may read the component by either the component's id or handle. When using the handle, it must be prefixed with `handle:`. ```python -def update_product_family_component(self, - product_family_id, - component_id, - body=None) +def read_component(self, + product_family_id, + component_id) ``` ## Parameters @@ -735,7 +667,6 @@ def update_product_family_component(self, | --- | --- | --- | --- | | `product_family_id` | `int` | Template, Required | The Advanced Billing id of the product family to which the component belongs | | `component_id` | `str` | Template, Required | Either the Advanced Billing id of the component or the handle for the component prefixed with `handle:` | -| `body` | [`UpdateComponentRequest`](../../doc/models/update-component-request.md) | Body, Optional | - | ## Response Type @@ -748,16 +679,9 @@ product_family_id = 140 component_id = 'component_id8' -body = UpdateComponentRequest( - component=UpdateComponent( - item_category=ItemCategory.ENUM_BUSINESS_SOFTWARE - ) -) - -result = components_controller.update_product_family_component( +result = components_controller.read_component( product_family_id, - component_id, - body=body + component_id ) ``` @@ -791,12 +715,6 @@ result = components_controller.update_product_family_component( } ``` -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - # Archive Component @@ -865,6 +783,88 @@ result = components_controller.archive_component( | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +# Update Product Family Component + +This request will update a component from a specific product family. + +You may read the component by either the component's id or handle. When using the handle, it must be prefixed with `handle:`. + +```python +def update_product_family_component(self, + product_family_id, + component_id, + body=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `product_family_id` | `int` | Template, Required | The Advanced Billing id of the product family to which the component belongs | +| `component_id` | `str` | Template, Required | Either the Advanced Billing id of the component or the handle for the component prefixed with `handle:` | +| `body` | [`UpdateComponentRequest`](../../doc/models/update-component-request.md) | Body, Optional | - | + +## Response Type + +[`ComponentResponse`](../../doc/models/component-response.md) + +## Example Usage + +```python +product_family_id = 140 + +component_id = 'component_id8' + +body = UpdateComponentRequest( + component=UpdateComponent( + item_category=ItemCategory.ENUM_BUSINESS_SOFTWARE + ) +) + +result = components_controller.update_product_family_component( + product_family_id, + component_id, + body=body +) +``` + +## Example Response *(as JSON)* + +```json +{ + "component": { + "id": 399853, + "name": "Annual Support Services", + "pricing_scheme": null, + "unit_name": "on/off", + "unit_price": "100.0", + "product_family_id": 997233, + "price_per_unit_in_cents": null, + "kind": "on_off_component", + "archived": false, + "taxable": true, + "description": "Prepay for support services", + "default_price_point_id": 121003, + "price_point_count": 4, + "price_points_url": "https://general-goods.chargify.com/components/399853/price_points", + "tax_code": "D0000000", + "recurring": true, + "upgrade_charge": null, + "downgrade_credit": null, + "created_at": "2019-08-02T05:54:53-04:00", + "default_price_point_name": "Original", + "product_family_name": "Chargify" + } +} +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + + # List Components This request will return a list of components for a site. diff --git a/doc/controllers/coupons.md b/doc/controllers/coupons.md index bbf0a297..201399d1 100644 --- a/doc/controllers/coupons.md +++ b/doc/controllers/coupons.md @@ -10,96 +10,20 @@ coupons_controller = client.coupons ## Methods -* [Create Coupon](../../doc/controllers/coupons.md#create-coupon) * [List Coupons for Product Family](../../doc/controllers/coupons.md#list-coupons-for-product-family) -* [Find Coupon](../../doc/controllers/coupons.md#find-coupon) -* [Read Coupon](../../doc/controllers/coupons.md#read-coupon) -* [Update Coupon](../../doc/controllers/coupons.md#update-coupon) -* [Archive Coupon](../../doc/controllers/coupons.md#archive-coupon) * [List Coupons](../../doc/controllers/coupons.md#list-coupons) -* [Read Coupon Usage](../../doc/controllers/coupons.md#read-coupon-usage) -* [Validate Coupon](../../doc/controllers/coupons.md#validate-coupon) * [Create or Update Coupon Currency Prices](../../doc/controllers/coupons.md#create-or-update-coupon-currency-prices) * [Create Coupon Subcodes](../../doc/controllers/coupons.md#create-coupon-subcodes) * [List Coupon Subcodes](../../doc/controllers/coupons.md#list-coupon-subcodes) -* [Update Coupon Subcodes](../../doc/controllers/coupons.md#update-coupon-subcodes) * [Delete Coupon Subcode](../../doc/controllers/coupons.md#delete-coupon-subcode) - - -# Create Coupon - -## 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. - -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). - -## Create Coupon - -This request will create a coupon, based on the provided information. - -When creating a coupon, you must specify a product family using the `product_family_id`. If no `product_family_id` is passed, the first product family available is used. You will also need to formulate your URL to cite the Product Family ID in your request. - -You can restrict a coupon to only apply to specific products / components by optionally passing in hashes of `restricted_products` and/or `restricted_components` in the format: -`{ "": boolean_value }` - -```python -def create_coupon(self, - product_family_id, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `product_family_id` | `int` | Template, Required | The Advanced Billing id of the product family to which the coupon belongs | -| `body` | [`CreateOrUpdateCoupon`](../../doc/models/create-or-update-coupon.md) | Body, Optional | - | - -## Response Type - -[`CouponResponse`](../../doc/models/coupon-response.md) - -## Example Usage - -```python -product_family_id = 140 - -body = CreateOrUpdateCoupon( - coupon=CreateOrUpdatePercentageCoupon( - name='15% off', - code='15OFF', - percentage=15, - description='15% off for life', - allow_negative_balance=False, - recurring=False, - end_date=dateutil.parser.parse('2012-08-29T12:00:00-04:00'), - product_family_id='2', - stackable=True, - compounding_strategy=CompoundingStrategy.COMPOUND, - exclude_mid_period_allocations=True, - apply_on_cancel_at_end_of_period=True - ), - restricted_products={ - '1': True - }, - restricted_components={ - '1': True, - '2': False - } -) - -result = coupons_controller.create_coupon( - product_family_id, - body=body -) -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +* [Find Coupon](../../doc/controllers/coupons.md#find-coupon) +* [Read Coupon Usage](../../doc/controllers/coupons.md#read-coupon-usage) +* [Validate Coupon](../../doc/controllers/coupons.md#validate-coupon) +* [Update Coupon Subcodes](../../doc/controllers/coupons.md#update-coupon-subcodes) +* [Create Coupon](../../doc/controllers/coupons.md#create-coupon) +* [Read Coupon](../../doc/controllers/coupons.md#read-coupon) +* [Update Coupon](../../doc/controllers/coupons.md#update-coupon) +* [Archive Coupon](../../doc/controllers/coupons.md#archive-coupon) # List Coupons for Product Family @@ -246,164 +170,227 @@ result = coupons_controller.list_coupons_for_product_family(collect) ``` -# Find Coupon +# List Coupons -You can search for a coupon via the API with the find method. By passing a code parameter, the find will attempt to locate a coupon that matches that code. If no coupon is found, a 404 is returned. +You can retrieve a list of coupons. -If you have more than one product family and if the coupon you are trying to find does not belong to the default product family in your site, then you will need to specify (either in the url or as a query string param) the product family id. +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 find_coupon(self, - product_family_id=None, - code=None) +def list_coupons(self, + options=dict()) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `product_family_id` | `int` | Query, Optional | The Advanced Billing id of the product family to which the coupon belongs | -| `code` | `str` | Query, Optional | The code of the coupon | +| `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`. | +| `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request. Default value is 30. The maximum allowed values is 200; any per_page value over 200 will be changed to 200.
Use in query `per_page=200`. | +| `filter` | [`ListCouponsFilter`](../../doc/models/list-coupons-filter.md) | Query, Optional | Filter to use for List Coupons operations | +| `currency_prices` | `bool` | Query, Optional | When fetching coupons, if you have defined multiple currencies at the site level, you can optionally pass the `?currency_prices=true` query param to include an array of currency price data in the response. Use in query `currency_prices=true`. | ## Response Type -[`CouponResponse`](../../doc/models/coupon-response.md) +[`List[CouponResponse]`](../../doc/models/coupon-response.md) ## Example Usage ```python -result = coupons_controller.find_coupon() +collect = { + 'page': 2, + 'per_page': 50, + 'filter': ListCouponsFilter( + start_date=dateutil.parser.parse('2011-12-17').date(), + end_date=dateutil.parser.parse('2011-12-15').date(), + start_datetime=dateutil.parser.parse('12/19/2011 09:15:30'), + end_datetime=dateutil.parser.parse('06/07/2019 17:20:06'), + ids=[ + 1, + 2, + 3 + ], + codes=[ + 'free', + 'free_trial' + ] + ), + 'currency_prices': True +} +result = coupons_controller.list_coupons(collect) ``` +## Example Response *(as JSON)* -# Read Coupon +```json +[ + { + "coupon": { + "id": 0, + "name": "string", + "code": "string", + "description": "string", + "amount": 0, + "amount_in_cents": 0, + "product_family_id": 0, + "product_family_name": "string", + "start_date": "2021-05-03T16:00:21-04:00", + "end_date": "2023-05-05T16:00:21-04:00", + "percentage": "10", + "recurring": true, + "recurring_scheme": "do_not_recur", + "duration_period_count": 0, + "duration_interval": 0, + "duration_interval_unit": "string", + "duration_interval_span": "string", + "allow_negative_balance": true, + "archived_at": null, + "conversion_limit": "string", + "stackable": true, + "compounding_strategy": "compound", + "use_site_exchange_rate": true, + "created_at": "2021-05-05T16:00:21-04:00", + "updated_at": "2021-05-05T16:00:21-04:00", + "discount_type": "amount", + "exclude_mid_period_allocations": true, + "apply_on_cancel_at_end_of_period": true, + "coupon_restrictions": [ + { + "id": 0, + "item_type": "Component", + "item_id": 0, + "name": "string", + "handle": "string" + } + ] + } + } +] +``` -You can retrieve the Coupon via the API with the Show method. You must identify the Coupon in this call by the ID parameter that Advanced Billing assigns. -If instead you would like to find a Coupon using a Coupon code, see the Coupon Find method. -When fetching a coupon, if you have defined multiple currencies at the site level, you can optionally pass the `?currency_prices=true` query param to include an array of currency price data in the response. +# Create or Update Coupon Currency Prices -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. +This endpoint allows you to create and/or update currency prices for an existing coupon. Multiple prices can be created or updated in a single request but each of the currencies must be defined on the site level already and the coupon must be an amount-based coupon, not percentage. + +Currency pricing for coupons must mirror the setup of the primary coupon pricing - if the primary coupon is percentage based, you will not be able to define pricing in non-primary currencies. ```python -def read_coupon(self, - product_family_id, - coupon_id) +def create_or_update_coupon_currency_prices(self, + coupon_id, + body=None) ``` ## Parameters | 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 | +| `body` | [`CouponCurrencyRequest`](../../doc/models/coupon-currency-request.md) | Body, Optional | - | ## Response Type -[`CouponResponse`](../../doc/models/coupon-response.md) +[`CouponCurrencyResponse`](../../doc/models/coupon-currency-response.md) ## Example Usage ```python -product_family_id = 140 - coupon_id = 162 -result = coupons_controller.read_coupon( - product_family_id, - coupon_id +body = CouponCurrencyRequest( + currency_prices=[ + UpdateCouponCurrency( + currency='EUR', + price=10 + ), + UpdateCouponCurrency( + currency='GBP', + price=9 + ) + ] ) -``` - -## Example Response *(as JSON)* -```json -{ - "coupon": { - "id": 67, - "name": "Foo Bar", - "code": "YEPPER99934", - "description": "my cool coupon", - "amount_in_cents": null, - "product_family_id": 4, - "product_family_name": "Billing Plans", - "created_at": "2017-11-08T10:01:15-05:00", - "updated_at": "2017-11-08T10:01:15-05:00", - "start_date": "2017-11-08T10:01:15-05:00", - "end_date": null, - "percentage": "33.3333", - "duration_period_count": null, - "duration_interval": null, - "duration_interval_unit": null, - "allow_negative_balance": false, - "archived_at": null, - "conversion_limit": null, - "stackable": true, - "compounding_strategy": "compound" - } -} +result = coupons_controller.create_or_update_coupon_currency_prices( + coupon_id, + body=body +) ``` -# Update Coupon +# Create Coupon Subcodes -## Update Coupon +## Coupon Subcodes Intro -You can update a Coupon via the API with a PUT request to the resource endpoint. +Coupon Subcodes allow you to create a set of unique codes that allow you to expand the use of one coupon. -You can restrict a coupon to only apply to specific products / components by optionally passing in hashes of `restricted_products` and/or `restricted_components` in the format: -`{ "": boolean_value }` +For example: -```python -def update_coupon(self, - product_family_id, - coupon_id, - body=None) +Master Coupon Code: + ++ SPRING2020 + +Coupon Subcodes: + ++ SPRING90210 ++ DP80302 ++ SPRINGBALTIMORE + +Coupon subcodes can be administered in the Admin Interface or via the API. + +When creating a coupon subcode, you must specify a coupon to attach it to using the coupon_id. Valid coupon subcodes are all capital letters, contain only letters and numbers, and do not have any spaces. Lowercase letters will be capitalized before the subcode is created. + +## Coupon Subcodes Documentation + +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). + +## Create Coupon Subcode + +This request allows you to create specific subcodes underneath an existing coupon code. + +*Note*: If you are using any of the allowed special characters ("%", "@", "+", "-", "_", and "."), you must encode them for use in the URL. + + % to %25 + @ to %40 + + to %2B + - to %2D + _ to %5F + . to %2E + +So, if the coupon subcode is `20%OFF`, the URL to delete this coupon subcode would be: `https://.chargify.com/coupons/567/codes/20%25OFF.` + +```python +def create_coupon_subcodes(self, + coupon_id, + body=None) ``` ## Parameters | 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 | -| `body` | [`CreateOrUpdateCoupon`](../../doc/models/create-or-update-coupon.md) | Body, Optional | - | +| `body` | [`CouponSubcodes`](../../doc/models/coupon-subcodes.md) | Body, Optional | - | ## Response Type -[`CouponResponse`](../../doc/models/coupon-response.md) +[`CouponSubcodesResponse`](../../doc/models/coupon-subcodes-response.md) ## Example Usage ```python -product_family_id = 140 - coupon_id = 162 -body = CreateOrUpdateCoupon( - coupon=CreateOrUpdatePercentageCoupon( - name='15% off', - code='15OFF', - percentage=15, - description='15% off for life', - allow_negative_balance=False, - recurring=False, - end_date=dateutil.parser.parse('2012-08-29T12:00:00-04:00'), - product_family_id='2', - stackable=True, - compounding_strategy=CompoundingStrategy.COMPOUND - ), - restricted_products={ - '1': True - }, - restricted_components={ - '1': True, - '2': False - } +body = CouponSubcodes( + codes=[ + 'BALTIMOREFALL', + 'ORLANDOFALL', + 'DETROITFALL' + ] ) -result = coupons_controller.update_coupon( - product_family_id, +result = coupons_controller.create_coupon_subcodes( coupon_id, body=body ) @@ -413,194 +400,166 @@ result = coupons_controller.update_coupon( ```json { - "coupon": { - "id": 67, - "name": "Foo Bar", - "code": "YEPPER99934", - "description": "my cool coupon", - "amount_in_cents": 10000, - "product_family_id": 4, - "created_at": "2017-11-08T10:01:15-05:00", - "updated_at": "2017-11-08T10:01:15-05:00", - "start_date": "2017-11-08T10:01:15-05:00", - "end_date": null, - "percentage": null, - "recurring": false, - "duration_period_count": null, - "duration_interval": null, - "duration_interval_unit": null, - "allow_negative_balance": false, - "archived_at": null, - "conversion_limit": null, - "stackable": true, - "compounding_strategy": "compound" - } + "created_codes": [ + "BALTIMOREFALL", + "ORLANDOFALL", + "DETROITFALL" + ] } ``` -# Archive Coupon +# List Coupon Subcodes -You can archive a Coupon via the API with the archive method. -Archiving makes that Coupon unavailable for future use, but allows it to remain attached and functional on existing Subscriptions that are using it. -The `archived_at` date and time will be assigned. +This request allows you to request the subcodes that are attached to a coupon. ```python -def archive_coupon(self, - product_family_id, - coupon_id) +def list_coupon_subcodes(self, + options=dict()) ``` ## Parameters | 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 | +| `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`. | +| `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`. | ## Response Type -[`CouponResponse`](../../doc/models/coupon-response.md) +[`CouponSubcodes`](../../doc/models/coupon-subcodes.md) ## Example Usage ```python -product_family_id = 140 - -coupon_id = 162 - -result = coupons_controller.archive_coupon( - product_family_id, - coupon_id -) +collect = { + 'coupon_id': 162, + 'page': 2, + 'per_page': 50 +} +result = coupons_controller.list_coupon_subcodes(collect) ``` ## Example Response *(as JSON)* ```json { - "coupon": { - "id": 67, - "name": "Foo Bar", - "code": "YEPPER99934", - "description": "my cool coupon", - "amount_in_cents": 10000, - "product_family_id": 4, - "created_at": "2017-11-08T10:01:15-05:00", - "updated_at": "2017-11-08T10:01:15-05:00", - "start_date": "2017-11-08T10:01:15-05:00", - "end_date": null, - "percentage": null, - "recurring": false, - "duration_period_count": null, - "duration_interval": null, - "duration_interval_unit": null, - "allow_negative_balance": false, - "archived_at": "2016-12-02T13:09:33-05:00", - "conversion_limit": null, - "stackable": true, - "compounding_strategy": "compound" - } + "codes": [ + "3JU6PR", + "9RO6MP", + "8OG1VV", + "5FL7VV", + "2SV8XK", + "4LW8LH", + "3VL4GZ", + "9UI9XO", + "0LZ0CC", + "8XI9JV", + "9UV5YE", + "3UI4GX", + "6SL5ST", + "9WC8IJ", + "2KA3PZ", + "7WR1VR", + "3VY7MN", + "6KC3KB", + "7DF7YT", + "9FH1ED" + ] } ``` -# List Coupons +# Delete Coupon Subcode -You can retrieve a list of coupons. +## Example -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. +Given a coupon with an ID of 567, and a coupon subcode of 20OFF, the URL to `DELETE` this coupon subcode would be: + +``` +http://subdomain.chargify.com/coupons/567/codes/20OFF. +``` + +Note: If you are using any of the allowed special characters (“%”, “@”, “+”, “-”, “_”, and “.”), you must encode them for use in the URL. + +| Special character | Encoding | +|-------------------|----------| +| % | %25 | +| @ | %40 | +| + | %2B | +| – | %2D | +| _ | %5F | +| . | %2E | + +## Percent Encoding Example + +Or if the coupon subcode is 20%OFF, the URL to delete this coupon subcode would be: @https://.chargify.com/coupons/567/codes/20%25OFF. ```python -def list_coupons(self, - options=dict()) +def delete_coupon_subcode(self, + coupon_id, + subcode) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `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`. | -| `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request. Default value is 30. The maximum allowed values is 200; any per_page value over 200 will be changed to 200.
Use in query `per_page=200`. | -| `filter` | [`ListCouponsFilter`](../../doc/models/list-coupons-filter.md) | Query, Optional | Filter to use for List Coupons operations | -| `currency_prices` | `bool` | Query, Optional | When fetching coupons, if you have defined multiple currencies at the site level, you can optionally pass the `?currency_prices=true` query param to include an array of currency price data in the response. Use in query `currency_prices=true`. | +| `coupon_id` | `int` | Template, Required | The Advanced Billing id of the coupon to which the subcode belongs | +| `subcode` | `str` | Template, Required | The subcode of the coupon | ## Response Type -[`List[CouponResponse]`](../../doc/models/coupon-response.md) +`void` ## Example Usage ```python -collect = { - 'page': 2, - 'per_page': 50, - 'filter': ListCouponsFilter( - start_date=dateutil.parser.parse('2011-12-17').date(), - end_date=dateutil.parser.parse('2011-12-15').date(), - start_datetime=dateutil.parser.parse('12/19/2011 09:15:30'), - end_datetime=dateutil.parser.parse('06/07/2019 17:20:06'), - ids=[ - 1, - 2, - 3 - ], - codes=[ - 'free', - 'free_trial' - ] - ), - 'currency_prices': True -} -result = coupons_controller.list_coupons(collect) +coupon_id = 162 + +subcode = 'subcode4' + +coupons_controller.delete_coupon_subcode( + coupon_id, + subcode +) ``` -## Example Response *(as JSON)* +## Errors -```json -[ - { - "coupon": { - "id": 0, - "name": "string", - "code": "string", - "description": "string", - "amount": 0, - "amount_in_cents": 0, - "product_family_id": 0, - "product_family_name": "string", - "start_date": "2021-05-03T16:00:21-04:00", - "end_date": "2023-05-05T16:00:21-04:00", - "percentage": "10", - "recurring": true, - "recurring_scheme": "do_not_recur", - "duration_period_count": 0, - "duration_interval": 0, - "duration_interval_unit": "string", - "duration_interval_span": "string", - "allow_negative_balance": true, - "archived_at": null, - "conversion_limit": "string", - "stackable": true, - "compounding_strategy": "compound", - "use_site_exchange_rate": true, - "created_at": "2021-05-05T16:00:21-04:00", - "updated_at": "2021-05-05T16:00:21-04:00", - "discount_type": "amount", - "exclude_mid_period_allocations": true, - "apply_on_cancel_at_end_of_period": true, - "coupon_restrictions": [ - { - "id": 0, - "item_type": "Component", - "item_id": 0, - "name": "string", - "handle": "string" - } - ] - } - } -] +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | + + +# Find Coupon + +You can search for a coupon via the API with the find method. By passing a code parameter, the find will attempt to locate a coupon that matches that code. If no coupon is found, a 404 is returned. + +If you have more than one product family and if the coupon you are trying to find does not belong to the default product family in your site, then you will need to specify (either in the url or as a query string param) the product family id. + +```python +def find_coupon(self, + product_family_id=None, + code=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `product_family_id` | `int` | Query, Optional | The Advanced Billing id of the product family to which the coupon belongs | +| `code` | `str` | Query, Optional | The code of the coupon | + +## Response Type + +[`CouponResponse`](../../doc/models/coupon-response.md) + +## Example Usage + +```python +result = coupons_controller.find_coupon() ``` @@ -758,16 +717,24 @@ result = coupons_controller.validate_coupon(code) | 404 | Not Found | [`SingleStringErrorResponseException`](../../doc/models/single-string-error-response-exception.md) | -# Create or Update Coupon Currency Prices +# Update Coupon Subcodes -This endpoint allows you to create and/or update currency prices for an existing coupon. Multiple prices can be created or updated in a single request but each of the currencies must be defined on the site level already and the coupon must be an amount-based coupon, not percentage. +You can update the subcodes for the given Coupon via the API with a PUT request to the resource endpoint. +Send an array of new coupon subcodes. -Currency pricing for coupons must mirror the setup of the primary coupon pricing - if the primary coupon is percentage based, you will not be able to define pricing in non-primary currencies. +**Note**: All current subcodes for that Coupon will be deleted first, and replaced with the list of subcodes sent to this endpoint. +The response will contain: + ++ The created subcodes, + ++ Subcodes that were not created because they already exist, + ++ Any subcodes not created because they are invalid. ```python -def create_or_update_coupon_currency_prices(self, - coupon_id, - body=None) +def update_coupon_subcodes(self, + coupon_id, + body=None) ``` ## Parameters @@ -775,300 +742,333 @@ def create_or_update_coupon_currency_prices(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `coupon_id` | `int` | Template, Required | The Advanced Billing id of the coupon | -| `body` | [`CouponCurrencyRequest`](../../doc/models/coupon-currency-request.md) | Body, Optional | - | +| `body` | [`CouponSubcodes`](../../doc/models/coupon-subcodes.md) | Body, Optional | - | ## Response Type -[`CouponCurrencyResponse`](../../doc/models/coupon-currency-response.md) +[`CouponSubcodesResponse`](../../doc/models/coupon-subcodes-response.md) ## Example Usage ```python coupon_id = 162 -body = CouponCurrencyRequest( - currency_prices=[ - UpdateCouponCurrency( - currency='EUR', - price=10 - ), - UpdateCouponCurrency( - currency='GBP', - price=9 - ) +body = CouponSubcodes( + codes=[ + 'AAAA', + 'BBBB', + 'CCCC' ] ) -result = coupons_controller.create_or_update_coupon_currency_prices( +result = coupons_controller.update_coupon_subcodes( coupon_id, body=body ) ``` -# Create Coupon Subcodes - -## Coupon Subcodes Intro - -Coupon Subcodes allow you to create a set of unique codes that allow you to expand the use of one coupon. - -For example: - -Master Coupon Code: - -+ SPRING2020 - -Coupon Subcodes: - -+ SPRING90210 -+ DP80302 -+ SPRINGBALTIMORE - -Coupon subcodes can be administered in the Admin Interface or via the API. - -When creating a coupon subcode, you must specify a coupon to attach it to using the coupon_id. Valid coupon subcodes are all capital letters, contain only letters and numbers, and do not have any spaces. Lowercase letters will be capitalized before the subcode is created. - -## Coupon Subcodes Documentation +# Create Coupon -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). +## Coupons Documentation -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). +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. -## Create Coupon Subcode +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). -This request allows you to create specific subcodes underneath an existing coupon code. +## Create Coupon -*Note*: If you are using any of the allowed special characters ("%", "@", "+", "-", "_", and "."), you must encode them for use in the URL. +This request will create a coupon, based on the provided information. - % to %25 - @ to %40 - + to %2B - - to %2D - _ to %5F - . to %2E +When creating a coupon, you must specify a product family using the `product_family_id`. If no `product_family_id` is passed, the first product family available is used. You will also need to formulate your URL to cite the Product Family ID in your request. -So, if the coupon subcode is `20%OFF`, the URL to delete this coupon subcode would be: `https://.chargify.com/coupons/567/codes/20%25OFF.` +You can restrict a coupon to only apply to specific products / components by optionally passing in hashes of `restricted_products` and/or `restricted_components` in the format: +`{ "": boolean_value }` ```python -def create_coupon_subcodes(self, - coupon_id, - body=None) +def create_coupon(self, + product_family_id, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `coupon_id` | `int` | Template, Required | The Advanced Billing id of the coupon | -| `body` | [`CouponSubcodes`](../../doc/models/coupon-subcodes.md) | Body, Optional | - | +| `product_family_id` | `int` | Template, Required | The Advanced Billing id of the product family to which the coupon belongs | +| `body` | [`CreateOrUpdateCoupon`](../../doc/models/create-or-update-coupon.md) | Body, Optional | - | ## Response Type -[`CouponSubcodesResponse`](../../doc/models/coupon-subcodes-response.md) +[`CouponResponse`](../../doc/models/coupon-response.md) ## Example Usage ```python -coupon_id = 162 +product_family_id = 140 -body = CouponSubcodes( - codes=[ - 'BALTIMOREFALL', - 'ORLANDOFALL', - 'DETROITFALL' - ] +body = CreateOrUpdateCoupon( + coupon=CreateOrUpdatePercentageCoupon( + name='15% off', + code='15OFF', + percentage=15, + description='15% off for life', + allow_negative_balance=False, + recurring=False, + end_date=dateutil.parser.parse('2012-08-29T12:00:00-04:00'), + product_family_id='2', + stackable=True, + compounding_strategy=CompoundingStrategy.COMPOUND, + exclude_mid_period_allocations=True, + apply_on_cancel_at_end_of_period=True + ), + restricted_products={ + '1': True + }, + restricted_components={ + '1': True, + '2': False + } ) -result = coupons_controller.create_coupon_subcodes( - coupon_id, +result = coupons_controller.create_coupon( + product_family_id, body=body ) ``` -## Example Response *(as JSON)* +## Errors -```json -{ - "created_codes": [ - "BALTIMOREFALL", - "ORLANDOFALL", - "DETROITFALL" - ] -} -``` +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# List Coupon Subcodes +# Read Coupon -This request allows you to request the subcodes that are attached to a coupon. +You can retrieve the Coupon via the API with the Show method. You must identify the Coupon in this call by the ID parameter that Advanced Billing assigns. +If instead you would like to find a Coupon using a Coupon code, see the Coupon Find method. + +When fetching a coupon, if you have defined multiple currencies at the site level, you can optionally pass the `?currency_prices=true` query param to include an array of currency price data in the response. + +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_coupon_subcodes(self, - options=dict()) +def read_coupon(self, + product_family_id, + coupon_id) ``` ## Parameters | 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 | -| `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`. | -| `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`. | ## Response Type -[`CouponSubcodes`](../../doc/models/coupon-subcodes.md) +[`CouponResponse`](../../doc/models/coupon-response.md) ## Example Usage ```python -collect = { - 'coupon_id': 162, - 'page': 2, - 'per_page': 50 -} -result = coupons_controller.list_coupon_subcodes(collect) +product_family_id = 140 + +coupon_id = 162 + +result = coupons_controller.read_coupon( + product_family_id, + coupon_id +) ``` ## Example Response *(as JSON)* ```json { - "codes": [ - "3JU6PR", - "9RO6MP", - "8OG1VV", - "5FL7VV", - "2SV8XK", - "4LW8LH", - "3VL4GZ", - "9UI9XO", - "0LZ0CC", - "8XI9JV", - "9UV5YE", - "3UI4GX", - "6SL5ST", - "9WC8IJ", - "2KA3PZ", - "7WR1VR", - "3VY7MN", - "6KC3KB", - "7DF7YT", - "9FH1ED" - ] + "coupon": { + "id": 67, + "name": "Foo Bar", + "code": "YEPPER99934", + "description": "my cool coupon", + "amount_in_cents": null, + "product_family_id": 4, + "product_family_name": "Billing Plans", + "created_at": "2017-11-08T10:01:15-05:00", + "updated_at": "2017-11-08T10:01:15-05:00", + "start_date": "2017-11-08T10:01:15-05:00", + "end_date": null, + "percentage": "33.3333", + "duration_period_count": null, + "duration_interval": null, + "duration_interval_unit": null, + "allow_negative_balance": false, + "archived_at": null, + "conversion_limit": null, + "stackable": true, + "compounding_strategy": "compound" + } } ``` -# Update Coupon Subcodes - -You can update the subcodes for the given Coupon via the API with a PUT request to the resource endpoint. -Send an array of new coupon subcodes. - -**Note**: All current subcodes for that Coupon will be deleted first, and replaced with the list of subcodes sent to this endpoint. -The response will contain: +# Update Coupon -+ The created subcodes, +## Update Coupon -+ Subcodes that were not created because they already exist, +You can update a Coupon via the API with a PUT request to the resource endpoint. -+ Any subcodes not created because they are invalid. +You can restrict a coupon to only apply to specific products / components by optionally passing in hashes of `restricted_products` and/or `restricted_components` in the format: +`{ "": boolean_value }` ```python -def update_coupon_subcodes(self, - coupon_id, - body=None) +def update_coupon(self, + product_family_id, + coupon_id, + body=None) ``` ## Parameters | 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 | -| `body` | [`CouponSubcodes`](../../doc/models/coupon-subcodes.md) | Body, Optional | - | +| `body` | [`CreateOrUpdateCoupon`](../../doc/models/create-or-update-coupon.md) | Body, Optional | - | ## Response Type -[`CouponSubcodesResponse`](../../doc/models/coupon-subcodes-response.md) +[`CouponResponse`](../../doc/models/coupon-response.md) ## Example Usage ```python +product_family_id = 140 + coupon_id = 162 -body = CouponSubcodes( - codes=[ - 'AAAA', - 'BBBB', - 'CCCC' - ] +body = CreateOrUpdateCoupon( + coupon=CreateOrUpdatePercentageCoupon( + name='15% off', + code='15OFF', + percentage=15, + description='15% off for life', + allow_negative_balance=False, + recurring=False, + end_date=dateutil.parser.parse('2012-08-29T12:00:00-04:00'), + product_family_id='2', + stackable=True, + compounding_strategy=CompoundingStrategy.COMPOUND + ), + restricted_products={ + '1': True + }, + restricted_components={ + '1': True, + '2': False + } ) -result = coupons_controller.update_coupon_subcodes( +result = coupons_controller.update_coupon( + product_family_id, coupon_id, body=body ) ``` +## Example Response *(as JSON)* -# Delete Coupon Subcode - -## Example - -Given a coupon with an ID of 567, and a coupon subcode of 20OFF, the URL to `DELETE` this coupon subcode would be: - -``` -http://subdomain.chargify.com/coupons/567/codes/20OFF. +```json +{ + "coupon": { + "id": 67, + "name": "Foo Bar", + "code": "YEPPER99934", + "description": "my cool coupon", + "amount_in_cents": 10000, + "product_family_id": 4, + "created_at": "2017-11-08T10:01:15-05:00", + "updated_at": "2017-11-08T10:01:15-05:00", + "start_date": "2017-11-08T10:01:15-05:00", + "end_date": null, + "percentage": null, + "recurring": false, + "duration_period_count": null, + "duration_interval": null, + "duration_interval_unit": null, + "allow_negative_balance": false, + "archived_at": null, + "conversion_limit": null, + "stackable": true, + "compounding_strategy": "compound" + } +} ``` -Note: If you are using any of the allowed special characters (“%”, “@”, “+”, “-”, “_”, and “.”), you must encode them for use in the URL. - -| Special character | Encoding | -|-------------------|----------| -| % | %25 | -| @ | %40 | -| + | %2B | -| – | %2D | -| _ | %5F | -| . | %2E | -## Percent Encoding Example +# Archive Coupon -Or if the coupon subcode is 20%OFF, the URL to delete this coupon subcode would be: @https://.chargify.com/coupons/567/codes/20%25OFF. +You can archive a Coupon via the API with the archive method. +Archiving makes that Coupon unavailable for future use, but allows it to remain attached and functional on existing Subscriptions that are using it. +The `archived_at` date and time will be assigned. ```python -def delete_coupon_subcode(self, - coupon_id, - subcode) +def archive_coupon(self, + product_family_id, + coupon_id) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `coupon_id` | `int` | Template, Required | The Advanced Billing id of the coupon to which the subcode belongs | -| `subcode` | `str` | Template, Required | The subcode 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 -`void` +[`CouponResponse`](../../doc/models/coupon-response.md) ## Example Usage ```python -coupon_id = 162 +product_family_id = 140 -subcode = 'subcode4' +coupon_id = 162 -coupons_controller.delete_coupon_subcode( - coupon_id, - subcode +result = coupons_controller.archive_coupon( + product_family_id, + coupon_id ) ``` -## Errors +## Example Response *(as JSON)* -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | +```json +{ + "coupon": { + "id": 67, + "name": "Foo Bar", + "code": "YEPPER99934", + "description": "my cool coupon", + "amount_in_cents": 10000, + "product_family_id": 4, + "created_at": "2017-11-08T10:01:15-05:00", + "updated_at": "2017-11-08T10:01:15-05:00", + "start_date": "2017-11-08T10:01:15-05:00", + "end_date": null, + "percentage": null, + "recurring": false, + "duration_period_count": null, + "duration_interval": null, + "duration_interval_unit": null, + "allow_negative_balance": false, + "archived_at": "2016-12-02T13:09:33-05:00", + "conversion_limit": null, + "stackable": true, + "compounding_strategy": "compound" + } +} +``` diff --git a/doc/controllers/custom-fields.md b/doc/controllers/custom-fields.md index 19091817..777958c4 100644 --- a/doc/controllers/custom-fields.md +++ b/doc/controllers/custom-fields.md @@ -10,48 +10,83 @@ custom_fields_controller = client.custom_fields ## Methods -* [Create Metafields](../../doc/controllers/custom-fields.md#create-metafields) -* [List Metafields](../../doc/controllers/custom-fields.md#list-metafields) * [Update Metafield](../../doc/controllers/custom-fields.md#update-metafield) -* [Delete Metafield](../../doc/controllers/custom-fields.md#delete-metafield) * [Create Metadata](../../doc/controllers/custom-fields.md#create-metadata) -* [List Metadata](../../doc/controllers/custom-fields.md#list-metadata) -* [Update Metadata](../../doc/controllers/custom-fields.md#update-metadata) * [Delete Metadata](../../doc/controllers/custom-fields.md#delete-metadata) +* [Delete Metafield](../../doc/controllers/custom-fields.md#delete-metafield) +* [Update Metadata](../../doc/controllers/custom-fields.md#update-metadata) +* [List Metafields](../../doc/controllers/custom-fields.md#list-metafields) +* [Create Metafields](../../doc/controllers/custom-fields.md#create-metafields) +* [List Metadata](../../doc/controllers/custom-fields.md#list-metadata) * [List Metadata for Resource Type](../../doc/controllers/custom-fields.md#list-metadata-for-resource-type) -# Create Metafields +# Update Metafield -## Custom Fields: Metafield Intro +Use the following method to update metafields for your Site. Metafields can be populated with metadata after the fact. + +```python +def update_metafield(self, + resource_type, + body=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `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 + +[`List[Metafield]`](../../doc/models/metafield.md) + +## Example Usage + +```python +resource_type = ResourceType.SUBSCRIPTIONS + +result = custom_fields_controller.update_metafield(resource_type) +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | + + +# Create Metadata + +## 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/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). - -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. +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) -## Create Metafields +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**. -Use this endpoint to create metafields for your Site. Metafields can be populated with metadata after the fact. +## Metadata limits -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. +Metadata values are limited to 2kB in size. Additonally, there are limits on the number of unique metafields available per resource. -### Metafields "On-the-Fly" +## Create Metadata -It is possible to create Metafields “on the fly” when you create your Metadata – if a non-existant 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”. +This method will create a metafield for the site on the fly if it does not already exist, and populate the metadata value. -### Metafield Scope Warning +### Subscription or Customer Resource -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**. +Please pay special attention to the resource you use when creating metadata. ```python -def create_metafields(self, - resource_type, - body=None) +def create_metadata(self, + resource_type, + resource_id, + body=None) ``` ## Parameters @@ -59,69 +94,40 @@ 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 | -| `body` | [`CreateMetafieldsRequest`](../../doc/models/create-metafields-request.md) | Body, Optional | - | +| `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 | - | ## Response Type -[`List[Metafield]`](../../doc/models/metafield.md) +[`List[Metadata]`](../../doc/models/metadata.md) ## Example Usage ```python resource_type = ResourceType.SUBSCRIPTIONS -body = CreateMetafieldsRequest( - metafields=CreateMetafield( - name='Dropdown field', - scope=MetafieldScope( - public_show=IncludeOption.INCLUDE, - public_edit=IncludeOption.INCLUDE +resource_id = 60 + +body = CreateMetadataRequest( + metadata=[ + CreateMetadata( + name='Color', + value='Blue' ), - input_type=MetafieldInput.DROPDOWN, - enum=[ - 'option 1', - 'option 2' - ] - ) + CreateMetadata( + name='Something', + value='Useful' + ) + ] ) -result = custom_fields_controller.create_metafields( +result = custom_fields_controller.create_metadata( resource_type, + resource_id, body=body ) ``` -## Example Response *(as JSON)* - -```json -[ - { - "name": "Color", - "scope": { - "csv": "0", - "statements": "0", - "invoices": "0", - "portal": "0" - }, - "data_count": 0, - "input_type": "text", - "enum": null - }, - { - "name": "Brand", - "scope": { - "csv": "0", - "statements": "0", - "invoices": "0", - "portal": "0" - }, - "data_count": 0, - "input_type": "text", - "enum": null - } -] -``` - ## Errors | HTTP Status Code | Error Description | Exception Class | @@ -129,77 +135,38 @@ result = custom_fields_controller.create_metafields( | 422 | Unprocessable Entity (WebDAV) | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | -# List Metafields - -This endpoint lists metafields associated with a site. The metafield description and usage is contained in the response. - -```python -def list_metafields(self, - options=dict()) -``` - -## Parameters - -| 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 | -| `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`. | -| `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`. | -| `direction` | [`SortingDirection`](../../doc/models/sorting-direction.md) | Query, Optional | Controls the order in which results are returned.
Use in query `direction=asc`. | +# Delete Metadata -## Response Type +This method removes the metadata from the subscriber/customer cited. -[`ListMetafieldsResponse`](../../doc/models/list-metafields-response.md) +## Query String Usage -## Example Usage +For instance if you wanted to delete the metadata for customer 99 named weight you would request: -```python -collect = { - 'resource_type': ResourceType.SUBSCRIPTIONS, - 'page': 2, - 'per_page': 50 -} -result = custom_fields_controller.list_metafields(collect) +``` +https://acme.chargify.com/customers/99/metadata.json?name=weight ``` -## Example Response *(as JSON)* +If you want to delete multiple metadata fields for a customer 99 named: `weight` and `age` you wrould request: -```json -{ - "total_count": 0, - "current_page": 0, - "total_pages": 0, - "per_page": 0, - "metafields": [ - { - "id": 0, - "name": "string", - "scope": { - "csv": "0", - "statements": "0", - "invoices": "0", - "portal": "0", - "public_show": "0", - "public_edit": "0" - }, - "data_count": 0, - "input_type": "text", - "enum": null - } - ] -} +``` +https://acme.chargify.com/customers/99/metadata.json?names[]=weight&names[]=age ``` +## Successful Response -# Update Metafield +For a success, there will be a code `200` and the plain text response `true`. -Use the following method to update metafields for your Site. Metafields can be populated with metadata after the fact. +## Unsuccessful Response + +When a failed response is encountered, you will receive a `404` response and the plain text response of `true`. ```python -def update_metafield(self, - resource_type, - body=None) +def delete_metadata(self, + resource_type, + resource_id, + name=None, + names=None) ``` ## Parameters @@ -207,25 +174,32 @@ 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 | -| `body` | [`UpdateMetafieldsRequest`](../../doc/models/update-metafields-request.md) | Body, Optional | - | +| `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`. | ## Response Type -[`List[Metafield]`](../../doc/models/metafield.md) +`void` ## Example Usage ```python resource_type = ResourceType.SUBSCRIPTIONS -result = custom_fields_controller.update_metafield(resource_type) +resource_id = 60 + +custom_fields_controller.delete_metadata( + resource_type, + resource_id +) ``` ## Errors | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | +| 404 | Not Found | `APIException` | # Delete Metafield @@ -266,33 +240,12 @@ custom_fields_controller.delete_metafield(resource_type) | 404 | Not Found | `APIException` | -# Create Metadata - -## 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-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 +# Update Metadata -Please pay special attention to the resource you use when creating metadata. +This method allows you to update the existing metadata associated with a subscription or customer. ```python -def create_metadata(self, +def update_metadata(self, resource_type, resource_id, body=None) @@ -304,7 +257,7 @@ def create_metadata(self, | --- | --- | --- | --- | | `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 | - | +| `body` | [`UpdateMetadataRequest`](../../doc/models/update-metadata-request.md) | Body, Optional | - | ## Response Type @@ -317,23 +270,9 @@ resource_type = ResourceType.SUBSCRIPTIONS resource_id = 60 -body = CreateMetadataRequest( - metadata=[ - CreateMetadata( - name='Color', - value='Blue' - ), - CreateMetadata( - name='Something', - value='Useful' - ) - ] -) - -result = custom_fields_controller.create_metadata( +result = custom_fields_controller.update_metadata( resource_type, - resource_id, - body=body + resource_id ) ``` @@ -344,17 +283,13 @@ result = custom_fields_controller.create_metadata( | 422 | Unprocessable Entity (WebDAV) | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | -# List Metadata - -This request will list all of the metadata belonging to a particular resource (ie. subscription, customer) that is specified. - -## Metadata Data +# List Metafields -This endpoint will also display the current stats of your metadata to use as a tool for pagination. +This endpoint lists metafields associated with a site. The metafield description and usage is contained in the response. ```python -def list_metadata(self, - options=dict()) +def list_metafields(self, + options=dict()) ``` ## Parameters @@ -362,36 +297,86 @@ 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_id` | `int` | Template, Required | The Advanced Billing id of the customer or the subscription for which the metadata applies | +| `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`. | | `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`. | +| `direction` | [`SortingDirection`](../../doc/models/sorting-direction.md) | Query, Optional | Controls the order in which results are returned.
Use in query `direction=asc`. | ## Response Type -[`PaginatedMetadata`](../../doc/models/paginated-metadata.md) +[`ListMetafieldsResponse`](../../doc/models/list-metafields-response.md) ## Example Usage ```python collect = { 'resource_type': ResourceType.SUBSCRIPTIONS, - 'resource_id': 60, 'page': 2, 'per_page': 50 } -result = custom_fields_controller.list_metadata(collect) +result = custom_fields_controller.list_metafields(collect) ``` +## Example Response *(as JSON)* -# Update Metadata +```json +{ + "total_count": 0, + "current_page": 0, + "total_pages": 0, + "per_page": 0, + "metafields": [ + { + "id": 0, + "name": "string", + "scope": { + "csv": "0", + "statements": "0", + "invoices": "0", + "portal": "0", + "public_show": "0", + "public_edit": "0" + }, + "data_count": 0, + "input_type": "text", + "enum": null + } + ] +} +``` -This method allows you to update the existing metadata associated with a subscription or customer. + +# Create Metafields + +## 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-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). + +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-existant 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**. ```python -def update_metadata(self, - resource_type, - resource_id, - body=None) +def create_metafields(self, + resource_type, + body=None) ``` ## Parameters @@ -399,26 +384,69 @@ 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_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 | - | +| `body` | [`CreateMetafieldsRequest`](../../doc/models/create-metafields-request.md) | Body, Optional | - | ## Response Type -[`List[Metadata]`](../../doc/models/metadata.md) +[`List[Metafield]`](../../doc/models/metafield.md) ## Example Usage ```python resource_type = ResourceType.SUBSCRIPTIONS -resource_id = 60 +body = CreateMetafieldsRequest( + metafields=CreateMetafield( + name='Dropdown field', + scope=MetafieldScope( + public_show=IncludeOption.INCLUDE, + public_edit=IncludeOption.INCLUDE + ), + input_type=MetafieldInput.DROPDOWN, + enum=[ + 'option 1', + 'option 2' + ] + ) +) -result = custom_fields_controller.update_metadata( +result = custom_fields_controller.create_metafields( resource_type, - resource_id + body=body ) ``` +## Example Response *(as JSON)* + +```json +[ + { + "name": "Color", + "scope": { + "csv": "0", + "statements": "0", + "invoices": "0", + "portal": "0" + }, + "data_count": 0, + "input_type": "text", + "enum": null + }, + { + "name": "Brand", + "scope": { + "csv": "0", + "statements": "0", + "invoices": "0", + "portal": "0" + }, + "data_count": 0, + "input_type": "text", + "enum": null + } +] +``` + ## Errors | HTTP Status Code | Error Description | Exception Class | @@ -426,38 +454,17 @@ result = custom_fields_controller.update_metadata( | 422 | Unprocessable Entity (WebDAV) | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | -# 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 +# List Metadata -For a success, there will be a code `200` and the plain text response `true`. +This request will list all of the metadata belonging to a particular resource (ie. subscription, customer) that is specified. -## Unsuccessful Response +## Metadata Data -When a failed response is encountered, you will receive a `404` response and the plain text response of `true`. +This endpoint will also display the current stats of your metadata to use as a tool for pagination. ```python -def delete_metadata(self, - resource_type, - resource_id, - name=None, - names=None) +def list_metadata(self, + options=dict()) ``` ## Parameters @@ -466,32 +473,25 @@ def delete_metadata(self, | --- | --- | --- | --- | | `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`. | +| `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`. | +| `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`. | ## Response Type -`void` +[`PaginatedMetadata`](../../doc/models/paginated-metadata.md) ## Example Usage ```python -resource_type = ResourceType.SUBSCRIPTIONS - -resource_id = 60 - -custom_fields_controller.delete_metadata( - resource_type, - resource_id -) +collect = { + 'resource_type': ResourceType.SUBSCRIPTIONS, + 'resource_id': 60, + 'page': 2, + 'per_page': 50 +} +result = custom_fields_controller.list_metadata(collect) ``` -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | - # List Metadata for Resource Type diff --git a/doc/controllers/customers.md b/doc/controllers/customers.md index b691d803..b0188f09 100644 --- a/doc/controllers/customers.md +++ b/doc/controllers/customers.md @@ -14,8 +14,8 @@ customers_controller = client.customers * [List Customers](../../doc/controllers/customers.md#list-customers) * [Read Customer](../../doc/controllers/customers.md#read-customer) * [Update Customer](../../doc/controllers/customers.md#update-customer) -* [Delete Customer](../../doc/controllers/customers.md#delete-customer) * [Read Customer by Reference](../../doc/controllers/customers.md#read-customer-by-reference) +* [Delete Customer](../../doc/controllers/customers.md#delete-customer) * [List Customer Subscriptions](../../doc/controllers/customers.md#list-customer-subscriptions) @@ -374,59 +374,59 @@ result = customers_controller.update_customer( | 422 | Unprocessable Entity (WebDAV) | [`CustomerErrorResponseException`](../../doc/models/customer-error-response-exception.md) | -# Delete Customer +# Read Customer by Reference -This method allows you to delete the Customer. +Use this method to return the customer object if you have the unique **Reference ID (Your App)** value handy. It will return a single match. ```python -def delete_customer(self, - id) +def read_customer_by_reference(self, + reference) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `id` | `int` | Template, Required | The Advanced Billing id of the customer | +| `reference` | `str` | Query, Required | Customer reference | ## Response Type -`void` +[`CustomerResponse`](../../doc/models/customer-response.md) ## Example Usage ```python -id = 112 +reference = 'reference4' -customers_controller.delete_customer(id) +result = customers_controller.read_customer_by_reference(reference) ``` -# Read Customer by Reference +# Delete Customer -Use this method to return the customer object if you have the unique **Reference ID (Your App)** value handy. It will return a single match. +This method allows you to delete the Customer. ```python -def read_customer_by_reference(self, - reference) +def delete_customer(self, + id) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `reference` | `str` | Query, Required | Customer reference | +| `id` | `int` | Template, Required | The Advanced Billing id of the customer | ## Response Type -[`CustomerResponse`](../../doc/models/customer-response.md) +`void` ## Example Usage ```python -reference = 'reference4' +id = 112 -result = customers_controller.read_customer_by_reference(reference) +customers_controller.delete_customer(id) ``` diff --git a/doc/controllers/events-based-billing-segments.md b/doc/controllers/events-based-billing-segments.md index 61626c86..7ef2eeb4 100644 --- a/doc/controllers/events-based-billing-segments.md +++ b/doc/controllers/events-based-billing-segments.md @@ -11,10 +11,10 @@ events_based_billing_segments_controller = client.events_based_billing_segments ## Methods * [Create Segment](../../doc/controllers/events-based-billing-segments.md#create-segment) -* [List Segments for Price Point](../../doc/controllers/events-based-billing-segments.md#list-segments-for-price-point) * [Update Segment](../../doc/controllers/events-based-billing-segments.md#update-segment) -* [Delete Segment](../../doc/controllers/events-based-billing-segments.md#delete-segment) * [Bulk Create Segments](../../doc/controllers/events-based-billing-segments.md#bulk-create-segments) +* [List Segments for Price Point](../../doc/controllers/events-based-billing-segments.md#list-segments-for-price-point) +* [Delete Segment](../../doc/controllers/events-based-billing-segments.md#delete-segment) * [Bulk Update Segments](../../doc/controllers/events-based-billing-segments.md#bulk-update-segments) @@ -84,56 +84,6 @@ result = events_based_billing_segments_controller.create_segment( | 422 | Unprocessable Entity (WebDAV) | [`EventBasedBillingSegmentErrorsException`](../../doc/models/event-based-billing-segment-errors-exception.md) | -# List Segments for Price Point - -This endpoint allows you to fetch Segments created for a given Price Point. They will be returned in the order of creation. - -You can pass `page` and `per_page` parameters in order to access all of the segments. By default it will return `30` records. You can set `per_page` to `200` at most. - -You may specify component and/or price point by using either the numeric ID or the `handle:gold` syntax. - -```python -def list_segments_for_price_point(self, - options=dict()) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `component_id` | `str` | Template, Required | ID or Handle for the Component | -| `price_point_id` | `str` | Template, Required | ID or Handle for the Price Point belonging to the Component | -| `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`. | -| `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request. Default value is 30. The maximum allowed values is 200; any per_page value over 200 will be changed to 200.
Use in query `per_page=200`. | -| `filter` | [`ListSegmentsFilter`](../../doc/models/list-segments-filter.md) | Query, Optional | Filter to use for List Segments for a Price Point operation | - -## Response Type - -[`ListSegmentsResponse`](../../doc/models/list-segments-response.md) - -## Example Usage - -```python -collect = { - 'component_id': 'component_id8', - 'price_point_id': 'price_point_id8', - 'page': 2, - 'per_page': 50, - 'filter': ListSegmentsFilter( - segment_property_1_value='EU' - ) -} -result = events_based_billing_segments_controller.list_segments_for_price_point(collect) -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`EventBasedBillingListSegmentsErrorsException`](../../doc/models/event-based-billing-list-segments-errors-exception.md) | - - # Update Segment This endpoint updates a single Segment for a Component with a segmented Metric. It allows you to update the pricing for the segment. @@ -185,30 +135,32 @@ result = events_based_billing_segments_controller.update_segment( | 422 | Unprocessable Entity (WebDAV) | [`EventBasedBillingSegmentErrorsException`](../../doc/models/event-based-billing-segment-errors-exception.md) | -# Delete Segment +# Bulk Create Segments -This endpoint allows you to delete a Segment with specified ID. +This endpoint allows you to create multiple segments in one request. The array of segments can contain up to `2000` records. + +If any of the records contain an error the whole request would fail and none of the requested segments get created. The error response contains a message for only the one segment that failed validation, with the corresponding index in the array. You may specify component and/or price point by using either the numeric ID or the `handle:gold` syntax. ```python -def delete_segment(self, - component_id, - price_point_id, - id) +def bulk_create_segments(self, + component_id, + price_point_id, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `component_id` | `str` | Template, Required | ID or Handle of the Component | -| `price_point_id` | `str` | Template, Required | ID or Handle of the Price Point belonging to the Component | -| `id` | `float` | Template, Required | The ID of the Segment | +| `component_id` | `str` | Template, Required | ID or Handle for the Component | +| `price_point_id` | `str` | Template, Required | ID or Handle for the Price Point belonging to the Component | +| `body` | [`BulkCreateSegments`](../../doc/models/bulk-create-segments.md) | Body, Optional | - | ## Response Type -`void` +[`ListSegmentsResponse`](../../doc/models/list-segments-response.md) ## Example Usage @@ -217,12 +169,9 @@ component_id = 'component_id8' price_point_id = 'price_point_id8' -id = 60 - -events_based_billing_segments_controller.delete_segment( +result = events_based_billing_segments_controller.bulk_create_segments( component_id, - price_point_id, - id + price_point_id ) ``` @@ -231,22 +180,20 @@ events_based_billing_segments_controller.delete_segment( | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | | 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`EventBasedBillingSegmentException`](../../doc/models/event-based-billing-segment-exception.md) | -# Bulk Create Segments +# List Segments for Price Point -This endpoint allows you to create multiple segments in one request. The array of segments can contain up to `2000` records. +This endpoint allows you to fetch Segments created for a given Price Point. They will be returned in the order of creation. -If any of the records contain an error the whole request would fail and none of the requested segments get created. The error response contains a message for only the one segment that failed validation, with the corresponding index in the array. +You can pass `page` and `per_page` parameters in order to access all of the segments. By default it will return `30` records. You can set `per_page` to `200` at most. You may specify component and/or price point by using either the numeric ID or the `handle:gold` syntax. ```python -def bulk_create_segments(self, - component_id, - price_point_id, - body=None) +def list_segments_for_price_point(self, + options=dict()) ``` ## Parameters @@ -255,7 +202,9 @@ def bulk_create_segments(self, | --- | --- | --- | --- | | `component_id` | `str` | Template, Required | ID or Handle for the Component | | `price_point_id` | `str` | Template, Required | ID or Handle for the Price Point belonging to the Component | -| `body` | [`BulkCreateSegments`](../../doc/models/bulk-create-segments.md) | Body, Optional | - | +| `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`. | +| `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request. Default value is 30. The maximum allowed values is 200; any per_page value over 200 will be changed to 200.
Use in query `per_page=200`. | +| `filter` | [`ListSegmentsFilter`](../../doc/models/list-segments-filter.md) | Query, Optional | Filter to use for List Segments for a Price Point operation | ## Response Type @@ -263,14 +212,65 @@ def bulk_create_segments(self, ## Example Usage +```python +collect = { + 'component_id': 'component_id8', + 'price_point_id': 'price_point_id8', + 'page': 2, + 'per_page': 50, + 'filter': ListSegmentsFilter( + segment_property_1_value='EU' + ) +} +result = events_based_billing_segments_controller.list_segments_for_price_point(collect) +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`EventBasedBillingListSegmentsErrorsException`](../../doc/models/event-based-billing-list-segments-errors-exception.md) | + + +# Delete Segment + +This endpoint allows you to delete a Segment with specified ID. + +You may specify component and/or price point by using either the numeric ID or the `handle:gold` syntax. + +```python +def delete_segment(self, + component_id, + price_point_id, + id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `component_id` | `str` | Template, Required | ID or Handle of the Component | +| `price_point_id` | `str` | Template, Required | ID or Handle of the Price Point belonging to the Component | +| `id` | `float` | Template, Required | The ID of the Segment | + +## Response Type + +`void` + +## Example Usage + ```python component_id = 'component_id8' price_point_id = 'price_point_id8' -result = events_based_billing_segments_controller.bulk_create_segments( +id = 60 + +events_based_billing_segments_controller.delete_segment( component_id, - price_point_id + price_point_id, + id ) ``` @@ -279,7 +279,7 @@ result = events_based_billing_segments_controller.bulk_create_segments( | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | | 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`EventBasedBillingSegmentException`](../../doc/models/event-based-billing-segment-exception.md) | +| 422 | Unprocessable Entity (WebDAV) | `APIException` | # Bulk Update Segments diff --git a/doc/controllers/events.md b/doc/controllers/events.md index 6420385b..4e8d9373 100644 --- a/doc/controllers/events.md +++ b/doc/controllers/events.md @@ -10,11 +10,98 @@ events_controller = client.events ## Methods -* [List Events](../../doc/controllers/events.md#list-events) * [List Subscription Events](../../doc/controllers/events.md#list-subscription-events) +* [List Events](../../doc/controllers/events.md#list-events) * [Read Events Count](../../doc/controllers/events.md#read-events-count) +# List Subscription Events + +The following request will return a list of events for a subscription. + +Each event type has its own `event_specific_data` specified. + +```python +def list_subscription_events(self, + options=dict()) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `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`. | +| `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`. | +| `since_id` | `long\|int` | Query, Optional | Returns events with an id greater than or equal to the one specified | +| `max_id` | `long\|int` | Query, Optional | Returns events with an id less than or equal to the one specified | +| `direction` | [`Direction`](../../doc/models/direction.md) | Query, Optional | The sort direction of the returned events. | +| `filter` | [`List[EventType]`](../../doc/models/event-type.md) | Query, Optional | You can pass multiple event keys after comma.
Use in query `filter=signup_success,payment_success`. | + +## Response Type + +[`List[EventResponse]`](../../doc/models/event-response.md) + +## Example Usage + +```python +collect = { + 'subscription_id': 222, + 'page': 2, + 'per_page': 50, + 'direction': Direction.DESC, + 'filter': [ + EventType.CUSTOM_FIELD_VALUE_CHANGE, + EventType.PAYMENT_SUCCESS + ] +} +result = events_controller.list_subscription_events(collect) +``` + +## Example Response *(as JSON)* + +```json +[ + { + "event": { + "id": 344799837, + "key": "statement_settled", + "message": "Statement 79702531 settled successfully for Amelia Example's subscription to Basic Plan", + "subscription_id": 14900541, + "customer_id": 77223344, + "created_at": "2016-11-01T12:41:29-04:00", + "event_specific_data": null + } + }, + { + "event": { + "id": 344799815, + "key": "renewal_success", + "message": "Successful renewal for Amelia Example's subscription to Basic Plan", + "subscription_id": 14900541, + "customer_id": 77223344, + "created_at": "2016-11-01T12:41:28-04:00", + "event_specific_data": { + "product_id": 3792003, + "account_transaction_id": 7590246 + } + } + }, + { + "event": { + "id": 344799705, + "key": "billing_date_change", + "message": "Billing date changed on Amelia Example's subscription to Basic Plan from 11/26/2016 to 11/01/2016", + "subscription_id": 14900541, + "customer_id": 77223344, + "created_at": "2016-11-01T12:41:25-04:00", + "event_specific_data": null + } + } +] +``` + + # List Events ## Events Intro @@ -184,93 +271,6 @@ result = events_controller.list_events(collect) ``` -# List Subscription Events - -The following request will return a list of events for a subscription. - -Each event type has its own `event_specific_data` specified. - -```python -def list_subscription_events(self, - options=dict()) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `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`. | -| `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`. | -| `since_id` | `long\|int` | Query, Optional | Returns events with an id greater than or equal to the one specified | -| `max_id` | `long\|int` | Query, Optional | Returns events with an id less than or equal to the one specified | -| `direction` | [`Direction`](../../doc/models/direction.md) | Query, Optional | The sort direction of the returned events. | -| `filter` | [`List[EventType]`](../../doc/models/event-type.md) | Query, Optional | You can pass multiple event keys after comma.
Use in query `filter=signup_success,payment_success`. | - -## Response Type - -[`List[EventResponse]`](../../doc/models/event-response.md) - -## Example Usage - -```python -collect = { - 'subscription_id': 222, - 'page': 2, - 'per_page': 50, - 'direction': Direction.DESC, - 'filter': [ - EventType.CUSTOM_FIELD_VALUE_CHANGE, - EventType.PAYMENT_SUCCESS - ] -} -result = events_controller.list_subscription_events(collect) -``` - -## Example Response *(as JSON)* - -```json -[ - { - "event": { - "id": 344799837, - "key": "statement_settled", - "message": "Statement 79702531 settled successfully for Amelia Example's subscription to Basic Plan", - "subscription_id": 14900541, - "customer_id": 77223344, - "created_at": "2016-11-01T12:41:29-04:00", - "event_specific_data": null - } - }, - { - "event": { - "id": 344799815, - "key": "renewal_success", - "message": "Successful renewal for Amelia Example's subscription to Basic Plan", - "subscription_id": 14900541, - "customer_id": 77223344, - "created_at": "2016-11-01T12:41:28-04:00", - "event_specific_data": { - "product_id": 3792003, - "account_transaction_id": 7590246 - } - } - }, - { - "event": { - "id": 344799705, - "key": "billing_date_change", - "message": "Billing date changed on Amelia Example's subscription to Basic Plan from 11/26/2016 to 11/01/2016", - "subscription_id": 14900541, - "customer_id": 77223344, - "created_at": "2016-11-01T12:41:25-04:00", - "event_specific_data": null - } - } -] -``` - - # Read Events Count Get a count of all the events for a given site by using this method. diff --git a/doc/controllers/insights.md b/doc/controllers/insights.md index 3d5301f5..3f3db665 100644 --- a/doc/controllers/insights.md +++ b/doc/controllers/insights.md @@ -10,106 +10,10 @@ insights_controller = client.insights ## Methods -* [Read Site Stats](../../doc/controllers/insights.md#read-site-stats) -* [Read Mrr](../../doc/controllers/insights.md#read-mrr) * [List Mrr Movements](../../doc/controllers/insights.md#list-mrr-movements) * [List Mrr Per Subscription](../../doc/controllers/insights.md#list-mrr-per-subscription) - - -# Read Site Stats - -The Stats API is a very basic view of some Site-level stats. This API call only answers with JSON responses. An XML version is not provided. - -## Stats Documentation - -There currently is not a complimentary matching set of documentation that compliments this endpoint. However, each Site's dashboard will reflect the summary of information provided in the Stats reposnse. - -``` -https://subdomain.chargify.com/dashboard -``` - -```python -def read_site_stats(self) -``` - -## Response Type - -[`SiteSummary`](../../doc/models/site-summary.md) - -## Example Usage - -```python -result = insights_controller.read_site_stats() -``` - -## Example Response *(as JSON)* - -```json -{ - "seller_name": "Acme, Inc.", - "site_name": "Production", - "site_id": 12345, - "site_currency": "USD", - "stats": { - "total_subscriptions": 120, - "subscriptions_today": 4, - "total_revenue": "$45,978.81", - "revenue_today": "$1,405.12", - "revenue_this_month": "$10,000.00", - "revenue_this_year": "$27,935.24" - } -} -``` - - -# Read Mrr - -**This endpoint is deprecated.** - -This endpoint returns your site's current MRR, including plan and usage breakouts. - -```python -def read_mrr(self, - at_time=None, - subscription_id=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `at_time` | `datetime` | Query, Optional | submit a timestamp in ISO8601 format to request MRR for a historic time | -| `subscription_id` | `int` | Query, Optional | submit the id of a subscription in order to limit results | - -## Response Type - -[`MRRResponse`](../../doc/models/mrr-response.md) - -## Example Usage - -```python -result = insights_controller.read_mrr() -``` - -## Example Response *(as JSON)* - -```json -{ - "mrr": { - "amount_in_cents": 9915593, - "amount_formatted": "$99,155.93", - "currency": "USD", - "currency_symbol": "$", - "at_time": "2021-02-03T14:23:17-05:00", - "breakouts": { - "plan_amount_in_cents": 9913593, - "plan_amount_formatted": "$99,135.93", - "usage_amount_in_cents": 2000, - "usage_amount_formatted": "$20.00" - } - } -} -``` +* [Read Site Stats](../../doc/controllers/insights.md#read-site-stats) +* [Read Mrr](../../doc/controllers/insights.md#read-mrr) # List Mrr Movements @@ -272,3 +176,99 @@ result = insights_controller.list_mrr_per_subscription(collect) | --- | --- | --- | | 400 | Bad Request | [`SubscriptionsMrrErrorResponseException`](../../doc/models/subscriptions-mrr-error-response-exception.md) | + +# Read Site Stats + +The Stats API is a very basic view of some Site-level stats. This API call only answers with JSON responses. An XML version is not provided. + +## Stats Documentation + +There currently is not a complimentary matching set of documentation that compliments this endpoint. However, each Site's dashboard will reflect the summary of information provided in the Stats reposnse. + +``` +https://subdomain.chargify.com/dashboard +``` + +```python +def read_site_stats(self) +``` + +## Response Type + +[`SiteSummary`](../../doc/models/site-summary.md) + +## Example Usage + +```python +result = insights_controller.read_site_stats() +``` + +## Example Response *(as JSON)* + +```json +{ + "seller_name": "Acme, Inc.", + "site_name": "Production", + "site_id": 12345, + "site_currency": "USD", + "stats": { + "total_subscriptions": 120, + "subscriptions_today": 4, + "total_revenue": "$45,978.81", + "revenue_today": "$1,405.12", + "revenue_this_month": "$10,000.00", + "revenue_this_year": "$27,935.24" + } +} +``` + + +# Read Mrr + +**This endpoint is deprecated.** + +This endpoint returns your site's current MRR, including plan and usage breakouts. + +```python +def read_mrr(self, + at_time=None, + subscription_id=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `at_time` | `datetime` | Query, Optional | submit a timestamp in ISO8601 format to request MRR for a historic time | +| `subscription_id` | `int` | Query, Optional | submit the id of a subscription in order to limit results | + +## Response Type + +[`MRRResponse`](../../doc/models/mrr-response.md) + +## Example Usage + +```python +result = insights_controller.read_mrr() +``` + +## Example Response *(as JSON)* + +```json +{ + "mrr": { + "amount_in_cents": 9915593, + "amount_formatted": "$99,155.93", + "currency": "USD", + "currency_symbol": "$", + "at_time": "2021-02-03T14:23:17-05:00", + "breakouts": { + "plan_amount_in_cents": 9913593, + "plan_amount_formatted": "$99,135.93", + "usage_amount_in_cents": 2000, + "usage_amount_formatted": "$20.00" + } + } +} +``` + diff --git a/doc/controllers/invoices.md b/doc/controllers/invoices.md index 2e5b50d2..56fedeb3 100644 --- a/doc/controllers/invoices.md +++ b/doc/controllers/invoices.md @@ -10,39 +10,45 @@ invoices_controller = client.invoices ## Methods -* [Refund Invoice](../../doc/controllers/invoices.md#refund-invoice) -* [List Invoices](../../doc/controllers/invoices.md#list-invoices) * [Read Invoice](../../doc/controllers/invoices.md#read-invoice) +* [List Invoices](../../doc/controllers/invoices.md#list-invoices) * [List Invoice Events](../../doc/controllers/invoices.md#list-invoice-events) -* [Record Payment for Invoice](../../doc/controllers/invoices.md#record-payment-for-invoice) * [Record Payment for Multiple Invoices](../../doc/controllers/invoices.md#record-payment-for-multiple-invoices) * [List Credit Notes](../../doc/controllers/invoices.md#list-credit-notes) -* [Read Credit Note](../../doc/controllers/invoices.md#read-credit-note) -* [Record Payment for Subscription](../../doc/controllers/invoices.md#record-payment-for-subscription) +* [Refund Invoice](../../doc/controllers/invoices.md#refund-invoice) +* [Record Payment for Invoice](../../doc/controllers/invoices.md#record-payment-for-invoice) * [Reopen Invoice](../../doc/controllers/invoices.md#reopen-invoice) -* [Void Invoice](../../doc/controllers/invoices.md#void-invoice) +* [Issue Invoice](../../doc/controllers/invoices.md#issue-invoice) * [List Consolidated Invoice Segments](../../doc/controllers/invoices.md#list-consolidated-invoice-segments) +* [Read Credit Note](../../doc/controllers/invoices.md#read-credit-note) * [Create Invoice](../../doc/controllers/invoices.md#create-invoice) * [Send Invoice](../../doc/controllers/invoices.md#send-invoice) +* [Record Payment for Subscription](../../doc/controllers/invoices.md#record-payment-for-subscription) +* [Void Invoice](../../doc/controllers/invoices.md#void-invoice) * [Preview Customer Information Changes](../../doc/controllers/invoices.md#preview-customer-information-changes) * [Update Customer Information](../../doc/controllers/invoices.md#update-customer-information) -* [Issue Invoice](../../doc/controllers/invoices.md#issue-invoice) -# Refund Invoice +# Read Invoice -Refund an invoice, segment, or consolidated invoice. +Use this endpoint to retrieve the details for an invoice. -## Partial Refund for Consolidated Invoice +## PDF Invoice retrieval -A refund less than the total of a consolidated invoice will be split across its segments. +Individual PDF Invoices can be retrieved by using the "Accept" header application/pdf or appending .pdf as the format portion of the URL: -A $50.00 refund on a $100.00 consolidated invoice with one $60.00 and one $40.00 segment, the refunded amount will be applied as 50% of each ($30.00 and $20.00 respectively). +```curl -u :x -H +Accept:application/pdf -H +https://acme.chargify.com/invoices/inv_8gd8tdhtd3hgr.pdf > output_file.pdf +URL: `https://.chargify.com/invoices/.` +Method: GET +Required parameters: `uid` +Response: A single Invoice. +``` ```python -def refund_invoice(self, - uid, - body=None) +def read_invoice(self, + uid) ``` ## Parameters @@ -50,7 +56,6 @@ def refund_invoice(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `uid` | `str` | Template, Required | The unique identifier for the invoice, this does not refer to the public facing invoice number. | -| `body` | [`RefundInvoiceRequest`](../../doc/models/refund-invoice-request.md) | Body, Optional | - | ## Response Type @@ -61,28 +66,116 @@ def refund_invoice(self, ```python uid = 'uid0' -body = RefundInvoiceRequest( - refund=RefundInvoice( - amount='100.00', - memo='Refund for Basic Plan renewal', - payment_id=12345, - external=False, - apply_credit=False, - void_invoice=True - ) -) - -result = invoices_controller.refund_invoice( - uid, - body=body -) +result = invoices_controller.read_invoice(uid) ``` -## Errors +## Example Response *(as JSON)* -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +```json +{ + "uid": "inv_8gd8tdhtd3hgr", + "site_id": 51288, + "customer_id": 20194505, + "subscription_id": 20597774, + "number": "117", + "sequence_number": 117, + "issue_date": "2018-07-26", + "due_date": "2018-07-26", + "paid_date": "2018-07-26", + "status": "paid", + "collection_method": "automatic", + "payment_instructions": "Make checks payable to Acme, Inc.", + "currency": "USD", + "consolidation_level": "none", + "parent_invoice_uid": null, + "parent_invoice_number": null, + "group_primary_subscription_id": null, + "product_name": "Monthly Product", + "product_family_name": "Billing Plans", + "seller": { + "name": "General Goods", + "address": { + "street": "123 General Goods Way", + "line2": "Apt. 10", + "city": "Boston", + "state": "MA", + "zip": "02120", + "country": "US" + }, + "phone": "555-555-1212" + }, + "customer": { + "chargify_id": 20194505, + "first_name": "Joe", + "last_name": "Example", + "organization": null, + "email": "joe@example.com" + }, + "memo": "Please pay within 15 days.", + "billing_address": { + "street": null, + "line2": null, + "city": null, + "state": null, + "zip": null, + "country": null + }, + "shipping_address": { + "street": null, + "line2": null, + "city": null, + "state": null, + "zip": null, + "country": null + }, + "subtotal_amount": "100.0", + "discount_amount": "0.0", + "tax_amount": "0.0", + "total_amount": "100.0", + "credit_amount": "0.0", + "paid_amount": "100.0", + "refund_amount": "0.0", + "due_amount": "0.0", + "line_items": [ + { + "uid": "li_8gd8tdhhgk55k", + "title": "Monthly Product", + "description": "Jul 26, 2018 - Aug 26, 2018", + "quantity": "1.0", + "unit_price": "100.0", + "subtotal_amount": "100.0", + "discount_amount": "0.0", + "tax_amount": "0.0", + "total_amount": "100.0", + "tiered_unit_price": false, + "period_range_start": "2018-07-26", + "period_range_end": "2018-08-26", + "product_id": 4607632, + "product_version": 1, + "component_id": null, + "price_point_id": null + } + ], + "payments": [ + { + "transaction_time": "2018-07-26T15:22:02Z", + "memo": "Joe Example - Monthly Product: Renewal payment", + "original_amount": "100.0", + "applied_amount": "100.0", + "payment_method": { + "card_brand": "bogus", + "card_expiration": "10/2020", + "last_four": null, + "masked_card_number": "XXXX-XXXX-XXXX-1", + "type": "credit_card" + }, + "transaction_id": 253028955, + "prepayment": false + } + ], + "public_url": "https://www.chargifypay.com/invoice/inv_8jzrw74xq8kxr?token=fb6kpjz5rcr2vttyjs4rcv6y" +} +``` # List Invoices @@ -432,211 +525,62 @@ result = invoices_controller.list_invoices(collect) ``` -# Read Invoice +# List Invoice Events -Use this endpoint to retrieve the details for an invoice. +This endpoint returns a list of invoice events. Each event contains event "data" (such as an applied payment) as well as a snapshot of the `invoice` at the time of event completion. -## PDF Invoice retrieval +Exposed event types are: -Individual PDF Invoices can be retrieved by using the "Accept" header application/pdf or appending .pdf as the format portion of the URL: ++ issue_invoice ++ apply_credit_note ++ apply_payment ++ refund_invoice ++ void_invoice ++ void_remainder ++ backport_invoice ++ change_invoice_status ++ change_invoice_collection_method ++ remove_payment ++ failed_payment ++ apply_debit_note ++ create_debit_note ++ change_chargeback_status -```curl -u :x -H -Accept:application/pdf -H -https://acme.chargify.com/invoices/inv_8gd8tdhtd3hgr.pdf > output_file.pdf -URL: `https://.chargify.com/invoices/.` -Method: GET -Required parameters: `uid` -Response: A single Invoice. -``` +Invoice events are returned in ascending order. + +If both a `since_date` and `since_id` are provided in request parameters, the `since_date` will be used. + +Note - invoice events that occurred prior to 09/05/2018 __will not__ contain an `invoice` snapshot. ```python -def read_invoice(self, - uid) +def list_invoice_events(self, + options=dict()) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `uid` | `str` | Template, Required | The unique identifier for the invoice, this does not refer to the public facing invoice number. | +| `since_date` | `str` | Query, Optional | The timestamp in a format `YYYY-MM-DD T HH:MM:SS Z`, or `YYYY-MM-DD`(in this case, it returns data from the beginning of the day). of the event from which you want to start the search. All the events before the `since_date` timestamp are not returned in the response. | +| `since_id` | `long\|int` | Query, Optional | The ID of the event from which you want to start the search(ID is not included. e.g. if ID is set to 2, then all events with ID 3 and more will be shown) This parameter is not used if since_date is defined. | +| `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`. | +| `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request. Default value is 100. The maximum allowed values is 200; any per_page value over 200 will be changed to 200. | +| `invoice_uid` | `str` | Query, Optional | Providing an invoice_uid allows for scoping of the invoice events to a single invoice or credit note. | +| `with_change_invoice_status` | `str` | Query, Optional | Use this parameter if you want to fetch also invoice events with change_invoice_status type. | +| `event_types` | [`List[InvoiceEventType]`](../../doc/models/invoice-event-type.md) | Query, Optional | Filter results by event_type. Supply a comma separated list of event types (listed above). Use in query: `event_types=void_invoice,void_remainder`. | ## Response Type -[`Invoice`](../../doc/models/invoice.md) +[`ListInvoiceEventsResponse`](../../doc/models/list-invoice-events-response.md) ## Example Usage ```python -uid = 'uid0' - -result = invoices_controller.read_invoice(uid) -``` - -## Example Response *(as JSON)* - -```json -{ - "uid": "inv_8gd8tdhtd3hgr", - "site_id": 51288, - "customer_id": 20194505, - "subscription_id": 20597774, - "number": "117", - "sequence_number": 117, - "issue_date": "2018-07-26", - "due_date": "2018-07-26", - "paid_date": "2018-07-26", - "status": "paid", - "collection_method": "automatic", - "payment_instructions": "Make checks payable to Acme, Inc.", - "currency": "USD", - "consolidation_level": "none", - "parent_invoice_uid": null, - "parent_invoice_number": null, - "group_primary_subscription_id": null, - "product_name": "Monthly Product", - "product_family_name": "Billing Plans", - "seller": { - "name": "General Goods", - "address": { - "street": "123 General Goods Way", - "line2": "Apt. 10", - "city": "Boston", - "state": "MA", - "zip": "02120", - "country": "US" - }, - "phone": "555-555-1212" - }, - "customer": { - "chargify_id": 20194505, - "first_name": "Joe", - "last_name": "Example", - "organization": null, - "email": "joe@example.com" - }, - "memo": "Please pay within 15 days.", - "billing_address": { - "street": null, - "line2": null, - "city": null, - "state": null, - "zip": null, - "country": null - }, - "shipping_address": { - "street": null, - "line2": null, - "city": null, - "state": null, - "zip": null, - "country": null - }, - "subtotal_amount": "100.0", - "discount_amount": "0.0", - "tax_amount": "0.0", - "total_amount": "100.0", - "credit_amount": "0.0", - "paid_amount": "100.0", - "refund_amount": "0.0", - "due_amount": "0.0", - "line_items": [ - { - "uid": "li_8gd8tdhhgk55k", - "title": "Monthly Product", - "description": "Jul 26, 2018 - Aug 26, 2018", - "quantity": "1.0", - "unit_price": "100.0", - "subtotal_amount": "100.0", - "discount_amount": "0.0", - "tax_amount": "0.0", - "total_amount": "100.0", - "tiered_unit_price": false, - "period_range_start": "2018-07-26", - "period_range_end": "2018-08-26", - "product_id": 4607632, - "product_version": 1, - "component_id": null, - "price_point_id": null - } - ], - "payments": [ - { - "transaction_time": "2018-07-26T15:22:02Z", - "memo": "Joe Example - Monthly Product: Renewal payment", - "original_amount": "100.0", - "applied_amount": "100.0", - "payment_method": { - "card_brand": "bogus", - "card_expiration": "10/2020", - "last_four": null, - "masked_card_number": "XXXX-XXXX-XXXX-1", - "type": "credit_card" - }, - "transaction_id": 253028955, - "prepayment": false - } - ], - "public_url": "https://www.chargifypay.com/invoice/inv_8jzrw74xq8kxr?token=fb6kpjz5rcr2vttyjs4rcv6y" -} -``` - - -# List Invoice Events - -This endpoint returns a list of invoice events. Each event contains event "data" (such as an applied payment) as well as a snapshot of the `invoice` at the time of event completion. - -Exposed event types are: - -+ issue_invoice -+ apply_credit_note -+ apply_payment -+ refund_invoice -+ void_invoice -+ void_remainder -+ backport_invoice -+ change_invoice_status -+ change_invoice_collection_method -+ remove_payment -+ failed_payment -+ apply_debit_note -+ create_debit_note -+ change_chargeback_status - -Invoice events are returned in ascending order. - -If both a `since_date` and `since_id` are provided in request parameters, the `since_date` will be used. - -Note - invoice events that occurred prior to 09/05/2018 __will not__ contain an `invoice` snapshot. - -```python -def list_invoice_events(self, - options=dict()) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `since_date` | `str` | Query, Optional | The timestamp in a format `YYYY-MM-DD T HH:MM:SS Z`, or `YYYY-MM-DD`(in this case, it returns data from the beginning of the day). of the event from which you want to start the search. All the events before the `since_date` timestamp are not returned in the response. | -| `since_id` | `long\|int` | Query, Optional | The ID of the event from which you want to start the search(ID is not included. e.g. if ID is set to 2, then all events with ID 3 and more will be shown) This parameter is not used if since_date is defined. | -| `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`. | -| `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request. Default value is 100. The maximum allowed values is 200; any per_page value over 200 will be changed to 200. | -| `invoice_uid` | `str` | Query, Optional | Providing an invoice_uid allows for scoping of the invoice events to a single invoice or credit note. | -| `with_change_invoice_status` | `str` | Query, Optional | Use this parameter if you want to fetch also invoice events with change_invoice_status type. | -| `event_types` | [`List[InvoiceEventType]`](../../doc/models/invoice-event-type.md) | Query, Optional | Filter results by event_type. Supply a comma separated list of event types (listed above). Use in query: `event_types=void_invoice,void_remainder`. | - -## Response Type - -[`ListInvoiceEventsResponse`](../../doc/models/list-invoice-events-response.md) - -## Example Usage - -```python -collect = { - 'page': 2, - 'per_page': 100 -} -result = invoices_controller.list_invoice_events(collect) +collect = { + 'page': 2, + 'per_page': 100 +} +result = invoices_controller.list_invoice_events(collect) ``` ## Example Response *(as JSON)* @@ -1023,98 +967,6 @@ result = invoices_controller.list_invoice_events(collect) ``` -# Record Payment for Invoice - -This API call should be used when you want to record a payment of a given type against a specific invoice. If you would like to apply a payment across multiple invoices, you can use the Bulk Payment endpoint. - -## Create a Payment from the existing payment profile - -In order to apply a payment to an invoice using an existing payment profile, specify `type` as `payment`, the amount less than the invoice total, and the customer's `payment_profile_id`. The ID of a payment profile might be retrieved via the Payment Profiles API endpoint. - -``` -{ - "type": "payment", - "payment": { - "amount": 10.00, - "payment_profile_id": 123 - } -} -``` - -## Create a Payment from the Subscription's Prepayment Account - -In order apply a prepayment to an invoice, specify the `type` as `prepayment`, and also the `amount`. - -``` -{ - "type": "prepayment", - "payment": { - "amount": 10.00 - } -} -``` - -Note that the `amount` must be less than or equal to the Subscription's Prepayment account balance. - -## Create a Payment from the Subscription's Service Credit Account - -In order to apply a service credit to an invoice, specify the `type` as `service_credit`, and also the `amount`: - -``` -{ - "type": "service_credit", - "payment": { - "amount": 10.00 - } -} -``` - -Note that Advanced Billing will attempt to fully pay the invoice's `due_amount` from the Subscription's Service Credit account. At this time, partial payments from a Service Credit Account are only allowed for consolidated invoices (subscription groups). Therefore, for normal invoices the Service Credit account balance must be greater than or equal to the invoice's `due_amount`. - -```python -def record_payment_for_invoice(self, - uid, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `uid` | `str` | Template, Required | The unique identifier for the invoice, this does not refer to the public facing invoice number. | -| `body` | [`CreateInvoicePaymentRequest`](../../doc/models/create-invoice-payment-request.md) | Body, Optional | - | - -## Response Type - -[`Invoice`](../../doc/models/invoice.md) - -## Example Usage - -```python -uid = 'uid0' - -body = CreateInvoicePaymentRequest( - payment=CreateInvoicePayment( - amount=124.33, - memo='for John Smith', - method=InvoicePaymentMethodType.CHECK, - details='#0102' - ) -) - -result = invoices_controller.record_payment_for_invoice( - uid, - body=body -) -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - - # Record Payment for Multiple Invoices This API call should be used when you want to record an external payment against multiple invoices. @@ -1562,417 +1414,152 @@ result = invoices_controller.list_credit_notes(collect) ``` -# Read Credit Note +# Refund Invoice -Use this endpoint to retrieve the details for a credit note. +Refund an invoice, segment, or consolidated invoice. + +## Partial Refund for Consolidated Invoice + +A refund less than the total of a consolidated invoice will be split across its segments. + +A $50.00 refund on a $100.00 consolidated invoice with one $60.00 and one $40.00 segment, the refunded amount will be applied as 50% of each ($30.00 and $20.00 respectively). ```python -def read_credit_note(self, - uid) +def refund_invoice(self, + uid, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `uid` | `str` | Template, Required | The unique identifier of the credit note | +| `uid` | `str` | Template, Required | The unique identifier for the invoice, this does not refer to the public facing invoice number. | +| `body` | [`RefundInvoiceRequest`](../../doc/models/refund-invoice-request.md) | Body, Optional | - | ## Response Type -[`CreditNote`](../../doc/models/credit-note.md) +[`Invoice`](../../doc/models/invoice.md) ## Example Usage ```python uid = 'uid0' -result = invoices_controller.read_credit_note(uid) -``` - -## Example Response *(as JSON)* +body = RefundInvoiceRequest( + refund=RefundInvoice( + amount='100.00', + memo='Refund for Basic Plan renewal', + payment_id=12345, + external=False, + apply_credit=False, + void_invoice=True + ) +) -```json +result = invoices_controller.refund_invoice( + uid, + body=body +) +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + + +# Record Payment for Invoice + +This API call should be used when you want to record a payment of a given type against a specific invoice. If you would like to apply a payment across multiple invoices, you can use the Bulk Payment endpoint. + +## Create a Payment from the existing payment profile + +In order to apply a payment to an invoice using an existing payment profile, specify `type` as `payment`, the amount less than the invoice total, and the customer's `payment_profile_id`. The ID of a payment profile might be retrieved via the Payment Profiles API endpoint. + +``` { - "uid": "cn_8m9vbd5kkv7kr", - "site_id": 20, - "customer_id": 3, - "subscription_id": 2, - "number": "77", - "sequence_number": 78, - "issue_date": "2018-12-31", - "applied_date": "2018-12-31", - "status": "applied", - "currency": "USD", - "memo": "Refund for overpayment", - "seller": { - "name": "Acme, Inc.", - "address": { - "street": "122 E Houston St", - "line2": "Suite 105", - "city": "San Antonio", - "state": "TX", - "zip": "78205", - "country": "US" - }, - "phone": "555-555-1234 x137" - }, - "customer": { - "chargify_id": 3, - "first_name": "Marty", - "last_name": "McFly", - "organization": "Time Travellers, Inc.", - "email": "timetraveller1985@example.com", - "reference": null - }, - "billing_address": { - "street": "200 Billing Rd.", - "line2": "Suite 100", - "city": "Needham", - "state": "MA", - "zip": "02494", - "country": "US" - }, - "shipping_address": { - "street": "100 Shipping St.", - "line2": "Apt 200", - "city": "Pleasantville", - "state": "NC", - "zip": "12345", - "country": "US" - }, - "subtotal_amount": "208.69341779", - "discount_amount": "20.87125167", - "tax_amount": "12.67783387", - "total_amount": "200.5", - "applied_amount": "200.5", - "remaining_amount": "0.0", - "line_items": [ - { - "uid": "cnli_8k5jvdzct4h9x", - "title": "IP Addresses: 5 to 10 addresses", - "description": "38.2% credit", - "quantity": "0.9855", - "unit_price": "2.0", - "subtotal_amount": "1.971004", - "discount_amount": "0.19862831", - "tax_amount": "0.11963536", - "total_amount": "1.89201105", - "tiered_unit_price": false, - "period_range_start": "2018-11-30", - "period_range_end": "2018-11-30", - "product_id": 85, - "product_version": 1, - "component_id": 81, - "price_point_id": 165, - "billing_schedule_item_id": null, - "custom_item": false - }, - { - "uid": "cnli_8kjttvjcjx8b4", - "title": "Professional Plan", - "description": "38.2% credit", - "quantity": "0.382", - "unit_price": "299.0", - "subtotal_amount": "114.21127834", - "discount_amount": "11.42112783", - "tax_amount": "6.93833516", - "total_amount": "109.72848567", - "tiered_unit_price": false, - "period_range_start": "2018-12-30", - "period_range_end": "2018-12-30", - "product_id": 85, - "product_version": 1, - "component_id": null, - "price_point_id": null, - "billing_schedule_item_id": null, - "custom_item": false - }, - { - "uid": "cnli_8kjttvjknzhx7", - "title": "Small Instance (Hourly)", - "description": "38.2% credit", - "quantity": "74.8676", - "unit_price": "0.12244898", - "subtotal_amount": "9.16746047", - "discount_amount": "0.91674605", - "tax_amount": "0.55692322", - "total_amount": "8.80763764", - "tiered_unit_price": true, - "period_range_start": "2018-11-30", - "period_range_end": "2018-11-30", - "product_id": 85, - "product_version": 1, - "component_id": 78, - "price_point_id": null, - "billing_schedule_item_id": null, - "custom_item": false - }, - { - "uid": "cnli_8kjttvjnmh25w", - "title": "Large Instance (Hourly)", - "description": "38.2% credit", - "quantity": "183.3492", - "unit_price": "0.39583333", - "subtotal_amount": "72.57572871", - "discount_amount": "7.25757287", - "tax_amount": "4.40897552", - "total_amount": "69.72713136", - "tiered_unit_price": true, - "period_range_start": "2018-11-30", - "period_range_end": "2018-11-30", - "product_id": 85, - "product_version": 1, - "component_id": 79, - "price_point_id": null, - "billing_schedule_item_id": null, - "custom_item": false - }, - { - "uid": "cnli_8kjttvjqn86kc", - "title": "Email Messages", - "description": "38.2% credit", - "quantity": "10076.9489", - "unit_price": "0.00031045", - "subtotal_amount": "3.12839588", - "discount_amount": "0.31322157", - "tax_amount": "0.19002427", - "total_amount": "3.00519858", - "tiered_unit_price": true, - "period_range_start": "2018-11-30", - "period_range_end": "2018-11-30", - "product_id": 85, - "product_version": 1, - "component_id": 80, - "price_point_id": null, - "billing_schedule_item_id": null, - "custom_item": false - }, - { - "uid": "cnli_8kjttvjtxxbdd", - "title": "IP Addresses", - "description": "38.2% credit", - "quantity": "3.8198", - "unit_price": "2.0", - "subtotal_amount": "7.63955039", - "discount_amount": "0.76395504", - "tax_amount": "0.46410269", - "total_amount": "7.33969804", - "tiered_unit_price": false, - "period_range_start": "2018-12-30", - "period_range_end": "2018-12-30", - "product_id": 85, - "product_version": 1, - "component_id": 81, - "price_point_id": 165, - "billing_schedule_item_id": null, - "custom_item": false - } - ], - "discounts": [ - { - "uid": "cndli_8k5jvdzct4h9y", - "title": "Multi-service discount (10%)", - "code": "MULTI3", - "source_type": "Coupon", - "source_id": 40, - "discount_type": "percentage", - "percentage": "10.0", - "eligible_amount": "208.69341779", - "discount_amount": "20.87125167", - "line_item_breakouts": [ - { - "uid": "cnli_8k5jvdzct4h9x", - "eligible_amount": "1.971004", - "discount_amount": "0.19862831" - }, - { - "uid": "cnli_8kjttvjcjx8b4", - "eligible_amount": "114.21127834", - "discount_amount": "11.42112783" - }, - { - "uid": "cnli_8kjttvjknzhx7", - "eligible_amount": "9.16746047", - "discount_amount": "0.91674605" - }, - { - "uid": "cnli_8kjttvjnmh25w", - "eligible_amount": "72.57572871", - "discount_amount": "7.25757287" - }, - { - "uid": "cnli_8kjttvjqn86kc", - "eligible_amount": "3.12839588", - "discount_amount": "0.31322157" - }, - { - "uid": "cnli_8kjttvjtxxbdd", - "eligible_amount": "7.63955039", - "discount_amount": "0.76395504" - } - ] - } - ], - "taxes": [ - { - "uid": "cntli_8k5jvdzct4h9z", - "title": "NC Sales Tax", - "source_type": "Tax", - "source_id": 1, - "percentage": "6.75", - "taxable_amount": "187.82216613", - "tax_amount": "12.67783387", - "line_item_breakouts": [ - { - "uid": "cnli_8k5jvdzct4h9x", - "taxable_amount": "1.77237569", - "tax_amount": "0.11963536" - }, - { - "uid": "cnli_8kjttvjcjx8b4", - "taxable_amount": "102.7901505", - "tax_amount": "6.93833516" - }, - { - "uid": "cnli_8kjttvjknzhx7", - "taxable_amount": "8.25071442", - "tax_amount": "0.55692322" - }, - { - "uid": "cnli_8kjttvjnmh25w", - "taxable_amount": "65.31815584", - "tax_amount": "4.40897552" - }, - { - "uid": "cnli_8kjttvjqn86kc", - "taxable_amount": "2.81517432", - "tax_amount": "0.19002427" - }, - { - "uid": "cnli_8kjttvjtxxbdd", - "taxable_amount": "6.87559535", - "tax_amount": "0.46410269" - } - ], - "tax_component_breakouts": [ - { - "tax_rule_id": 1, - "percentage": "6.75", - "country_code": "US", - "subdivision_code": "NC", - "tax_amount": "10.66", - "taxable_amount": "157.95", - "tax_exempt_amount": "0.0", - "non_taxable_amount": "0.0", - "tax_name": "NC STATE TAX", - "tax_type": "Sales", - "rate_type": "General", - "tax_authority_type": 45, - "state_assigned_no": "", - "tax_sub_type": "S" - } - ], - "eu_vat": false, - "type": "Sales", - "tax_exempt_amount": "0.0" - } - ], - "applications": [ - { - "uid": "cdt_8m9vbdbdwd28n", - "transaction_time": "2018-12-31T21:19:28Z", - "invoice_uid": "inv_8k5jvdzct4hb2", - "memo": "Refund for overpayment", - "applied_amount": "200.5" - } - ], - "refunds": [ - { - "transaction_id": 329, - "payment_id": 39, - "memo": "Refund for overpayment", - "original_amount": "524.9", - "applied_amount": "200.5" - } - ] + "type": "payment", + "payment": { + "amount": 10.00, + "payment_profile_id": 123 + } } ``` +## Create a Payment from the Subscription's Prepayment Account -# Record Payment for Subscription +In order apply a prepayment to an invoice, specify the `type` as `prepayment`, and also the `amount`. -Record an external payment made against a subscription that will pay partially or in full one or more invoices. +``` +{ + "type": "prepayment", + "payment": { + "amount": 10.00 + } +} +``` -Payment will be applied starting with the oldest open invoice and then next oldest, and so on until the amount of the payment is fully consumed. +Note that the `amount` must be less than or equal to the Subscription's Prepayment account balance. -Excess payment will result in the creation of a prepayment on the Invoice Account. +## Create a Payment from the Subscription's Service Credit Account -Only ungrouped or primary subscriptions may be paid using the "bulk" payment request. +In order to apply a service credit to an invoice, specify the `type` as `service_credit`, and also the `amount`: + +``` +{ + "type": "service_credit", + "payment": { + "amount": 10.00 + } +} +``` + +Note that Advanced Billing will attempt to fully pay the invoice's `due_amount` from the Subscription's Service Credit account. At this time, partial payments from a Service Credit Account are only allowed for consolidated invoices (subscription groups). Therefore, for normal invoices the Service Credit account balance must be greater than or equal to the invoice's `due_amount`. ```python -def record_payment_for_subscription(self, - subscription_id, - body=None) +def record_payment_for_invoice(self, + uid, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `body` | [`RecordPaymentRequest`](../../doc/models/record-payment-request.md) | Body, Optional | - | +| `uid` | `str` | Template, Required | The unique identifier for the invoice, this does not refer to the public facing invoice number. | +| `body` | [`CreateInvoicePaymentRequest`](../../doc/models/create-invoice-payment-request.md) | Body, Optional | - | ## Response Type -[`RecordPaymentResponse`](../../doc/models/record-payment-response.md) +[`Invoice`](../../doc/models/invoice.md) ## Example Usage ```python -subscription_id = 222 +uid = 'uid0' -body = RecordPaymentRequest( - payment=CreatePayment( - amount='10.0', - memo='to pay the bills', - payment_details='check number 8675309', - payment_method=InvoicePaymentMethodType.CHECK +body = CreateInvoicePaymentRequest( + payment=CreateInvoicePayment( + amount=124.33, + memo='for John Smith', + method=InvoicePaymentMethodType.CHECK, + details='#0102' ) ) -result = invoices_controller.record_payment_for_subscription( - subscription_id, +result = invoices_controller.record_payment_for_invoice( + uid, body=body ) ``` -## Example Response *(as JSON)* - -```json -{ - "paid_invoices": [ - { - "invoice_id": "inv_bchyhr6z5grby", - "status": "paid", - "due_amount": "0.0", - "paid_amount": "50.0" - }, - { - "invoice_id": "inv_bchyhrgvyb6vm", - "status": "paid", - "due_amount": "0.0", - "paid_amount": "50.0" - } - ], - "prepayment": null -} -``` - ## Errors | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +| 422 | Unprocessable Entity | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | # Reopen Invoice @@ -2021,14 +1608,24 @@ result = invoices_controller.reopen_invoice(uid) | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Void Invoice +# Issue Invoice -This endpoint allows you to void any invoice with the "open" or "canceled" status. It will also allow voiding of an invoice with the "pending" status if it is not a consolidated invoice. +This endpoint allows you to issue an invoice that is in "pending" status. For example, you can issue an invoice that was created when allocating new quantity on a component and using "accrue charges" option. + +You cannot issue a pending child invoice that was created for a member subscription in a group. + +For Remittance subscriptions, the invoice will go into "open" status and payment won't be attempted. The value for `on_failed_payment` would be rejected if sent. Any prepayments or service credits that exist on subscription will be automatically applied. Additionally, if setting is on, an email will be sent for issued invoice. + +For Automatic subscriptions, prepayments and service credits will apply to the invoice and before payment is attempted. On successful payment, the invoice will go into "paid" status and email will be sent to the customer (if setting applies). When payment fails, the next event depends on the `on_failed_payment` value: + +- `leave_open_invoice` - prepayments and credits applied to invoice; invoice status set to "open"; email sent to the customer for the issued invoice (if setting applies); payment failure recorded in the invoice history. This is the default option. +- `rollback_to_pending` - prepayments and credits not applied; invoice remains in "pending" status; no email sent to the customer; payment failure recorded in the invoice history. +- `initiate_dunning` - prepayments and credits applied to the invoice; invoice status set to "open"; email sent to the customer for the issued invoice (if setting applies); payment failure recorded in the invoice history; subscription will most likely go into "past_due" or "canceled" state (depending upon net terms and dunning settings). ```python -def void_invoice(self, - uid, - body=None) +def issue_invoice(self, + uid, + body=None) ``` ## Parameters @@ -2036,7 +1633,7 @@ def void_invoice(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `uid` | `str` | Template, Required | The unique identifier for the invoice, this does not refer to the public facing invoice number. | -| `body` | [`VoidInvoiceRequest`](../../doc/models/void-invoice-request.md) | Body, Optional | - | +| `body` | [`IssueInvoiceRequest`](../../doc/models/issue-invoice-request.md) | Body, Optional | - | ## Response Type @@ -2047,13 +1644,11 @@ def void_invoice(self, ```python uid = 'uid0' -body = VoidInvoiceRequest( - void=VoidInvoice( - reason='Duplicate invoice' - ) +body = IssueInvoiceRequest( + on_failed_payment=FailedPaymentAction.LEAVE_OPEN_INVOICE ) -result = invoices_controller.void_invoice( +result = invoices_controller.issue_invoice( uid, body=body ) @@ -2107,24 +1702,222 @@ result = invoices_controller.list_consolidated_invoice_segments(collect) { "invoices": [ { - "uid": "inv_8htcd29wcq3q6", + "uid": "inv_8htcd29wcq3q6", + "site_id": 51288, + "customer_id": 20153415, + "subscription_id": 23277588, + "number": "125", + "sequence_number": 125, + "issue_date": "2018-09-20", + "due_date": "2018-09-20", + "paid_date": "2018-09-20", + "status": "paid", + "collection_method": "automatic", + "payment_instructions": "Make checks payable to Acme, Inc.", + "currency": "USD", + "consolidation_level": "parent", + "parent_invoice_uid": null, + "parent_invoice_number": null, + "group_primary_subscription_id": 23277588, + "product_name": "Trial and setup fee", + "product_family_name": "Billing Plans", + "seller": { + "name": "General Goods", + "address": { + "street": "123 General Goods Way", + "line2": "Apt. 10", + "city": "Boston", + "state": "MA", + "zip": "02120", + "country": "US" + }, + "phone": "555-555-1212" + }, + "customer": { + "chargify_id": 20153415, + "first_name": "Meg", + "last_name": "Example", + "organization": "", + "email": "meg@example.com" + }, + "memo": "Please pay within 15 days.", + "billing_address": { + "street": "123 I Love Cats Way", + "line2": "", + "city": "Boston", + "state": "MA", + "zip": "90210", + "country": "US" + }, + "shipping_address": { + "street": "123 I Love Cats Way", + "line2": "", + "city": "Boston", + "state": "MA", + "zip": "90210", + "country": "US" + }, + "subtotal_amount": "100.0", + "discount_amount": "0.0", + "tax_amount": "0.0", + "total_amount": "100.0", + "credit_amount": "0.0", + "paid_amount": "100.0", + "refund_amount": "0.0", + "due_amount": "0.0", + "public_url": "https://www.chargifypay.com/invoice/inv_8htcd29wcq3q6?token=fb6kpjz5rcr2vttyjs4rcv6y" + }, + { + "uid": "inv_8hr3546xp4h8n", + "site_id": 51288, + "customer_id": 21687686, + "subscription_id": 22007644, + "number": "124", + "sequence_number": 124, + "issue_date": "2018-09-18", + "due_date": "2018-09-18", + "paid_date": null, + "status": "open", + "collection_method": "remittance", + "payment_instructions": "Make checks payable to Acme, Inc.", + "currency": "USD", + "consolidation_level": "none", + "parent_invoice_uid": null, + "parent_invoice_number": null, + "group_primary_subscription_id": null, + "product_name": "Trial and setup fee", + "product_family_name": "Billing Plans", + "seller": { + "name": "General Goods", + "address": { + "street": "123 General Goods Way", + "line2": "Apt. 10", + "city": "Boston", + "state": "MA", + "zip": "02120", + "country": "US" + }, + "phone": "555-555-1212" + }, + "customer": { + "chargify_id": 21687686, + "first_name": "Charlene", + "last_name": "Tester", + "organization": "", + "email": "food@example.com" + }, + "memo": "Please pay within 15 days.", + "billing_address": { + "street": "", + "line2": "", + "city": "", + "state": "", + "zip": "", + "country": "" + }, + "shipping_address": { + "street": "", + "line2": "", + "city": "", + "state": "", + "zip": "", + "country": "" + }, + "subtotal_amount": "100.0", + "discount_amount": "0.0", + "tax_amount": "0.0", + "total_amount": "100.0", + "credit_amount": "0.0", + "paid_amount": "0.0", + "refund_amount": "0.0", + "due_amount": "100.0", + "public_url": "https://www.chargifypay.com/invoice/inv_8hr3546xp4h8n?token=fb6kpjz5rcr2vttyjs4rcv6y" + }, + { + "uid": "inv_8hr3546wdwxkr", + "site_id": 51288, + "customer_id": 21687670, + "subscription_id": 22007627, + "number": "123", + "sequence_number": 123, + "issue_date": "2018-09-18", + "due_date": "2018-09-18", + "paid_date": "2018-09-18", + "status": "paid", + "collection_method": "automatic", + "payment_instructions": "Make checks payable to Acme, Inc.", + "currency": "USD", + "consolidation_level": "none", + "parent_invoice_uid": null, + "parent_invoice_number": null, + "group_primary_subscription_id": null, + "product_name": "Trial End - Free", + "product_family_name": "Billing Plans", + "seller": { + "name": "General Goods", + "address": { + "street": "123 General Goods Way", + "line2": "Apt. 10", + "city": "Boston", + "state": "MA", + "zip": "02120", + "country": "US" + }, + "phone": "555-555-1212" + }, + "customer": { + "chargify_id": 21687670, + "first_name": "Hello", + "last_name": "World", + "organization": "123", + "email": "example@example.com" + }, + "memo": "Please pay within 15 days.", + "billing_address": { + "street": "123 Anywhere Street", + "line2": "", + "city": "Boston", + "state": "MA", + "zip": "02120", + "country": "US" + }, + "shipping_address": { + "street": "", + "line2": "", + "city": "Boston", + "state": "AL", + "zip": "02120", + "country": "US" + }, + "subtotal_amount": "0.0", + "discount_amount": "0.0", + "tax_amount": "0.0", + "total_amount": "0.0", + "credit_amount": "0.0", + "paid_amount": "0.0", + "refund_amount": "0.0", + "due_amount": "0.0", + "public_url": "https://www.chargifypay.com/invoice/inv_8hr3546wdwxkr?token=fb6kpjz5rcr2vttyjs4rcv6y" + }, + { + "uid": "inv_8hjtk8bz56bbp", "site_id": 51288, - "customer_id": 20153415, - "subscription_id": 23277588, - "number": "125", - "sequence_number": 125, - "issue_date": "2018-09-20", - "due_date": "2018-09-20", - "paid_date": "2018-09-20", + "customer_id": 20137757, + "subscription_id": 20541100, + "number": "122", + "sequence_number": 122, + "issue_date": "2018-09-10", + "due_date": "2018-09-10", + "paid_date": "2018-09-10", "status": "paid", "collection_method": "automatic", "payment_instructions": "Make checks payable to Acme, Inc.", "currency": "USD", - "consolidation_level": "parent", + "consolidation_level": "none", "parent_invoice_uid": null, "parent_invoice_number": null, - "group_primary_subscription_id": 23277588, - "product_name": "Trial and setup fee", + "group_primary_subscription_id": null, + "product_name": "$0 Product", "product_family_name": "Billing Plans", "seller": { "name": "General Goods", @@ -2139,17 +1932,17 @@ result = invoices_controller.list_consolidated_invoice_segments(collect) "phone": "555-555-1212" }, "customer": { - "chargify_id": 20153415, - "first_name": "Meg", + "chargify_id": 20137757, + "first_name": "Sasha", "last_name": "Example", "organization": "", - "email": "meg@example.com" + "email": "example@example.com" }, "memo": "Please pay within 15 days.", "billing_address": { "street": "123 I Love Cats Way", "line2": "", - "city": "Boston", + "city": "Catville", "state": "MA", "zip": "90210", "country": "US" @@ -2157,218 +1950,357 @@ result = invoices_controller.list_consolidated_invoice_segments(collect) "shipping_address": { "street": "123 I Love Cats Way", "line2": "", - "city": "Boston", - "state": "MA", + "city": "Catville", + "state": "AL", "zip": "90210", "country": "US" }, - "subtotal_amount": "100.0", + "subtotal_amount": "0.0", "discount_amount": "0.0", "tax_amount": "0.0", - "total_amount": "100.0", + "total_amount": "0.0", "credit_amount": "0.0", - "paid_amount": "100.0", + "paid_amount": "0.0", "refund_amount": "0.0", "due_amount": "0.0", - "public_url": "https://www.chargifypay.com/invoice/inv_8htcd29wcq3q6?token=fb6kpjz5rcr2vttyjs4rcv6y" + "public_url": "https://www.chargifypay.com/invoice/inv_8jzrw74xq8kxr?token=fb6kpjz5rcr2vttyjs4rcv6y" + } + ] +} +``` + + +# Read Credit Note + +Use this endpoint to retrieve the details for a credit note. + +```python +def read_credit_note(self, + uid) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `uid` | `str` | Template, Required | The unique identifier of the credit note | + +## Response Type + +[`CreditNote`](../../doc/models/credit-note.md) + +## Example Usage + +```python +uid = 'uid0' + +result = invoices_controller.read_credit_note(uid) +``` + +## Example Response *(as JSON)* + +```json +{ + "uid": "cn_8m9vbd5kkv7kr", + "site_id": 20, + "customer_id": 3, + "subscription_id": 2, + "number": "77", + "sequence_number": 78, + "issue_date": "2018-12-31", + "applied_date": "2018-12-31", + "status": "applied", + "currency": "USD", + "memo": "Refund for overpayment", + "seller": { + "name": "Acme, Inc.", + "address": { + "street": "122 E Houston St", + "line2": "Suite 105", + "city": "San Antonio", + "state": "TX", + "zip": "78205", + "country": "US" + }, + "phone": "555-555-1234 x137" + }, + "customer": { + "chargify_id": 3, + "first_name": "Marty", + "last_name": "McFly", + "organization": "Time Travellers, Inc.", + "email": "timetraveller1985@example.com", + "reference": null + }, + "billing_address": { + "street": "200 Billing Rd.", + "line2": "Suite 100", + "city": "Needham", + "state": "MA", + "zip": "02494", + "country": "US" + }, + "shipping_address": { + "street": "100 Shipping St.", + "line2": "Apt 200", + "city": "Pleasantville", + "state": "NC", + "zip": "12345", + "country": "US" + }, + "subtotal_amount": "208.69341779", + "discount_amount": "20.87125167", + "tax_amount": "12.67783387", + "total_amount": "200.5", + "applied_amount": "200.5", + "remaining_amount": "0.0", + "line_items": [ + { + "uid": "cnli_8k5jvdzct4h9x", + "title": "IP Addresses: 5 to 10 addresses", + "description": "38.2% credit", + "quantity": "0.9855", + "unit_price": "2.0", + "subtotal_amount": "1.971004", + "discount_amount": "0.19862831", + "tax_amount": "0.11963536", + "total_amount": "1.89201105", + "tiered_unit_price": false, + "period_range_start": "2018-11-30", + "period_range_end": "2018-11-30", + "product_id": 85, + "product_version": 1, + "component_id": 81, + "price_point_id": 165, + "billing_schedule_item_id": null, + "custom_item": false + }, + { + "uid": "cnli_8kjttvjcjx8b4", + "title": "Professional Plan", + "description": "38.2% credit", + "quantity": "0.382", + "unit_price": "299.0", + "subtotal_amount": "114.21127834", + "discount_amount": "11.42112783", + "tax_amount": "6.93833516", + "total_amount": "109.72848567", + "tiered_unit_price": false, + "period_range_start": "2018-12-30", + "period_range_end": "2018-12-30", + "product_id": 85, + "product_version": 1, + "component_id": null, + "price_point_id": null, + "billing_schedule_item_id": null, + "custom_item": false + }, + { + "uid": "cnli_8kjttvjknzhx7", + "title": "Small Instance (Hourly)", + "description": "38.2% credit", + "quantity": "74.8676", + "unit_price": "0.12244898", + "subtotal_amount": "9.16746047", + "discount_amount": "0.91674605", + "tax_amount": "0.55692322", + "total_amount": "8.80763764", + "tiered_unit_price": true, + "period_range_start": "2018-11-30", + "period_range_end": "2018-11-30", + "product_id": 85, + "product_version": 1, + "component_id": 78, + "price_point_id": null, + "billing_schedule_item_id": null, + "custom_item": false + }, + { + "uid": "cnli_8kjttvjnmh25w", + "title": "Large Instance (Hourly)", + "description": "38.2% credit", + "quantity": "183.3492", + "unit_price": "0.39583333", + "subtotal_amount": "72.57572871", + "discount_amount": "7.25757287", + "tax_amount": "4.40897552", + "total_amount": "69.72713136", + "tiered_unit_price": true, + "period_range_start": "2018-11-30", + "period_range_end": "2018-11-30", + "product_id": 85, + "product_version": 1, + "component_id": 79, + "price_point_id": null, + "billing_schedule_item_id": null, + "custom_item": false + }, + { + "uid": "cnli_8kjttvjqn86kc", + "title": "Email Messages", + "description": "38.2% credit", + "quantity": "10076.9489", + "unit_price": "0.00031045", + "subtotal_amount": "3.12839588", + "discount_amount": "0.31322157", + "tax_amount": "0.19002427", + "total_amount": "3.00519858", + "tiered_unit_price": true, + "period_range_start": "2018-11-30", + "period_range_end": "2018-11-30", + "product_id": 85, + "product_version": 1, + "component_id": 80, + "price_point_id": null, + "billing_schedule_item_id": null, + "custom_item": false }, { - "uid": "inv_8hr3546xp4h8n", - "site_id": 51288, - "customer_id": 21687686, - "subscription_id": 22007644, - "number": "124", - "sequence_number": 124, - "issue_date": "2018-09-18", - "due_date": "2018-09-18", - "paid_date": null, - "status": "open", - "collection_method": "remittance", - "payment_instructions": "Make checks payable to Acme, Inc.", - "currency": "USD", - "consolidation_level": "none", - "parent_invoice_uid": null, - "parent_invoice_number": null, - "group_primary_subscription_id": null, - "product_name": "Trial and setup fee", - "product_family_name": "Billing Plans", - "seller": { - "name": "General Goods", - "address": { - "street": "123 General Goods Way", - "line2": "Apt. 10", - "city": "Boston", - "state": "MA", - "zip": "02120", - "country": "US" - }, - "phone": "555-555-1212" - }, - "customer": { - "chargify_id": 21687686, - "first_name": "Charlene", - "last_name": "Tester", - "organization": "", - "email": "food@example.com" - }, - "memo": "Please pay within 15 days.", - "billing_address": { - "street": "", - "line2": "", - "city": "", - "state": "", - "zip": "", - "country": "" - }, - "shipping_address": { - "street": "", - "line2": "", - "city": "", - "state": "", - "zip": "", - "country": "" - }, - "subtotal_amount": "100.0", - "discount_amount": "0.0", - "tax_amount": "0.0", - "total_amount": "100.0", - "credit_amount": "0.0", - "paid_amount": "0.0", - "refund_amount": "0.0", - "due_amount": "100.0", - "public_url": "https://www.chargifypay.com/invoice/inv_8hr3546xp4h8n?token=fb6kpjz5rcr2vttyjs4rcv6y" - }, + "uid": "cnli_8kjttvjtxxbdd", + "title": "IP Addresses", + "description": "38.2% credit", + "quantity": "3.8198", + "unit_price": "2.0", + "subtotal_amount": "7.63955039", + "discount_amount": "0.76395504", + "tax_amount": "0.46410269", + "total_amount": "7.33969804", + "tiered_unit_price": false, + "period_range_start": "2018-12-30", + "period_range_end": "2018-12-30", + "product_id": 85, + "product_version": 1, + "component_id": 81, + "price_point_id": 165, + "billing_schedule_item_id": null, + "custom_item": false + } + ], + "discounts": [ { - "uid": "inv_8hr3546wdwxkr", - "site_id": 51288, - "customer_id": 21687670, - "subscription_id": 22007627, - "number": "123", - "sequence_number": 123, - "issue_date": "2018-09-18", - "due_date": "2018-09-18", - "paid_date": "2018-09-18", - "status": "paid", - "collection_method": "automatic", - "payment_instructions": "Make checks payable to Acme, Inc.", - "currency": "USD", - "consolidation_level": "none", - "parent_invoice_uid": null, - "parent_invoice_number": null, - "group_primary_subscription_id": null, - "product_name": "Trial End - Free", - "product_family_name": "Billing Plans", - "seller": { - "name": "General Goods", - "address": { - "street": "123 General Goods Way", - "line2": "Apt. 10", - "city": "Boston", - "state": "MA", - "zip": "02120", - "country": "US" + "uid": "cndli_8k5jvdzct4h9y", + "title": "Multi-service discount (10%)", + "code": "MULTI3", + "source_type": "Coupon", + "source_id": 40, + "discount_type": "percentage", + "percentage": "10.0", + "eligible_amount": "208.69341779", + "discount_amount": "20.87125167", + "line_item_breakouts": [ + { + "uid": "cnli_8k5jvdzct4h9x", + "eligible_amount": "1.971004", + "discount_amount": "0.19862831" }, - "phone": "555-555-1212" - }, - "customer": { - "chargify_id": 21687670, - "first_name": "Hello", - "last_name": "World", - "organization": "123", - "email": "example@example.com" - }, - "memo": "Please pay within 15 days.", - "billing_address": { - "street": "123 Anywhere Street", - "line2": "", - "city": "Boston", - "state": "MA", - "zip": "02120", - "country": "US" - }, - "shipping_address": { - "street": "", - "line2": "", - "city": "Boston", - "state": "AL", - "zip": "02120", - "country": "US" - }, - "subtotal_amount": "0.0", - "discount_amount": "0.0", - "tax_amount": "0.0", - "total_amount": "0.0", - "credit_amount": "0.0", - "paid_amount": "0.0", - "refund_amount": "0.0", - "due_amount": "0.0", - "public_url": "https://www.chargifypay.com/invoice/inv_8hr3546wdwxkr?token=fb6kpjz5rcr2vttyjs4rcv6y" - }, + { + "uid": "cnli_8kjttvjcjx8b4", + "eligible_amount": "114.21127834", + "discount_amount": "11.42112783" + }, + { + "uid": "cnli_8kjttvjknzhx7", + "eligible_amount": "9.16746047", + "discount_amount": "0.91674605" + }, + { + "uid": "cnli_8kjttvjnmh25w", + "eligible_amount": "72.57572871", + "discount_amount": "7.25757287" + }, + { + "uid": "cnli_8kjttvjqn86kc", + "eligible_amount": "3.12839588", + "discount_amount": "0.31322157" + }, + { + "uid": "cnli_8kjttvjtxxbdd", + "eligible_amount": "7.63955039", + "discount_amount": "0.76395504" + } + ] + } + ], + "taxes": [ { - "uid": "inv_8hjtk8bz56bbp", - "site_id": 51288, - "customer_id": 20137757, - "subscription_id": 20541100, - "number": "122", - "sequence_number": 122, - "issue_date": "2018-09-10", - "due_date": "2018-09-10", - "paid_date": "2018-09-10", - "status": "paid", - "collection_method": "automatic", - "payment_instructions": "Make checks payable to Acme, Inc.", - "currency": "USD", - "consolidation_level": "none", - "parent_invoice_uid": null, - "parent_invoice_number": null, - "group_primary_subscription_id": null, - "product_name": "$0 Product", - "product_family_name": "Billing Plans", - "seller": { - "name": "General Goods", - "address": { - "street": "123 General Goods Way", - "line2": "Apt. 10", - "city": "Boston", - "state": "MA", - "zip": "02120", - "country": "US" + "uid": "cntli_8k5jvdzct4h9z", + "title": "NC Sales Tax", + "source_type": "Tax", + "source_id": 1, + "percentage": "6.75", + "taxable_amount": "187.82216613", + "tax_amount": "12.67783387", + "line_item_breakouts": [ + { + "uid": "cnli_8k5jvdzct4h9x", + "taxable_amount": "1.77237569", + "tax_amount": "0.11963536" + }, + { + "uid": "cnli_8kjttvjcjx8b4", + "taxable_amount": "102.7901505", + "tax_amount": "6.93833516" + }, + { + "uid": "cnli_8kjttvjknzhx7", + "taxable_amount": "8.25071442", + "tax_amount": "0.55692322" + }, + { + "uid": "cnli_8kjttvjnmh25w", + "taxable_amount": "65.31815584", + "tax_amount": "4.40897552" + }, + { + "uid": "cnli_8kjttvjqn86kc", + "taxable_amount": "2.81517432", + "tax_amount": "0.19002427" }, - "phone": "555-555-1212" - }, - "customer": { - "chargify_id": 20137757, - "first_name": "Sasha", - "last_name": "Example", - "organization": "", - "email": "example@example.com" - }, - "memo": "Please pay within 15 days.", - "billing_address": { - "street": "123 I Love Cats Way", - "line2": "", - "city": "Catville", - "state": "MA", - "zip": "90210", - "country": "US" - }, - "shipping_address": { - "street": "123 I Love Cats Way", - "line2": "", - "city": "Catville", - "state": "AL", - "zip": "90210", - "country": "US" - }, - "subtotal_amount": "0.0", - "discount_amount": "0.0", - "tax_amount": "0.0", - "total_amount": "0.0", - "credit_amount": "0.0", - "paid_amount": "0.0", - "refund_amount": "0.0", - "due_amount": "0.0", - "public_url": "https://www.chargifypay.com/invoice/inv_8jzrw74xq8kxr?token=fb6kpjz5rcr2vttyjs4rcv6y" + { + "uid": "cnli_8kjttvjtxxbdd", + "taxable_amount": "6.87559535", + "tax_amount": "0.46410269" + } + ], + "tax_component_breakouts": [ + { + "tax_rule_id": 1, + "percentage": "6.75", + "country_code": "US", + "subdivision_code": "NC", + "tax_amount": "10.66", + "taxable_amount": "157.95", + "tax_exempt_amount": "0.0", + "non_taxable_amount": "0.0", + "tax_name": "NC STATE TAX", + "tax_type": "Sales", + "rate_type": "General", + "tax_authority_type": 45, + "state_assigned_no": "", + "tax_sub_type": "S" + } + ], + "eu_vat": false, + "type": "Sales", + "tax_exempt_amount": "0.0" + } + ], + "applications": [ + { + "uid": "cdt_8m9vbdbdwd28n", + "transaction_time": "2018-12-31T21:19:28Z", + "invoice_uid": "inv_8k5jvdzct4hb2", + "memo": "Refund for overpayment", + "applied_amount": "200.5" + } + ], + "refunds": [ + { + "transaction_id": 329, + "payment_id": 39, + "memo": "Refund for overpayment", + "original_amount": "524.9", + "applied_amount": "200.5" } ] } @@ -2744,6 +2676,128 @@ invoices_controller.send_invoice( | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +# Record Payment for Subscription + +Record an external payment made against a subscription that will pay partially or in full one or more invoices. + +Payment will be applied starting with the oldest open invoice and then next oldest, and so on until the amount of the payment is fully consumed. + +Excess payment will result in the creation of a prepayment on the Invoice Account. + +Only ungrouped or primary subscriptions may be paid using the "bulk" payment request. + +```python +def record_payment_for_subscription(self, + subscription_id, + body=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `body` | [`RecordPaymentRequest`](../../doc/models/record-payment-request.md) | Body, Optional | - | + +## Response Type + +[`RecordPaymentResponse`](../../doc/models/record-payment-response.md) + +## Example Usage + +```python +subscription_id = 222 + +body = RecordPaymentRequest( + payment=CreatePayment( + amount='10.0', + memo='to pay the bills', + payment_details='check number 8675309', + payment_method=InvoicePaymentMethodType.CHECK + ) +) + +result = invoices_controller.record_payment_for_subscription( + subscription_id, + body=body +) +``` + +## Example Response *(as JSON)* + +```json +{ + "paid_invoices": [ + { + "invoice_id": "inv_bchyhr6z5grby", + "status": "paid", + "due_amount": "0.0", + "paid_amount": "50.0" + }, + { + "invoice_id": "inv_bchyhrgvyb6vm", + "status": "paid", + "due_amount": "0.0", + "paid_amount": "50.0" + } + ], + "prepayment": null +} +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + + +# Void Invoice + +This endpoint allows you to void any invoice with the "open" or "canceled" status. It will also allow voiding of an invoice with the "pending" status if it is not a consolidated invoice. + +```python +def void_invoice(self, + uid, + body=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `uid` | `str` | Template, Required | The unique identifier for the invoice, this does not refer to the public facing invoice number. | +| `body` | [`VoidInvoiceRequest`](../../doc/models/void-invoice-request.md) | Body, Optional | - | + +## Response Type + +[`Invoice`](../../doc/models/invoice.md) + +## Example Usage + +```python +uid = 'uid0' + +body = VoidInvoiceRequest( + void=VoidInvoice( + reason='Duplicate invoice' + ) +) + +result = invoices_controller.void_invoice( + uid, + body=body +) +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + + # Preview Customer Information Changes Customer information may change after an invoice is issued which may lead to a mismatch between customer information that are present on an open invoice and actual customer information. This endpoint allows to preview these differences, if any. @@ -3058,57 +3112,3 @@ result = invoices_controller.update_customer_information(uid) | 404 | Not Found | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - -# Issue Invoice - -This endpoint allows you to issue an invoice that is in "pending" status. For example, you can issue an invoice that was created when allocating new quantity on a component and using "accrue charges" option. - -You cannot issue a pending child invoice that was created for a member subscription in a group. - -For Remittance subscriptions, the invoice will go into "open" status and payment won't be attempted. The value for `on_failed_payment` would be rejected if sent. Any prepayments or service credits that exist on subscription will be automatically applied. Additionally, if setting is on, an email will be sent for issued invoice. - -For Automatic subscriptions, prepayments and service credits will apply to the invoice and before payment is attempted. On successful payment, the invoice will go into "paid" status and email will be sent to the customer (if setting applies). When payment fails, the next event depends on the `on_failed_payment` value: - -- `leave_open_invoice` - prepayments and credits applied to invoice; invoice status set to "open"; email sent to the customer for the issued invoice (if setting applies); payment failure recorded in the invoice history. This is the default option. -- `rollback_to_pending` - prepayments and credits not applied; invoice remains in "pending" status; no email sent to the customer; payment failure recorded in the invoice history. -- `initiate_dunning` - prepayments and credits applied to the invoice; invoice status set to "open"; email sent to the customer for the issued invoice (if setting applies); payment failure recorded in the invoice history; subscription will most likely go into "past_due" or "canceled" state (depending upon net terms and dunning settings). - -```python -def issue_invoice(self, - uid, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `uid` | `str` | Template, Required | The unique identifier for the invoice, this does not refer to the public facing invoice number. | -| `body` | [`IssueInvoiceRequest`](../../doc/models/issue-invoice-request.md) | Body, Optional | - | - -## Response Type - -[`Invoice`](../../doc/models/invoice.md) - -## Example Usage - -```python -uid = 'uid0' - -body = IssueInvoiceRequest( - on_failed_payment=FailedPaymentAction.LEAVE_OPEN_INVOICE -) - -result = invoices_controller.issue_invoice( - uid, - body=body -) -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - diff --git a/doc/controllers/offers.md b/doc/controllers/offers.md index cedf2ddd..7babd29b 100644 --- a/doc/controllers/offers.md +++ b/doc/controllers/offers.md @@ -10,11 +10,127 @@ offers_controller = client.offers ## Methods -* [Create Offer](../../doc/controllers/offers.md#create-offer) * [List Offers](../../doc/controllers/offers.md#list-offers) +* [Unarchive Offer](../../doc/controllers/offers.md#unarchive-offer) +* [Create Offer](../../doc/controllers/offers.md#create-offer) * [Read Offer](../../doc/controllers/offers.md#read-offer) * [Archive Offer](../../doc/controllers/offers.md#archive-offer) -* [Unarchive Offer](../../doc/controllers/offers.md#unarchive-offer) + + +# List Offers + +This endpoint will list offers for a site. + +```python +def list_offers(self, + options=dict()) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `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`. | +| `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`. | +| `include_archived` | `bool` | Query, Optional | Include archived products. Use in query: `include_archived=true`. | + +## Response Type + +[`ListOffersResponse`](../../doc/models/list-offers-response.md) + +## Example Usage + +```python +collect = { + 'page': 2, + 'per_page': 50, + 'include_archived': True +} +result = offers_controller.list_offers(collect) +``` + +## Example Response *(as JSON)* + +```json +{ + "offers": [ + { + "id": 239, + "site_id": 48110, + "product_family_id": 1025627, + "product_family_name": "Gold", + "product_id": 110, + "product_name": "Pro", + "product_price_in_cents": 1000, + "product_revisable_number": 0, + "product_price_point_id": 138, + "product_price_point_name": "Default", + "name": "Third Offer", + "handle": "third", + "description": "", + "created_at": "2018-08-03T09:56:11-05:00", + "updated_at": "2018-08-03T09:56:11-05:00", + "archived_at": null, + "offer_items": [ + { + "component_id": 426665, + "component_name": "Database Size (GB)", + "component_unit_price": "1.0", + "price_point_id": 149438, + "price_point_name": "Auto-created", + "starting_quantity": "0.0", + "editable": false + } + ], + "offer_discounts": [ + { + "coupon_id": 234, + "coupon_code": "GR8_CUSTOMER", + "coupon_name": "Multi-service Discount" + } + ], + "offer_signup_pages": [ + { + "id": 356482, + "nickname": "ggoods", + "enabled": true, + "return_url": "", + "return_params": "", + "url": "https://general-goods.chargifypay.com/subscribe/hjpvhnw63tzy" + } + ] + } + ] +} +``` + + +# Unarchive Offer + +Unarchive a previously archived offer. Please provide an `offer_id` in order to un-archive the correct item. + +```python +def unarchive_offer(self, + offer_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `offer_id` | `int` | Template, Required | The Chargify id of the offer | + +## Response Type + +`void` + +## Example Usage + +```python +offer_id = 130 + +offers_controller.unarchive_offer(offer_id) +``` # Create Offer @@ -124,94 +240,6 @@ result = offers_controller.create_offer( | 422 | Unprocessable Entity (WebDAV) | [`ErrorArrayMapResponseException`](../../doc/models/error-array-map-response-exception.md) | -# List Offers - -This endpoint will list offers for a site. - -```python -def list_offers(self, - options=dict()) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `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`. | -| `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`. | -| `include_archived` | `bool` | Query, Optional | Include archived products. Use in query: `include_archived=true`. | - -## Response Type - -[`ListOffersResponse`](../../doc/models/list-offers-response.md) - -## Example Usage - -```python -collect = { - 'page': 2, - 'per_page': 50, - 'include_archived': True -} -result = offers_controller.list_offers(collect) -``` - -## Example Response *(as JSON)* - -```json -{ - "offers": [ - { - "id": 239, - "site_id": 48110, - "product_family_id": 1025627, - "product_family_name": "Gold", - "product_id": 110, - "product_name": "Pro", - "product_price_in_cents": 1000, - "product_revisable_number": 0, - "product_price_point_id": 138, - "product_price_point_name": "Default", - "name": "Third Offer", - "handle": "third", - "description": "", - "created_at": "2018-08-03T09:56:11-05:00", - "updated_at": "2018-08-03T09:56:11-05:00", - "archived_at": null, - "offer_items": [ - { - "component_id": 426665, - "component_name": "Database Size (GB)", - "component_unit_price": "1.0", - "price_point_id": 149438, - "price_point_name": "Auto-created", - "starting_quantity": "0.0", - "editable": false - } - ], - "offer_discounts": [ - { - "coupon_id": 234, - "coupon_code": "GR8_CUSTOMER", - "coupon_name": "Multi-service Discount" - } - ], - "offer_signup_pages": [ - { - "id": 356482, - "nickname": "ggoods", - "enabled": true, - "return_url": "", - "return_params": "", - "url": "https://general-goods.chargifypay.com/subscribe/hjpvhnw63tzy" - } - ] - } - ] -} -``` - - # Read Offer This method allows you to list a specific offer's attributes. This is different than list all offers for a site, as it requires an `offer_id`. @@ -267,31 +295,3 @@ offer_id = 130 offers_controller.archive_offer(offer_id) ``` - -# Unarchive Offer - -Unarchive a previously archived offer. Please provide an `offer_id` in order to un-archive the correct item. - -```python -def unarchive_offer(self, - offer_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `offer_id` | `int` | Template, Required | The Chargify id of the offer | - -## Response Type - -`void` - -## Example Usage - -```python -offer_id = 130 - -offers_controller.unarchive_offer(offer_id) -``` - diff --git a/doc/controllers/payment-profiles.md b/doc/controllers/payment-profiles.md index 2f684905..68226dfe 100644 --- a/doc/controllers/payment-profiles.md +++ b/doc/controllers/payment-profiles.md @@ -10,18 +10,299 @@ payment_profiles_controller = client.payment_profiles ## Methods -* [Create Payment Profile](../../doc/controllers/payment-profiles.md#create-payment-profile) * [List Payment Profiles](../../doc/controllers/payment-profiles.md#list-payment-profiles) +* [Change Subscription Group Default Payment Profile](../../doc/controllers/payment-profiles.md#change-subscription-group-default-payment-profile) +* [Read One Time Token](../../doc/controllers/payment-profiles.md#read-one-time-token) +* [Send Request Update Payment Email](../../doc/controllers/payment-profiles.md#send-request-update-payment-email) +* [Delete Unused Payment Profile](../../doc/controllers/payment-profiles.md#delete-unused-payment-profile) +* [Create Payment Profile](../../doc/controllers/payment-profiles.md#create-payment-profile) * [Read Payment Profile](../../doc/controllers/payment-profiles.md#read-payment-profile) * [Update Payment Profile](../../doc/controllers/payment-profiles.md#update-payment-profile) -* [Delete Unused Payment Profile](../../doc/controllers/payment-profiles.md#delete-unused-payment-profile) * [Delete Subscriptions Payment Profile](../../doc/controllers/payment-profiles.md#delete-subscriptions-payment-profile) * [Verify Bank Account](../../doc/controllers/payment-profiles.md#verify-bank-account) * [Delete Subscription Group Payment Profile](../../doc/controllers/payment-profiles.md#delete-subscription-group-payment-profile) * [Change Subscription Default Payment Profile](../../doc/controllers/payment-profiles.md#change-subscription-default-payment-profile) -* [Change Subscription Group Default Payment Profile](../../doc/controllers/payment-profiles.md#change-subscription-group-default-payment-profile) -* [Read One Time Token](../../doc/controllers/payment-profiles.md#read-one-time-token) -* [Send Request Update Payment Email](../../doc/controllers/payment-profiles.md#send-request-update-payment-email) + + +# List Payment Profiles + +This method will return all of the active `payment_profiles` for a Site, or for one Customer within a site. If no payment profiles are found, this endpoint will return an empty array, not a 404. + +```python +def list_payment_profiles(self, + options=dict()) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `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`. | +| `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`. | +| `customer_id` | `int` | Query, Optional | The ID of the customer for which you wish to list payment profiles | + +## Response Type + +[`List[PaymentProfileResponse]`](../../doc/models/payment-profile-response.md) + +## Example Usage + +```python +collect = { + 'page': 2, + 'per_page': 50 +} +result = payment_profiles_controller.list_payment_profiles(collect) +``` + +## Example Response *(as JSON)* + +```json +[ + { + "payment_profile": { + "id": 10089892, + "first_name": "Chester", + "last_name": "Tester", + "customer_id": 14543792, + "current_vault": "bogus", + "vault_token": "0011223344", + "billing_address": "456 Juniper Court", + "billing_city": "Boulder", + "billing_state": "CO", + "billing_zip": "80302", + "billing_country": "US", + "customer_vault_token": null, + "billing_address_2": "", + "bank_name": "Bank of Kansas City", + "masked_bank_routing_number": "XXXX6789", + "masked_bank_account_number": "XXXX3344", + "bank_account_type": "checking", + "bank_account_holder_type": "personal", + "payment_type": "bank_account", + "verified": true, + "site_gateway_setting_id": 1, + "gateway_handle": "handle" + } + }, + { + "payment_profile": { + "id": 10188522, + "first_name": "Frankie", + "last_name": "Tester", + "customer_id": 14543712, + "current_vault": "bogus", + "vault_token": "123456789", + "billing_address": "123 Montana Way", + "billing_city": "Los Angeles", + "billing_state": "CA", + "billing_zip": "90210", + "billing_country": "US", + "customer_vault_token": null, + "billing_address_2": "", + "bank_name": "Bank of Kansas City", + "masked_bank_routing_number": "XXXX6789", + "masked_bank_account_number": "XXXX6789", + "bank_account_type": "checking", + "bank_account_holder_type": "personal", + "payment_type": "bank_account", + "verified": true, + "site_gateway_setting_id": 1, + "gateway_handle": "handle" + } + } +] +``` + + +# Change Subscription Group Default Payment Profile + +This will change the default payment profile on the subscription group to the existing payment profile with the id specified. + +You must elect to change the existing payment profile to a new payment profile ID in order to receive a satisfactory response from this endpoint. + +The new payment profile must belong to the subscription group's customer, otherwise you will receive an error. + +```python +def change_subscription_group_default_payment_profile(self, + uid, + payment_profile_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `uid` | `str` | Template, Required | The uid of the subscription group | +| `payment_profile_id` | `int` | Template, Required | The Chargify id of the payment profile | + +## Response Type + +[`PaymentProfileResponse`](../../doc/models/payment-profile-response.md) + +## Example Usage + +```python +uid = 'uid0' + +payment_profile_id = 198 + +result = payment_profiles_controller.change_subscription_group_default_payment_profile( + uid, + payment_profile_id +) +``` + +## Example Response *(as JSON)* + +```json +{ + "payment_profile": { + "id": 10211899, + "first_name": "Amelia", + "last_name": "Example", + "masked_card_number": "XXXX-XXXX-XXXX-1", + "card_type": "bogus", + "expiration_month": 2, + "expiration_year": 2018, + "customer_id": 14399371, + "current_vault": "bogus", + "vault_token": "1", + "billing_address": "", + "billing_city": "", + "billing_state": "", + "billing_zip": "", + "billing_country": "", + "customer_vault_token": null, + "billing_address_2": "", + "payment_type": "credit_card", + "site_gateway_setting_id": 1, + "gateway_handle": null + } +} +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + + +# Read One Time Token + +One Time Tokens aka Advanced Billing Tokens house the credit card or ACH (Authorize.Net or Stripe only) data for a customer. + +You can use One Time Tokens while creating a subscription or payment profile instead of passing all bank account or credit card data directly to a given API endpoint. + +To obtain a One Time Token you have to use [Chargify.js](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDI0-overview). + +```python +def read_one_time_token(self, + chargify_token) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `chargify_token` | `str` | Template, Required | Advanced Billing Token | + +## Response Type + +[`GetOneTimeTokenRequest`](../../doc/models/get-one-time-token-request.md) + +## Example Usage + +```python +chargify_token = 'chargify_token8' + +result = payment_profiles_controller.read_one_time_token(chargify_token) +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + + +# Send Request Update Payment Email + +You can send a "request payment update" email to the customer associated with the subscription. + +If you attempt to send a "request payment update" email more than five times within a 30-minute period, you will receive a `422` response with an error message in the body. This error message will indicate that the request has been rejected due to excessive attempts, and will provide instructions on how to resubmit the request. + +Additionally, if you attempt to send a "request payment update" email for a subscription that does not exist, you will receive a `404` error response. This error message will indicate that the subscription could not be found, and will provide instructions on how to correct the error and resubmit the request. + +These error responses are designed to prevent excessive or invalid requests, and to provide clear and helpful information to users who encounter errors during the request process. + +```python +def send_request_update_payment_email(self, + subscription_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | + +## Response Type + +`void` + +## Example Usage + +```python +subscription_id = 222 + +payment_profiles_controller.send_request_update_payment_email(subscription_id) +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + + +# Delete Unused Payment Profile + +Deletes an unused payment profile. + +If the payment profile is in use by one or more subscriptions or groups, a 422 and error message will be returned. + +```python +def delete_unused_payment_profile(self, + payment_profile_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `payment_profile_id` | `int` | Template, Required | The Chargify id of the payment profile | + +## Response Type + +`void` + +## Example Usage + +```python +payment_profile_id = 198 + +payment_profiles_controller.delete_unused_payment_profile(payment_profile_id) +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | # Create Payment Profile @@ -357,109 +638,18 @@ result = payment_profiles_controller.create_payment_profile( "billing_address_2": null, "payment_type": "credit_card", "site_gateway_setting_id": 1, - "gateway_handle": "handle", - "disabled": false - } -} -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - - -# List Payment Profiles - -This method will return all of the active `payment_profiles` for a Site, or for one Customer within a site. If no payment profiles are found, this endpoint will return an empty array, not a 404. - -```python -def list_payment_profiles(self, - options=dict()) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `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`. | -| `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`. | -| `customer_id` | `int` | Query, Optional | The ID of the customer for which you wish to list payment profiles | - -## Response Type - -[`List[PaymentProfileResponse]`](../../doc/models/payment-profile-response.md) - -## Example Usage - -```python -collect = { - 'page': 2, - 'per_page': 50 + "gateway_handle": "handle", + "disabled": false + } } -result = payment_profiles_controller.list_payment_profiles(collect) ``` -## Example Response *(as JSON)* +## Errors -```json -[ - { - "payment_profile": { - "id": 10089892, - "first_name": "Chester", - "last_name": "Tester", - "customer_id": 14543792, - "current_vault": "bogus", - "vault_token": "0011223344", - "billing_address": "456 Juniper Court", - "billing_city": "Boulder", - "billing_state": "CO", - "billing_zip": "80302", - "billing_country": "US", - "customer_vault_token": null, - "billing_address_2": "", - "bank_name": "Bank of Kansas City", - "masked_bank_routing_number": "XXXX6789", - "masked_bank_account_number": "XXXX3344", - "bank_account_type": "checking", - "bank_account_holder_type": "personal", - "payment_type": "bank_account", - "verified": true, - "site_gateway_setting_id": 1, - "gateway_handle": "handle" - } - }, - { - "payment_profile": { - "id": 10188522, - "first_name": "Frankie", - "last_name": "Tester", - "customer_id": 14543712, - "current_vault": "bogus", - "vault_token": "123456789", - "billing_address": "123 Montana Way", - "billing_city": "Los Angeles", - "billing_state": "CA", - "billing_zip": "90210", - "billing_country": "US", - "customer_vault_token": null, - "billing_address_2": "", - "bank_name": "Bank of Kansas City", - "masked_bank_routing_number": "XXXX6789", - "masked_bank_account_number": "XXXX6789", - "bank_account_type": "checking", - "bank_account_holder_type": "personal", - "payment_type": "bank_account", - "verified": true, - "site_gateway_setting_id": 1, - "gateway_handle": "handle" - } - } -] -``` +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | # Read Payment Profile @@ -679,43 +869,6 @@ result = payment_profiles_controller.update_payment_profile( | 422 | Unprocessable Entity (WebDAV) | [`ErrorStringMapResponseException`](../../doc/models/error-string-map-response-exception.md) | -# Delete Unused Payment Profile - -Deletes an unused payment profile. - -If the payment profile is in use by one or more subscriptions or groups, a 422 and error message will be returned. - -```python -def delete_unused_payment_profile(self, - payment_profile_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `payment_profile_id` | `int` | Template, Required | The Chargify id of the payment profile | - -## Response Type - -`void` - -## Example Usage - -```python -payment_profile_id = 198 - -payment_profiles_controller.delete_unused_payment_profile(payment_profile_id) -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - - # Delete Subscriptions Payment Profile This will delete a payment profile belonging to the customer on the subscription. @@ -939,156 +1092,3 @@ result = payment_profiles_controller.change_subscription_default_payment_profile | 404 | Not Found | `APIException` | | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - -# Change Subscription Group Default Payment Profile - -This will change the default payment profile on the subscription group to the existing payment profile with the id specified. - -You must elect to change the existing payment profile to a new payment profile ID in order to receive a satisfactory response from this endpoint. - -The new payment profile must belong to the subscription group's customer, otherwise you will receive an error. - -```python -def change_subscription_group_default_payment_profile(self, - uid, - payment_profile_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `uid` | `str` | Template, Required | The uid of the subscription group | -| `payment_profile_id` | `int` | Template, Required | The Chargify id of the payment profile | - -## Response Type - -[`PaymentProfileResponse`](../../doc/models/payment-profile-response.md) - -## Example Usage - -```python -uid = 'uid0' - -payment_profile_id = 198 - -result = payment_profiles_controller.change_subscription_group_default_payment_profile( - uid, - payment_profile_id -) -``` - -## Example Response *(as JSON)* - -```json -{ - "payment_profile": { - "id": 10211899, - "first_name": "Amelia", - "last_name": "Example", - "masked_card_number": "XXXX-XXXX-XXXX-1", - "card_type": "bogus", - "expiration_month": 2, - "expiration_year": 2018, - "customer_id": 14399371, - "current_vault": "bogus", - "vault_token": "1", - "billing_address": "", - "billing_city": "", - "billing_state": "", - "billing_zip": "", - "billing_country": "", - "customer_vault_token": null, - "billing_address_2": "", - "payment_type": "credit_card", - "site_gateway_setting_id": 1, - "gateway_handle": null - } -} -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - - -# Read One Time Token - -One Time Tokens aka Advanced Billing Tokens house the credit card or ACH (Authorize.Net or Stripe only) data for a customer. - -You can use One Time Tokens while creating a subscription or payment profile instead of passing all bank account or credit card data directly to a given API endpoint. - -To obtain a One Time Token you have to use [Chargify.js](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDI0-overview). - -```python -def read_one_time_token(self, - chargify_token) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `chargify_token` | `str` | Template, Required | Advanced Billing Token | - -## Response Type - -[`GetOneTimeTokenRequest`](../../doc/models/get-one-time-token-request.md) - -## Example Usage - -```python -chargify_token = 'chargify_token8' - -result = payment_profiles_controller.read_one_time_token(chargify_token) -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - - -# Send Request Update Payment Email - -You can send a "request payment update" email to the customer associated with the subscription. - -If you attempt to send a "request payment update" email more than five times within a 30-minute period, you will receive a `422` response with an error message in the body. This error message will indicate that the request has been rejected due to excessive attempts, and will provide instructions on how to resubmit the request. - -Additionally, if you attempt to send a "request payment update" email for a subscription that does not exist, you will receive a `404` error response. This error message will indicate that the subscription could not be found, and will provide instructions on how to correct the error and resubmit the request. - -These error responses are designed to prevent excessive or invalid requests, and to provide clear and helpful information to users who encounter errors during the request process. - -```python -def send_request_update_payment_email(self, - subscription_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | - -## Response Type - -`void` - -## Example Usage - -```python -subscription_id = 222 - -payment_profiles_controller.send_request_update_payment_email(subscription_id) -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - diff --git a/doc/controllers/product-families.md b/doc/controllers/product-families.md index 4851e96d..21ce6c33 100644 --- a/doc/controllers/product-families.md +++ b/doc/controllers/product-families.md @@ -11,9 +11,9 @@ product_families_controller = client.product_families ## Methods * [List Products for Product Family](../../doc/controllers/product-families.md#list-products-for-product-family) +* [Read Product Family](../../doc/controllers/product-families.md#read-product-family) * [Create Product Family](../../doc/controllers/product-families.md#create-product-family) * [List Product Families](../../doc/controllers/product-families.md#list-product-families) -* [Read Product Family](../../doc/controllers/product-families.md#read-product-family) # List Products for Product Family @@ -164,6 +164,50 @@ result = product_families_controller.list_products_for_product_family(collect) | 404 | Not Found | `APIException` | +# Read Product Family + +This method allows to retrieve 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. + +```python +def read_product_family(self, + id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `id` | `int` | Template, Required | The Advanced Billing id of the product family | + +## Response Type + +[`ProductFamilyResponse`](../../doc/models/product-family-response.md) + +## Example Usage + +```python +id = 112 + +result = product_families_controller.read_product_family(id) +``` + +## Example Response *(as JSON)* + +```json +{ + "product_family": { + "id": 527890, + "name": "Acme Projects", + "description": "", + "handle": "billing-plans", + "accounting_code": null + } +} +``` + + # 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. @@ -282,47 +326,3 @@ result = product_families_controller.list_product_families(collect) ] ``` - -# Read Product Family - -This method allows to retrieve 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. - -```python -def read_product_family(self, - id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `id` | `int` | Template, Required | The Advanced Billing id of the product family | - -## Response Type - -[`ProductFamilyResponse`](../../doc/models/product-family-response.md) - -## Example Usage - -```python -id = 112 - -result = product_families_controller.read_product_family(id) -``` - -## Example Response *(as JSON)* - -```json -{ - "product_family": { - "id": 527890, - "name": "Acme Projects", - "description": "", - "handle": "billing-plans", - "accounting_code": null - } -} -``` - diff --git a/doc/controllers/product-price-points.md b/doc/controllers/product-price-points.md index 66e845ef..c171889f 100644 --- a/doc/controllers/product-price-points.md +++ b/doc/controllers/product-price-points.md @@ -10,35 +10,35 @@ product_price_points_controller = client.product_price_points ## Methods -* [Create Product Price Point](../../doc/controllers/product-price-points.md#create-product-price-point) +* [Unarchive Product Price Point](../../doc/controllers/product-price-points.md#unarchive-product-price-point) * [List Product Price Points](../../doc/controllers/product-price-points.md#list-product-price-points) -* [Update Product Price Point](../../doc/controllers/product-price-points.md#update-product-price-point) * [Read Product Price Point](../../doc/controllers/product-price-points.md#read-product-price-point) -* [Archive Product Price Point](../../doc/controllers/product-price-points.md#archive-product-price-point) -* [Unarchive Product Price Point](../../doc/controllers/product-price-points.md#unarchive-product-price-point) -* [Promote Product Price Point to Default](../../doc/controllers/product-price-points.md#promote-product-price-point-to-default) -* [Bulk Create Product Price Points](../../doc/controllers/product-price-points.md#bulk-create-product-price-points) * [Create Product Currency Prices](../../doc/controllers/product-price-points.md#create-product-currency-prices) +* [Create Product Price Point](../../doc/controllers/product-price-points.md#create-product-price-point) +* [Bulk Create Product Price Points](../../doc/controllers/product-price-points.md#bulk-create-product-price-points) * [Update Product Currency Prices](../../doc/controllers/product-price-points.md#update-product-currency-prices) +* [Update Product Price Point](../../doc/controllers/product-price-points.md#update-product-price-point) +* [Archive Product Price Point](../../doc/controllers/product-price-points.md#archive-product-price-point) +* [Promote Product Price Point to Default](../../doc/controllers/product-price-points.md#promote-product-price-point-to-default) * [List All Product Price Points](../../doc/controllers/product-price-points.md#list-all-product-price-points) -# Create Product Price Point +# Unarchive Product Price Point -[Product Price Point Documentation](https://maxio.zendesk.com/hc/en-us/articles/24261111947789-Product-Price-Points) +Use this endpoint to unarchive an archived product price point. ```python -def create_product_price_point(self, - product_id, - body=None) +def unarchive_product_price_point(self, + product_id, + price_point_id) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `product_id` | int \| str | Template, Required | This is a container for one-of cases. | -| `body` | [`CreateProductPricePointRequest`](../../doc/models/create-product-price-point-request.md) | Body, Optional | - | +| `product_id` | `int` | Template, Required | The Advanced Billing id of the product to which the price point belongs | +| `price_point_id` | `int` | Template, Required | The Advanced Billing id of the product price point | ## Response Type @@ -47,29 +47,13 @@ def create_product_price_point(self, ## Example Usage ```python -product_id = 124 +product_id = 202 -body = CreateProductPricePointRequest( - price_point=CreateProductPricePoint( - name='Educational', - price_in_cents=1000, - interval=1, - interval_unit=IntervalUnit.MONTH, - handle='educational', - trial_price_in_cents=4900, - trial_interval=1, - trial_interval_unit=IntervalUnit.MONTH, - trial_type='payment_expected', - initial_charge_in_cents=120000, - initial_charge_after_trial=False, - expiration_interval=12, - expiration_interval_unit=ExpirationIntervalUnit.MONTH - ) -) +price_point_id = 10 -result = product_price_points_controller.create_product_price_point( +result = product_price_points_controller.unarchive_product_price_point( product_id, - body=body + price_point_id ) ``` @@ -100,12 +84,6 @@ result = product_price_points_controller.create_product_price_point( } ``` -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ProductPricePointErrorResponseException`](../../doc/models/product-price-point-error-response-exception.md) | - # List Product Price Points @@ -171,17 +149,15 @@ result = product_price_points_controller.list_product_price_points(collect) ``` -# Update Product Price Point - -Use this endpoint to update a product price point. +# Read Product Price Point -Note: Custom product price points are not able to be updated. +Use this endpoint to retrieve details for a specific product price point. You can achieve this by using either the product price point ID or handle. ```python -def update_product_price_point(self, - product_id, - price_point_id, - body=None) +def read_product_price_point(self, + product_id, + price_point_id, + currency_prices=None) ``` ## Parameters @@ -190,7 +166,7 @@ def update_product_price_point(self, | --- | --- | --- | --- | | `product_id` | int \| str | Template, Required | This is a container for one-of cases. | | `price_point_id` | int \| str | Template, Required | This is a container for one-of cases. | -| `body` | [`UpdateProductPricePointRequest`](../../doc/models/update-product-price-point-request.md) | Body, Optional | - | +| `currency_prices` | `bool` | Query, Optional | When fetching a product's price points, if you have defined multiple currencies at the site level, you can optionally pass the ?currency_prices=true query param to include an array of currency price data in the response. If the product price point 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. | ## Response Type @@ -203,17 +179,9 @@ product_id = 124 price_point_id = 188 -body = UpdateProductPricePointRequest( - price_point=UpdateProductPricePoint( - handle='educational', - price_in_cents=1250 - ) -) - -result = product_price_points_controller.update_product_price_point( +result = product_price_points_controller.read_product_price_point( product_id, - price_point_id, - body=body + price_point_id ) ``` @@ -245,39 +213,59 @@ result = product_price_points_controller.update_product_price_point( ``` -# Read Product Price Point +# Create Product Currency Prices -Use this endpoint to retrieve details for a specific product price point. You can achieve this by using either the product price point ID or handle. +This endpoint allows you to create 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. + +Note: Currency Prices are not able to be created for custom product price points. ```python -def read_product_price_point(self, - product_id, - price_point_id, - currency_prices=None) +def create_product_currency_prices(self, + product_price_point_id, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `product_id` | int \| str | Template, Required | This is a container for one-of cases. | -| `price_point_id` | int \| str | Template, Required | This is a container for one-of cases. | -| `currency_prices` | `bool` | Query, Optional | When fetching a product's price points, if you have defined multiple currencies at the site level, you can optionally pass the ?currency_prices=true query param to include an array of currency price data in the response. If the product price point 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. | +| `product_price_point_id` | `int` | Template, Required | The Advanced Billing id of the product price point | +| `body` | [`CreateProductCurrencyPricesRequest`](../../doc/models/create-product-currency-prices-request.md) | Body, Optional | - | ## Response Type -[`ProductPricePointResponse`](../../doc/models/product-price-point-response.md) +[`CurrencyPricesResponse`](../../doc/models/currency-prices-response.md) ## Example Usage ```python -product_id = 124 +product_price_point_id = 234 -price_point_id = 188 +body = CreateProductCurrencyPricesRequest( + currency_prices=[ + CreateProductCurrencyPrice( + currency='EUR', + price=60, + role=CurrencyPriceRole.BASELINE + ), + CreateProductCurrencyPrice( + currency='EUR', + price=30, + role=CurrencyPriceRole.TRIAL + ), + CreateProductCurrencyPrice( + currency='EUR', + price=100, + role=CurrencyPriceRole.INITIAL + ) + ] +) -result = product_price_points_controller.read_product_price_point( - product_id, - price_point_id +result = product_price_points_controller.create_product_currency_prices( + product_price_point_id, + body=body ) ``` @@ -285,38 +273,34 @@ result = product_price_points_controller.read_product_price_point( ```json { - "price_point": { - "id": 283, - "name": "Educational", - "handle": "educational", - "price_in_cents": 1000, - "interval": 1, - "interval_unit": "month", - "trial_price_in_cents": 4900, - "trial_interval": 1, - "trial_interval_unit": "month", - "trial_type": "payment_expected", - "initial_charge_in_cents": 120000, - "initial_charge_after_trial": false, - "expiration_interval": 12, - "expiration_interval_unit": "month", - "product_id": 901, - "archived_at": "2023-11-30T06:37:20-05:00", - "created_at": "2023-11-27T06:37:20-05:00", - "updated_at": "2023-11-27T06:37:20-05:00" - } + "currency_prices": [ + { + "id": 100, + "currency": "EUR", + "price": 123, + "formatted_price": "€123,00", + "product_price_point_id": 32669, + "role": "baseline" + } + ] } ``` +## Errors -# Archive Product Price Point +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorArrayMapResponseException`](../../doc/models/error-array-map-response-exception.md) | -Use this endpoint to archive a product price point. + +# Create Product Price Point + +[Product Price Point Documentation](https://maxio.zendesk.com/hc/en-us/articles/24261111947789-Product-Price-Points) ```python -def archive_product_price_point(self, - product_id, - price_point_id) +def create_product_price_point(self, + product_id, + body=None) ``` ## Parameters @@ -324,7 +308,7 @@ def archive_product_price_point(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `product_id` | int \| str | Template, Required | This is a container for one-of cases. | -| `price_point_id` | int \| str | Template, Required | This is a container for one-of cases. | +| `body` | [`CreateProductPricePointRequest`](../../doc/models/create-product-price-point-request.md) | Body, Optional | - | ## Response Type @@ -335,11 +319,27 @@ def archive_product_price_point(self, ```python product_id = 124 -price_point_id = 188 +body = CreateProductPricePointRequest( + price_point=CreateProductPricePoint( + name='Educational', + price_in_cents=1000, + interval=1, + interval_unit=IntervalUnit.MONTH, + handle='educational', + trial_price_in_cents=4900, + trial_interval=1, + trial_interval_unit=IntervalUnit.MONTH, + trial_type='payment_expected', + initial_charge_in_cents=120000, + initial_charge_after_trial=False, + expiration_interval=12, + expiration_interval_unit=ExpirationIntervalUnit.MONTH + ) +) -result = product_price_points_controller.archive_product_price_point( +result = product_price_points_controller.create_product_price_point( product_id, - price_point_id + body=body ) ``` @@ -374,181 +374,29 @@ result = product_price_points_controller.archive_product_price_point( | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +| 422 | Unprocessable Entity (WebDAV) | [`ProductPricePointErrorResponseException`](../../doc/models/product-price-point-error-response-exception.md) | -# Unarchive Product Price Point +# Bulk Create Product Price Points -Use this endpoint to unarchive an archived product price point. +Use this endpoint to create multiple product price points in one request. ```python -def unarchive_product_price_point(self, - product_id, - price_point_id) +def bulk_create_product_price_points(self, + product_id, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `product_id` | `int` | Template, Required | The Advanced Billing id of the product to which the price point belongs | -| `price_point_id` | `int` | Template, Required | The Advanced Billing id of the product price point | +| `product_id` | `int` | Template, Required | The Advanced Billing id of the product to which the price points belong | +| `body` | [`BulkCreateProductPricePointsRequest`](../../doc/models/bulk-create-product-price-points-request.md) | Body, Optional | - | ## Response Type -[`ProductPricePointResponse`](../../doc/models/product-price-point-response.md) - -## Example Usage - -```python -product_id = 202 - -price_point_id = 10 - -result = product_price_points_controller.unarchive_product_price_point( - product_id, - price_point_id -) -``` - -## Example Response *(as JSON)* - -```json -{ - "price_point": { - "id": 283, - "name": "Educational", - "handle": "educational", - "price_in_cents": 1000, - "interval": 1, - "interval_unit": "month", - "trial_price_in_cents": 4900, - "trial_interval": 1, - "trial_interval_unit": "month", - "trial_type": "payment_expected", - "initial_charge_in_cents": 120000, - "initial_charge_after_trial": false, - "expiration_interval": 12, - "expiration_interval_unit": "month", - "product_id": 901, - "archived_at": "2023-11-30T06:37:20-05:00", - "created_at": "2023-11-27T06:37:20-05:00", - "updated_at": "2023-11-27T06:37:20-05:00" - } -} -``` - - -# Promote Product Price Point to Default - -Use this endpoint to make a product price point the default for the product. - -Note: Custom product price points are not able to be set as the default for a product. - -```python -def promote_product_price_point_to_default(self, - product_id, - price_point_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `product_id` | `int` | Template, Required | The Advanced Billing id of the product to which the price point belongs | -| `price_point_id` | `int` | Template, Required | The Advanced Billing id of the product price point | - -## Response Type - -[`ProductResponse`](../../doc/models/product-response.md) - -## Example Usage - -```python -product_id = 202 - -price_point_id = 10 - -result = product_price_points_controller.promote_product_price_point_to_default( - product_id, - price_point_id -) -``` - -## Example Response *(as JSON)* - -```json -{ - "product": { - "id": 29778, - "name": "Educational", - "handle": "educational", - "description": null, - "accounting_code": null, - "request_credit_card": true, - "expiration_interval": 12, - "expiration_interval_unit": "month", - "created_at": "2023-12-01T06:56:12-05:00", - "updated_at": "2023-12-01T06:56:26-05:00", - "price_in_cents": 100, - "interval": 2, - "interval_unit": "month", - "initial_charge_in_cents": 120000, - "trial_price_in_cents": 4900, - "trial_interval": 1, - "trial_interval_unit": "month", - "archived_at": null, - "require_credit_card": true, - "return_params": null, - "taxable": false, - "update_return_url": null, - "tax_code": null, - "initial_charge_after_trial": false, - "version_number": 1, - "update_return_params": null, - "default_product_price_point_id": 32395, - "request_billing_address": false, - "require_billing_address": false, - "require_shipping_address": false, - "use_site_exchange_rate": true, - "item_category": null, - "product_price_point_id": 32395, - "product_price_point_name": "Default", - "product_price_point_handle": "uuid:8c878f50-726e-013c-c71b-0286551bb34f", - "product_family": { - "id": 933860, - "name": "Acme Projects", - "description": "Amazing project management tool", - "handle": "acme-projects", - "accounting_code": null, - "created_at": "2023-12-01T06:56:12-05:00", - "updated_at": "2023-12-01T06:56:12-05:00" - } - } -} -``` - - -# Bulk Create Product Price Points - -Use this endpoint to create multiple product price points in one request. - -```python -def bulk_create_product_price_points(self, - product_id, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `product_id` | `int` | Template, Required | The Advanced Billing id of the product to which the price points belong | -| `body` | [`BulkCreateProductPricePointsRequest`](../../doc/models/bulk-create-product-price-points-request.md) | Body, Optional | - | - -## Response Type - -[`BulkCreateProductPricePointsResponse`](../../doc/models/bulk-create-product-price-points-response.md) +[`BulkCreateProductPricePointsResponse`](../../doc/models/bulk-create-product-price-points-response.md) ## Example Usage @@ -632,16 +480,16 @@ result = product_price_points_controller.bulk_create_product_price_points( | 422 | Unprocessable Entity (WebDAV) | `APIException` | -# Create Product Currency Prices +# Update 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. +This endpoint allows you to update the `price`s of currency prices for a given currency that exists on the product price point. -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. +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 created for custom product price points. +Note: Currency Prices are not able to be updated for custom product price points. ```python -def create_product_currency_prices(self, +def update_product_currency_prices(self, product_price_point_id, body=None) ``` @@ -651,7 +499,7 @@ def create_product_currency_prices(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `product_price_point_id` | `int` | Template, Required | The Advanced Billing id of the product price point | -| `body` | [`CreateProductCurrencyPricesRequest`](../../doc/models/create-product-currency-prices-request.md) | Body, Optional | - | +| `body` | [`UpdateCurrencyPricesRequest`](../../doc/models/update-currency-prices-request.md) | Body, Optional | - | ## Response Type @@ -662,27 +510,20 @@ def create_product_currency_prices(self, ```python product_price_point_id = 234 -body = CreateProductCurrencyPricesRequest( +body = UpdateCurrencyPricesRequest( currency_prices=[ - CreateProductCurrencyPrice( - currency='EUR', - price=60, - role=CurrencyPriceRole.BASELINE - ), - CreateProductCurrencyPrice( - currency='EUR', - price=30, - role=CurrencyPriceRole.TRIAL + UpdateCurrencyPrice( + id=200, + price=15 ), - CreateProductCurrencyPrice( - currency='EUR', - price=100, - role=CurrencyPriceRole.INITIAL + UpdateCurrencyPrice( + id=201, + price=5 ) ] ) -result = product_price_points_controller.create_product_currency_prices( +result = product_price_points_controller.update_product_currency_prices( product_price_point_id, body=body ) @@ -694,9 +535,9 @@ result = product_price_points_controller.create_product_currency_prices( { "currency_prices": [ { - "id": 100, + "id": 123, "currency": "EUR", - "price": 123, + "price": 100, "formatted_price": "€123,00", "product_price_point_id": 32669, "role": "baseline" @@ -712,51 +553,48 @@ result = product_price_points_controller.create_product_currency_prices( | 422 | Unprocessable Entity (WebDAV) | [`ErrorArrayMapResponseException`](../../doc/models/error-array-map-response-exception.md) | -# 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. +# Update 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. +Use this endpoint to update a product price point. -Note: Currency Prices are not able to be updated for custom product price points. +Note: Custom product price points are not able to be updated. ```python -def update_product_currency_prices(self, - product_price_point_id, - body=None) +def update_product_price_point(self, + product_id, + price_point_id, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `product_price_point_id` | `int` | Template, Required | The Advanced Billing id of the product price point | -| `body` | [`UpdateCurrencyPricesRequest`](../../doc/models/update-currency-prices-request.md) | Body, Optional | - | +| `product_id` | int \| str | Template, Required | This is a container for one-of cases. | +| `price_point_id` | int \| str | Template, Required | This is a container for one-of cases. | +| `body` | [`UpdateProductPricePointRequest`](../../doc/models/update-product-price-point-request.md) | Body, Optional | - | ## Response Type -[`CurrencyPricesResponse`](../../doc/models/currency-prices-response.md) +[`ProductPricePointResponse`](../../doc/models/product-price-point-response.md) ## Example Usage ```python -product_price_point_id = 234 +product_id = 124 -body = UpdateCurrencyPricesRequest( - currency_prices=[ - UpdateCurrencyPrice( - id=200, - price=15 - ), - UpdateCurrencyPrice( - id=201, - price=5 - ) - ] +price_point_id = 188 + +body = UpdateProductPricePointRequest( + price_point=UpdateProductPricePoint( + handle='educational', + price_in_cents=1250 + ) ) -result = product_price_points_controller.update_product_currency_prices( - product_price_point_id, +result = product_price_points_controller.update_product_price_point( + product_id, + price_point_id, body=body ) ``` @@ -765,16 +603,88 @@ result = product_price_points_controller.update_product_currency_prices( ```json { - "currency_prices": [ - { - "id": 123, - "currency": "EUR", - "price": 100, - "formatted_price": "€123,00", - "product_price_point_id": 32669, - "role": "baseline" - } - ] + "price_point": { + "id": 283, + "name": "Educational", + "handle": "educational", + "price_in_cents": 1000, + "interval": 1, + "interval_unit": "month", + "trial_price_in_cents": 4900, + "trial_interval": 1, + "trial_interval_unit": "month", + "trial_type": "payment_expected", + "initial_charge_in_cents": 120000, + "initial_charge_after_trial": false, + "expiration_interval": 12, + "expiration_interval_unit": "month", + "product_id": 901, + "archived_at": "2023-11-30T06:37:20-05:00", + "created_at": "2023-11-27T06:37:20-05:00", + "updated_at": "2023-11-27T06:37:20-05:00" + } +} +``` + + +# Archive Product Price Point + +Use this endpoint to archive a product price point. + +```python +def archive_product_price_point(self, + product_id, + price_point_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `product_id` | int \| str | Template, Required | This is a container for one-of cases. | +| `price_point_id` | int \| str | Template, Required | This is a container for one-of cases. | + +## Response Type + +[`ProductPricePointResponse`](../../doc/models/product-price-point-response.md) + +## Example Usage + +```python +product_id = 124 + +price_point_id = 188 + +result = product_price_points_controller.archive_product_price_point( + product_id, + price_point_id +) +``` + +## Example Response *(as JSON)* + +```json +{ + "price_point": { + "id": 283, + "name": "Educational", + "handle": "educational", + "price_in_cents": 1000, + "interval": 1, + "interval_unit": "month", + "trial_price_in_cents": 4900, + "trial_interval": 1, + "trial_interval_unit": "month", + "trial_type": "payment_expected", + "initial_charge_in_cents": 120000, + "initial_charge_after_trial": false, + "expiration_interval": 12, + "expiration_interval_unit": "month", + "product_id": 901, + "archived_at": "2023-11-30T06:37:20-05:00", + "created_at": "2023-11-27T06:37:20-05:00", + "updated_at": "2023-11-27T06:37:20-05:00" + } } ``` @@ -782,7 +692,97 @@ result = product_price_points_controller.update_product_currency_prices( | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorArrayMapResponseException`](../../doc/models/error-array-map-response-exception.md) | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + + +# Promote Product Price Point to Default + +Use this endpoint to make a product price point the default for the product. + +Note: Custom product price points are not able to be set as the default for a product. + +```python +def promote_product_price_point_to_default(self, + product_id, + price_point_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `product_id` | `int` | Template, Required | The Advanced Billing id of the product to which the price point belongs | +| `price_point_id` | `int` | Template, Required | The Advanced Billing id of the product price point | + +## Response Type + +[`ProductResponse`](../../doc/models/product-response.md) + +## Example Usage + +```python +product_id = 202 + +price_point_id = 10 + +result = product_price_points_controller.promote_product_price_point_to_default( + product_id, + price_point_id +) +``` + +## Example Response *(as JSON)* + +```json +{ + "product": { + "id": 29778, + "name": "Educational", + "handle": "educational", + "description": null, + "accounting_code": null, + "request_credit_card": true, + "expiration_interval": 12, + "expiration_interval_unit": "month", + "created_at": "2023-12-01T06:56:12-05:00", + "updated_at": "2023-12-01T06:56:26-05:00", + "price_in_cents": 100, + "interval": 2, + "interval_unit": "month", + "initial_charge_in_cents": 120000, + "trial_price_in_cents": 4900, + "trial_interval": 1, + "trial_interval_unit": "month", + "archived_at": null, + "require_credit_card": true, + "return_params": null, + "taxable": false, + "update_return_url": null, + "tax_code": null, + "initial_charge_after_trial": false, + "version_number": 1, + "update_return_params": null, + "default_product_price_point_id": 32395, + "request_billing_address": false, + "require_billing_address": false, + "require_shipping_address": false, + "use_site_exchange_rate": true, + "item_category": null, + "product_price_point_id": 32395, + "product_price_point_name": "Default", + "product_price_point_handle": "uuid:8c878f50-726e-013c-c71b-0286551bb34f", + "product_family": { + "id": 933860, + "name": "Acme Projects", + "description": "Amazing project management tool", + "handle": "acme-projects", + "accounting_code": null, + "created_at": "2023-12-01T06:56:12-05:00", + "updated_at": "2023-12-01T06:56:12-05:00" + } + } +} +``` # List All Product Price Points diff --git a/doc/controllers/products.md b/doc/controllers/products.md index cc71cfd9..91afe13d 100644 --- a/doc/controllers/products.md +++ b/doc/controllers/products.md @@ -11,10 +11,10 @@ products_controller = client.products ## Methods * [Create Product](../../doc/controllers/products.md#create-product) -* [Read Product](../../doc/controllers/products.md#read-product) * [Update Product](../../doc/controllers/products.md#update-product) * [Archive Product](../../doc/controllers/products.md#archive-product) * [Read Product by Handle](../../doc/controllers/products.md#read-product-by-handle) +* [Read Product](../../doc/controllers/products.md#read-product) * [List Products](../../doc/controllers/products.md#list-products) @@ -124,77 +124,6 @@ result = products_controller.create_product( | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Read Product - -This endpoint allows you to read the current details of a product that you've created in Advanced Billing. - -```python -def read_product(self, - product_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `product_id` | `int` | Template, Required | The Advanced Billing id of the product | - -## Response Type - -[`ProductResponse`](../../doc/models/product-response.md) - -## Example Usage - -```python -product_id = 202 - -result = products_controller.read_product(product_id) -``` - -## Example Response *(as JSON)* - -```json -{ - "product": { - "id": 4535635, - "name": "Paid Annual Seats", - "handle": "paid-annual-seats", - "description": "Paid annual seats for our commercial enterprise product", - "accounting_code": "paid-annual-seats", - "request_credit_card": true, - "expiration_interval": 1, - "expiration_interval_unit": "day", - "created_at": "2017-08-25T10:25:31-05:00", - "updated_at": "2018-01-16T12:58:04-06:00", - "price_in_cents": 10000, - "interval": 12, - "interval_unit": "month", - "initial_charge_in_cents": 4900, - "trial_price_in_cents": 1000, - "trial_interval": 14, - "trial_interval_unit": "day", - "archived_at": null, - "require_credit_card": true, - "return_params": "id={subscription_id}&ref={customer_reference}", - "taxable": true, - "update_return_url": "http://www.example.com", - "tax_code": "D0000000", - "initial_charge_after_trial": false, - "version_number": 4, - "update_return_params": "id={subscription_id}&ref={customer_reference}", - "product_family": { - "id": 1025627, - "name": "Acme Products", - "description": "", - "handle": "acme-products", - "accounting_code": null - }, - "product_price_point_name": "Default" - } -} -``` - - # Update Product Use this method to change aspects of an existing product. @@ -462,6 +391,77 @@ result = products_controller.read_product_by_handle(api_handle) ``` +# Read Product + +This endpoint allows you to read the current details of a product that you've created in Advanced Billing. + +```python +def read_product(self, + product_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `product_id` | `int` | Template, Required | The Advanced Billing id of the product | + +## Response Type + +[`ProductResponse`](../../doc/models/product-response.md) + +## Example Usage + +```python +product_id = 202 + +result = products_controller.read_product(product_id) +``` + +## Example Response *(as JSON)* + +```json +{ + "product": { + "id": 4535635, + "name": "Paid Annual Seats", + "handle": "paid-annual-seats", + "description": "Paid annual seats for our commercial enterprise product", + "accounting_code": "paid-annual-seats", + "request_credit_card": true, + "expiration_interval": 1, + "expiration_interval_unit": "day", + "created_at": "2017-08-25T10:25:31-05:00", + "updated_at": "2018-01-16T12:58:04-06:00", + "price_in_cents": 10000, + "interval": 12, + "interval_unit": "month", + "initial_charge_in_cents": 4900, + "trial_price_in_cents": 1000, + "trial_interval": 14, + "trial_interval_unit": "day", + "archived_at": null, + "require_credit_card": true, + "return_params": "id={subscription_id}&ref={customer_reference}", + "taxable": true, + "update_return_url": "http://www.example.com", + "tax_code": "D0000000", + "initial_charge_after_trial": false, + "version_number": 4, + "update_return_params": "id={subscription_id}&ref={customer_reference}", + "product_family": { + "id": 1025627, + "name": "Acme Products", + "description": "", + "handle": "acme-products", + "accounting_code": null + }, + "product_price_point_name": "Default" + } +} +``` + + # List Products This method allows to retrieve a list of Products belonging to a Site. diff --git a/doc/controllers/proforma-invoices.md b/doc/controllers/proforma-invoices.md index 75e31a20..193a5052 100644 --- a/doc/controllers/proforma-invoices.md +++ b/doc/controllers/proforma-invoices.md @@ -11,14 +11,14 @@ proforma_invoices_controller = client.proforma_invoices ## Methods * [Create Consolidated Proforma Invoice](../../doc/controllers/proforma-invoices.md#create-consolidated-proforma-invoice) -* [List Subscription Group Proforma Invoices](../../doc/controllers/proforma-invoices.md#list-subscription-group-proforma-invoices) -* [Read Proforma Invoice](../../doc/controllers/proforma-invoices.md#read-proforma-invoice) * [Create Proforma Invoice](../../doc/controllers/proforma-invoices.md#create-proforma-invoice) +* [Preview Proforma Invoice](../../doc/controllers/proforma-invoices.md#preview-proforma-invoice) +* [Read Proforma Invoice](../../doc/controllers/proforma-invoices.md#read-proforma-invoice) * [List Proforma Invoices](../../doc/controllers/proforma-invoices.md#list-proforma-invoices) +* [Preview Signup Proforma Invoice](../../doc/controllers/proforma-invoices.md#preview-signup-proforma-invoice) +* [List Subscription Group Proforma Invoices](../../doc/controllers/proforma-invoices.md#list-subscription-group-proforma-invoices) * [Void Proforma Invoice](../../doc/controllers/proforma-invoices.md#void-proforma-invoice) -* [Preview Proforma Invoice](../../doc/controllers/proforma-invoices.md#preview-proforma-invoice) * [Create Signup Proforma Invoice](../../doc/controllers/proforma-invoices.md#create-signup-proforma-invoice) -* [Preview Signup Proforma Invoice](../../doc/controllers/proforma-invoices.md#preview-signup-proforma-invoice) # Create Consolidated Proforma Invoice @@ -61,73 +61,66 @@ proforma_invoices_controller.create_consolidated_proforma_invoice(uid) | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# List Subscription Group Proforma Invoices +# Create Proforma Invoice -Only proforma invoices with a `consolidation_level` of parent are returned. +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. -By default, proforma invoices returned on the index will only include totals, not detailed breakdowns for `line_items`, `discounts`, `taxes`, `credits`, `payments`, `custom_fields`. To include breakdowns, pass the specific field as a key in the query with a value set to true. +If you would like to preview the next billing amounts without generating a full proforma invoice, please 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, must not be prepaid, and must be in a live state. ```python -def list_subscription_group_proforma_invoices(self, - options=dict()) +def create_proforma_invoice(self, + subscription_id) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `uid` | `str` | Template, Required | The uid of the subscription group | -| `line_items` | `bool` | Query, Optional | Include line items data | -| `discounts` | `bool` | Query, Optional | Include discounts data | -| `taxes` | `bool` | Query, Optional | Include taxes data | -| `credits` | `bool` | Query, Optional | Include credits data | -| `payments` | `bool` | Query, Optional | Include payments data | -| `custom_fields` | `bool` | Query, Optional | Include custom fields data | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | ## Response Type -[`ListProformaInvoicesResponse`](../../doc/models/list-proforma-invoices-response.md) +[`ProformaInvoice`](../../doc/models/proforma-invoice.md) ## Example Usage ```python -collect = { - 'uid': 'uid0', - 'line_items': False, - 'discounts': False, - 'taxes': False, - 'credits': False, - 'payments': False, - 'custom_fields': False -} -result = proforma_invoices_controller.list_subscription_group_proforma_invoices(collect) +subscription_id = 222 + +result = proforma_invoices_controller.create_proforma_invoice(subscription_id) ``` ## Errors | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Read Proforma Invoice +# Preview Proforma Invoice -Use this endpoint to read the details of an existing proforma invoice. +Return a preview of the data that will be included on a given subscription's proforma invoice if one were to be generated. It will have similar line items and totals as a renewal preview, but the response will be presented in the format of a proforma invoice. Consequently it will include additional information such as the name and addresses that will appear on the proforma invoice. -## Restrictions +The preview endpoint is subject to all the same conditions as the proforma invoice endpoint. For example, previews are only available on the Relationship Invoicing architecture, and previews cannot be made for end-of-life subscriptions. -Proforma invoices are only available on Relationship Invoicing sites. +If all the data returned in the preview is as expected, you may then create a static proforma invoice and send it to your customer. The data within a preview will not be saved and will not be accessible after the call is made. + +Alternatively, if you have some proforma invoices already, you may make a preview call to determine whether any billing information for the subscription's upcoming renewal has changed. ```python -def read_proforma_invoice(self, - proforma_invoice_uid) +def preview_proforma_invoice(self, + subscription_id) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `proforma_invoice_uid` | `str` | Template, Required | The uid of the proforma invoice | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | ## Response Type @@ -136,9 +129,9 @@ def read_proforma_invoice(self, ## Example Usage ```python -proforma_invoice_uid = 'proforma_invoice_uid4' +subscription_id = 222 -result = proforma_invoices_controller.read_proforma_invoice(proforma_invoice_uid) +result = proforma_invoices_controller.preview_proforma_invoice(subscription_id) ``` ## Errors @@ -146,28 +139,27 @@ result = proforma_invoices_controller.read_proforma_invoice(proforma_invoice_uid | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | | 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Create Proforma Invoice - -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. +# Read Proforma Invoice -If you would like to preview the next billing amounts without generating a full proforma invoice, please use the renewal preview endpoint. +Use this endpoint to read the details of an existing proforma invoice. ## Restrictions -Proforma invoices are only available on Relationship Invoicing sites. To create a proforma invoice, the subscription must not be in a group, must not be prepaid, and must be in a live state. +Proforma invoices are only available on Relationship Invoicing sites. ```python -def create_proforma_invoice(self, - subscription_id) +def read_proforma_invoice(self, + proforma_invoice_uid) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `proforma_invoice_uid` | `str` | Template, Required | The uid of the proforma invoice | ## Response Type @@ -176,16 +168,16 @@ def create_proforma_invoice(self, ## Example Usage ```python -subscription_id = 222 +proforma_invoice_uid = 'proforma_invoice_uid4' -result = proforma_invoices_controller.create_proforma_invoice(subscription_id) +result = proforma_invoices_controller.read_proforma_invoice(proforma_invoice_uid) ``` ## Errors | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +| 404 | Not Found | `APIException` | # List Proforma Invoices @@ -238,82 +230,100 @@ result = proforma_invoices_controller.list_proforma_invoices(collect) ``` -# Void Proforma Invoice - -This endpoint will void a proforma invoice that has the status "draft". +# Preview Signup Proforma Invoice -## Restrictions +This endpoint is only available for Relationship Invoicing sites. It cannot be used to create consolidated proforma invoice previews or preview prepaid subscriptions. -Proforma invoices are only available on Relationship Invoicing sites. +Create a signup preview in the format of a proforma invoice to preview costs before a subscription's signup. You have the option of optionally previewing the first renewal's costs as well. The proforma invoice preview will not be persisted. -Only proforma invoices that have the appropriate status may be reopened. If the invoice identified by {uid} does not have the appropriate status, the response will have HTTP status code 422 and an error message. +Pass a payload that resembles a subscription create or signup preview request. For example, you can specify components, coupons/a referral, offers, custom pricing, and an existing customer or payment profile to populate a shipping or billing address. -A reason for the void operation is required to be included in the request body. If one is not provided, the response will have HTTP status code 422 and an error message. +A product and customer first name, last name, and email are the minimum requirements. ```python -def void_proforma_invoice(self, - proforma_invoice_uid, - body=None) +def preview_signup_proforma_invoice(self, + include=None, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `proforma_invoice_uid` | `str` | Template, Required | The uid of the proforma invoice | -| `body` | [`VoidInvoiceRequest`](../../doc/models/void-invoice-request.md) | Body, Optional | - | +| `include` | [`CreateSignupProformaPreviewInclude`](../../doc/models/create-signup-proforma-preview-include.md) | Query, Optional | Choose to include a proforma invoice preview for the first renewal. Use in query `include=next_proforma_invoice`. | +| `body` | [`CreateSubscriptionRequest`](../../doc/models/create-subscription-request.md) | Body, Optional | - | ## Response Type -[`ProformaInvoice`](../../doc/models/proforma-invoice.md) +[`SignupProformaPreviewResponse`](../../doc/models/signup-proforma-preview-response.md) ## Example Usage ```python -proforma_invoice_uid = 'proforma_invoice_uid4' +body = CreateSubscriptionRequest( + subscription=CreateSubscription( + product_handle='gold-plan', + customer_attributes=CustomerAttributes( + first_name='first', + last_name='last', + email='flast@example.com' + ) + ) +) -result = proforma_invoices_controller.void_proforma_invoice(proforma_invoice_uid) +result = proforma_invoices_controller.preview_signup_proforma_invoice( + body=body +) ``` ## Errors | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - - -# Preview Proforma Invoice +| 400 | Bad Request | [`ProformaBadRequestErrorResponseException`](../../doc/models/proforma-bad-request-error-response-exception.md) | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorArrayMapResponseException`](../../doc/models/error-array-map-response-exception.md) | -Return a preview of the data that will be included on a given subscription's proforma invoice if one were to be generated. It will have similar line items and totals as a renewal preview, but the response will be presented in the format of a proforma invoice. Consequently it will include additional information such as the name and addresses that will appear on the proforma invoice. -The preview endpoint is subject to all the same conditions as the proforma invoice endpoint. For example, previews are only available on the Relationship Invoicing architecture, and previews cannot be made for end-of-life subscriptions. +# List Subscription Group Proforma Invoices -If all the data returned in the preview is as expected, you may then create a static proforma invoice and send it to your customer. The data within a preview will not be saved and will not be accessible after the call is made. +Only proforma invoices with a `consolidation_level` of parent are returned. -Alternatively, if you have some proforma invoices already, you may make a preview call to determine whether any billing information for the subscription's upcoming renewal has changed. +By default, proforma invoices returned on the index will only include totals, not detailed breakdowns for `line_items`, `discounts`, `taxes`, `credits`, `payments`, `custom_fields`. To include breakdowns, pass the specific field as a key in the query with a value set to true. ```python -def preview_proforma_invoice(self, - subscription_id) +def list_subscription_group_proforma_invoices(self, + options=dict()) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `uid` | `str` | Template, Required | The uid of the subscription group | +| `line_items` | `bool` | Query, Optional | Include line items data | +| `discounts` | `bool` | Query, Optional | Include discounts data | +| `taxes` | `bool` | Query, Optional | Include taxes data | +| `credits` | `bool` | Query, Optional | Include credits data | +| `payments` | `bool` | Query, Optional | Include payments data | +| `custom_fields` | `bool` | Query, Optional | Include custom fields data | ## Response Type -[`ProformaInvoice`](../../doc/models/proforma-invoice.md) +[`ListProformaInvoicesResponse`](../../doc/models/list-proforma-invoices-response.md) ## Example Usage ```python -subscription_id = 222 - -result = proforma_invoices_controller.preview_proforma_invoice(subscription_id) +collect = { + 'uid': 'uid0', + 'line_items': False, + 'discounts': False, + 'taxes': False, + 'credits': False, + 'payments': False, + 'custom_fields': False +} +result = proforma_invoices_controller.list_subscription_group_proforma_invoices(collect) ``` ## Errors @@ -321,29 +331,32 @@ result = proforma_invoices_controller.preview_proforma_invoice(subscription_id) | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | | 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Create Signup Proforma Invoice +# Void Proforma Invoice -This endpoint is only available for Relationship Invoicing sites. It cannot be used to create consolidated proforma invoices or preview prepaid subscriptions. +This endpoint will void a proforma invoice that has the status "draft". -Create a proforma invoice to preview costs before a subscription's signup. Like other proforma invoices, it can be emailed to the customer, voided, and publicly viewed on the chargifypay domain. +## Restrictions -Pass a payload that resembles a subscription create or signup preview request. For example, you can specify components, coupons/a referral, offers, custom pricing, and an existing customer or payment profile to populate a shipping or billing address. +Proforma invoices are only available on Relationship Invoicing sites. -A product and customer first name, last name, and email are the minimum requirements. We recommend associating the proforma invoice with a customer_id to easily find their proforma invoices, since the subscription_id will always be blank. +Only proforma invoices that have the appropriate status may be reopened. If the invoice identified by {uid} does not have the appropriate status, the response will have HTTP status code 422 and an error message. + +A reason for the void operation is required to be included in the request body. If one is not provided, the response will have HTTP status code 422 and an error message. ```python -def create_signup_proforma_invoice(self, - body=None) +def void_proforma_invoice(self, + proforma_invoice_uid, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `body` | [`CreateSubscriptionRequest`](../../doc/models/create-subscription-request.md) | Body, Optional | - | +| `proforma_invoice_uid` | `str` | Template, Required | The uid of the proforma invoice | +| `body` | [`VoidInvoiceRequest`](../../doc/models/void-invoice-request.md) | Body, Optional | - | ## Response Type @@ -352,72 +365,59 @@ def create_signup_proforma_invoice(self, ## Example Usage ```python -body = CreateSubscriptionRequest( - subscription=CreateSubscription( - product_handle='gold-product', - customer_attributes=CustomerAttributes( - first_name='Myra', - last_name='Maisel', - email='mmaisel@example.com' - ) - ) -) +proforma_invoice_uid = 'proforma_invoice_uid4' -result = proforma_invoices_controller.create_signup_proforma_invoice( - body=body -) +result = proforma_invoices_controller.void_proforma_invoice(proforma_invoice_uid) ``` ## Errors | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 400 | Bad Request | [`ProformaBadRequestErrorResponseException`](../../doc/models/proforma-bad-request-error-response-exception.md) | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorArrayMapResponseException`](../../doc/models/error-array-map-response-exception.md) | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Preview Signup Proforma Invoice +# Create Signup Proforma Invoice -This endpoint is only available for Relationship Invoicing sites. It cannot be used to create consolidated proforma invoice previews or preview prepaid subscriptions. +This endpoint is only available for Relationship Invoicing sites. It cannot be used to create consolidated proforma invoices or preview prepaid subscriptions. -Create a signup preview in the format of a proforma invoice to preview costs before a subscription's signup. You have the option of optionally previewing the first renewal's costs as well. The proforma invoice preview will not be persisted. +Create a proforma invoice to preview costs before a subscription's signup. Like other proforma invoices, it can be emailed to the customer, voided, and publicly viewed on the chargifypay domain. Pass a payload that resembles a subscription create or signup preview request. For example, you can specify components, coupons/a referral, offers, custom pricing, and an existing customer or payment profile to populate a shipping or billing address. -A product and customer first name, last name, and email are the minimum requirements. +A product and customer first name, last name, and email are the minimum requirements. We recommend associating the proforma invoice with a customer_id to easily find their proforma invoices, since the subscription_id will always be blank. ```python -def preview_signup_proforma_invoice(self, - include=None, - body=None) +def create_signup_proforma_invoice(self, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `include` | [`CreateSignupProformaPreviewInclude`](../../doc/models/create-signup-proforma-preview-include.md) | Query, Optional | Choose to include a proforma invoice preview for the first renewal. Use in query `include=next_proforma_invoice`. | | `body` | [`CreateSubscriptionRequest`](../../doc/models/create-subscription-request.md) | Body, Optional | - | ## Response Type -[`SignupProformaPreviewResponse`](../../doc/models/signup-proforma-preview-response.md) +[`ProformaInvoice`](../../doc/models/proforma-invoice.md) ## Example Usage ```python body = CreateSubscriptionRequest( subscription=CreateSubscription( - product_handle='gold-plan', + product_handle='gold-product', customer_attributes=CustomerAttributes( - first_name='first', - last_name='last', - email='flast@example.com' + first_name='Myra', + last_name='Maisel', + email='mmaisel@example.com' ) ) ) -result = proforma_invoices_controller.preview_signup_proforma_invoice( +result = proforma_invoices_controller.create_signup_proforma_invoice( body=body ) ``` diff --git a/doc/controllers/sales-commissions.md b/doc/controllers/sales-commissions.md index c0e80845..c079327c 100644 --- a/doc/controllers/sales-commissions.md +++ b/doc/controllers/sales-commissions.md @@ -11,8 +11,8 @@ sales_commissions_controller = client.sales_commissions ## Methods * [List Sales Commission Settings](../../doc/controllers/sales-commissions.md#list-sales-commission-settings) -* [List Sales Reps](../../doc/controllers/sales-commissions.md#list-sales-reps) * [Read Sales Rep](../../doc/controllers/sales-commissions.md#read-sales-rep) +* [List Sales Reps](../../doc/controllers/sales-commissions.md#list-sales-reps) # List Sales Commission Settings @@ -93,6 +93,103 @@ result = sales_commissions_controller.list_sales_commission_settings(collect) ``` +# Read Sales Rep + +Endpoint returns sales rep and attached subscriptions details. + +## Modified Authentication Process + +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. + +> Note: The request is at seller level, it means `<>` variable will be replaced by `app` + +```python +def read_sales_rep(self, + seller_id, + sales_rep_id, + authorization='Bearer <>', + live_mode=None, + page=1, + per_page=100) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `seller_id` | `str` | Template, Required | The Chargify id of your seller account | +| `sales_rep_id` | `str` | Template, Required | The Advanced Billing id of sales rep. | +| `authorization` | `str` | Header, Optional | For authorization use user API key. See details [here](https://developers.chargify.com/docs/developer-docs/ZG9jOjMyNzk5NTg0-2020-04-20-new-api-authentication). | +| `live_mode` | `bool` | Query, Optional | This parameter indicates if records should be fetched from live mode sites. Default value is true. | +| `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`. | +| `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request. Default value is 100. | + +## Response Type + +[`SaleRep`](../../doc/models/sale-rep.md) + +## Example Usage + +```python +seller_id = 'seller_id8' + +sales_rep_id = 'sales_rep_id4' + +authorization = 'Bearer <>' + +page = 2 + +per_page = 100 + +result = sales_commissions_controller.read_sales_rep( + seller_id, + sales_rep_id, + authorization=authorization, + page=page, + per_page=per_page +) +``` + +## Example Response *(as JSON)* + +```json +{ + "id": 48, + "full_name": "John Candy", + "subscriptions_count": 2, + "test_mode": true, + "subscriptions": [ + { + "id": 81746, + "site_name": "Chargify", + "subscription_url": "https://chargify9.staging-chargify.com/subscriptions/81746", + "customer_name": "Ziomek Ziomeczek", + "created_at": "2020-01-03T02:36:27-05:00", + "mrr": "$200.00", + "usage": "$0.00", + "recurring": "$200.00", + "last_payment": "2020-04-03T03:40:27-04:00", + "churn_date": null + }, + { + "id": 83790, + "site_name": "Chargify", + "subscription_url": "https://chargify9.staging-chargify.com/subscriptions/83790", + "customer_name": "George Bush", + "created_at": "2020-01-17T07:34:32-05:00", + "mrr": "$200.00", + "usage": "$0.00", + "recurring": "$200.00", + "last_payment": "2020-04-17T08:41:03-04:00", + "churn_date": null + } + ] +} +``` + + # List Sales Reps Endpoint returns sales rep list with details @@ -219,100 +316,3 @@ result = sales_commissions_controller.list_sales_reps(collect) ] ``` - -# Read Sales Rep - -Endpoint returns sales rep and attached subscriptions details. - -## Modified Authentication Process - -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. - -> Note: The request is at seller level, it means `<>` variable will be replaced by `app` - -```python -def read_sales_rep(self, - seller_id, - sales_rep_id, - authorization='Bearer <>', - live_mode=None, - page=1, - per_page=100) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `seller_id` | `str` | Template, Required | The Chargify id of your seller account | -| `sales_rep_id` | `str` | Template, Required | The Advanced Billing id of sales rep. | -| `authorization` | `str` | Header, Optional | For authorization use user API key. See details [here](https://developers.chargify.com/docs/developer-docs/ZG9jOjMyNzk5NTg0-2020-04-20-new-api-authentication). | -| `live_mode` | `bool` | Query, Optional | This parameter indicates if records should be fetched from live mode sites. Default value is true. | -| `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`. | -| `per_page` | `int` | Query, Optional | This parameter indicates how many records to fetch in each request. Default value is 100. | - -## Response Type - -[`SaleRep`](../../doc/models/sale-rep.md) - -## Example Usage - -```python -seller_id = 'seller_id8' - -sales_rep_id = 'sales_rep_id4' - -authorization = 'Bearer <>' - -page = 2 - -per_page = 100 - -result = sales_commissions_controller.read_sales_rep( - seller_id, - sales_rep_id, - authorization=authorization, - page=page, - per_page=per_page -) -``` - -## Example Response *(as JSON)* - -```json -{ - "id": 48, - "full_name": "John Candy", - "subscriptions_count": 2, - "test_mode": true, - "subscriptions": [ - { - "id": 81746, - "site_name": "Chargify", - "subscription_url": "https://chargify9.staging-chargify.com/subscriptions/81746", - "customer_name": "Ziomek Ziomeczek", - "created_at": "2020-01-03T02:36:27-05:00", - "mrr": "$200.00", - "usage": "$0.00", - "recurring": "$200.00", - "last_payment": "2020-04-03T03:40:27-04:00", - "churn_date": null - }, - { - "id": 83790, - "site_name": "Chargify", - "subscription_url": "https://chargify9.staging-chargify.com/subscriptions/83790", - "customer_name": "George Bush", - "created_at": "2020-01-17T07:34:32-05:00", - "mrr": "$200.00", - "usage": "$0.00", - "recurring": "$200.00", - "last_payment": "2020-04-17T08:41:03-04:00", - "churn_date": null - } - ] -} -``` - diff --git a/doc/controllers/subscription-components.md b/doc/controllers/subscription-components.md index faa665a6..97c93deb 100644 --- a/doc/controllers/subscription-components.md +++ b/doc/controllers/subscription-components.md @@ -10,176 +10,23 @@ subscription_components_controller = client.subscription_components ## Methods -* [Read Subscription Component](../../doc/controllers/subscription-components.md#read-subscription-component) -* [List Subscription Components](../../doc/controllers/subscription-components.md#list-subscription-components) * [Bulk Update Subscription Components Price Points](../../doc/controllers/subscription-components.md#bulk-update-subscription-components-price-points) -* [Bulk Reset Subscription Components Price Points](../../doc/controllers/subscription-components.md#bulk-reset-subscription-components-price-points) -* [Allocate Component](../../doc/controllers/subscription-components.md#allocate-component) -* [List Allocations](../../doc/controllers/subscription-components.md#list-allocations) +* [List Usages](../../doc/controllers/subscription-components.md#list-usages) +* [Activate Event Based Component](../../doc/controllers/subscription-components.md#activate-event-based-component) +* [List Subscription Components for Site](../../doc/controllers/subscription-components.md#list-subscription-components-for-site) +* [Read Subscription Component](../../doc/controllers/subscription-components.md#read-subscription-component) * [Allocate Components](../../doc/controllers/subscription-components.md#allocate-components) * [Preview Allocations](../../doc/controllers/subscription-components.md#preview-allocations) +* [Record Event](../../doc/controllers/subscription-components.md#record-event) +* [List Subscription Components](../../doc/controllers/subscription-components.md#list-subscription-components) +* [Allocate Component](../../doc/controllers/subscription-components.md#allocate-component) * [Update Prepaid Usage Allocation Expiration Date](../../doc/controllers/subscription-components.md#update-prepaid-usage-allocation-expiration-date) +* [Bulk Reset Subscription Components Price Points](../../doc/controllers/subscription-components.md#bulk-reset-subscription-components-price-points) +* [List Allocations](../../doc/controllers/subscription-components.md#list-allocations) * [Delete Prepaid Usage Allocation](../../doc/controllers/subscription-components.md#delete-prepaid-usage-allocation) * [Create Usage](../../doc/controllers/subscription-components.md#create-usage) -* [List Usages](../../doc/controllers/subscription-components.md#list-usages) -* [Activate Event Based Component](../../doc/controllers/subscription-components.md#activate-event-based-component) * [Deactivate Event Based Component](../../doc/controllers/subscription-components.md#deactivate-event-based-component) -* [Record Event](../../doc/controllers/subscription-components.md#record-event) * [Bulk Record Events](../../doc/controllers/subscription-components.md#bulk-record-events) -* [List Subscription Components for Site](../../doc/controllers/subscription-components.md#list-subscription-components-for-site) - - -# Read Subscription Component - -This request will list information regarding a specific component owned by a subscription. - -```python -def read_subscription_component(self, - subscription_id, - component_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `component_id` | `int` | Template, Required | The Advanced Billing id of the component. Alternatively, the component's handle prefixed by `handle:` | - -## Response Type - -[`SubscriptionComponentResponse`](../../doc/models/subscription-component-response.md) - -## Example Usage - -```python -subscription_id = 222 - -component_id = 222 - -result = subscription_components_controller.read_subscription_component( - subscription_id, - component_id -) -``` - -## Example Response *(as JSON)* - -```json -{ - "component": { - "component_id": 193028, - "subscription_id": 14593192, - "allocated_quantity": 1, - "pricing_scheme": "per_unit", - "name": "Users", - "kind": "quantity_based_component", - "unit_name": "Users", - "price_point_id": 1, - "price_point_handle": "top-tier", - "enabled": true - } -} -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | - - -# List Subscription Components - -This request will list a subscription's applied components. - -## Archived Components - -When requesting to list components for a given subscription, if the subscription contains **archived** components they will be listed in the server response. - -```python -def list_subscription_components(self, - options=dict()) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `date_field` | [`SubscriptionListDateField`](../../doc/models/subscription-list-date-field.md) | Query, Optional | The type of filter you'd like to apply to your search. Use in query `date_field=updated_at`. | -| `direction` | [`SortingDirection`](../../doc/models/sorting-direction.md) | Query, Optional | Controls the order in which results are returned.
Use in query `direction=asc`. | -| `filter` | [`ListSubscriptionComponentsFilter`](../../doc/models/list-subscription-components-filter.md) | Query, Optional | Filter to use for List Subscription Components operation | -| `end_date` | `str` | Query, Optional | The end date (format YYYY-MM-DD) with which to filter the date_field. Returns components with a timestamp up to and including 11:59:59PM in your site’s time zone on the date specified. | -| `end_datetime` | `str` | Query, Optional | The end date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns components 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. | -| `price_point_ids` | [`IncludeNotNull`](../../doc/models/include-not-null.md) | Query, Optional | Allows fetching components allocation only if price point id is present. Use in query `price_point_ids=not_null`. | -| `product_family_ids` | `List[int]` | Query, Optional | Allows fetching components allocation with matching product family id based on provided ids. Use in query `product_family_ids=1,2,3`. | -| `sort` | [`ListSubscriptionComponentsSort`](../../doc/models/list-subscription-components-sort.md) | Query, Optional | The attribute by which to sort. Use in query `sort=updated_at`. | -| `start_date` | `str` | Query, Optional | The start date (format YYYY-MM-DD) with which to filter the date_field. Returns components with a timestamp at or after midnight (12:00:00 AM) in your site’s time zone on the date specified. | -| `start_datetime` | `str` | Query, Optional | The start date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns components with a timestamp at or after 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 start_date. | -| `include` | [`List[ListSubscriptionComponentsInclude]`](../../doc/models/list-subscription-components-include.md) | Query, Optional | Allows including additional data in the response. Use in query `include=subscription,historic_usages`. | -| `in_use` | `bool` | Query, Optional | If in_use is set to true, it returns only components that are currently in use. However, if it's set to false or not provided, it returns all components connected with the subscription. | - -## Response Type - -[`List[SubscriptionComponentResponse]`](../../doc/models/subscription-component-response.md) - -## Example Usage - -```python -collect = { - 'subscription_id': 222, - 'date_field': SubscriptionListDateField.UPDATED_AT, - 'filter': ListSubscriptionComponentsFilter( - currencies=[ - 'EUR', - 'USD' - ] - ), - 'price_point_ids': IncludeNotNull.NOT_NULL, - 'product_family_ids': [ - 1, - 2, - 3 - ], - 'sort': ListSubscriptionComponentsSort.UPDATED_AT, - 'include': [ - ListSubscriptionComponentsInclude.SUBSCRIPTION, - ListSubscriptionComponentsInclude.HISTORIC_USAGES - ], - 'in_use': True -} -result = subscription_components_controller.list_subscription_components(collect) -``` - -## Example Response *(as JSON)* - -```json -[ - { - "component": { - "component_id": 0, - "subscription_id": 0, - "allocated_quantity": 0, - "pricing_scheme": "per_unit", - "name": "string", - "kind": "quantity_based_component", - "unit_name": "string", - "price_point_id": 0, - "price_point_handle": "string", - "price_point_type": "default", - "price_point_name": "string", - "enabled": true, - "unit_balance": 0, - "id": 0, - "created_at": "2022-02-22T14:07:00-05:00", - "updated_at": "2022-02-22T14:07:00-05:00", - "component_handle": "string", - "archived_at": null - } - } -] -``` # Bulk Update Subscription Components Price Points @@ -261,15 +108,27 @@ result = subscription_components_controller.bulk_update_subscription_components_ | 422 | Unprocessable Entity (WebDAV) | [`ComponentPricePointErrorException`](../../doc/models/component-price-point-error-exception.md) | -# Bulk Reset Subscription Components Price Points +# List Usages -Resets all of a subscription's components to use the current default. +This request will return a list of the usages associated with a subscription for a particular metered component. This will display the previously recorded components for a subscription. -**Note**: this will update the price point for all of the subscription's components, even ones that have not been allocated yet. +This endpoint is not compatible with quantity-based components. + +## Since Date and Until Date Usage + +Note: The `since_date` and `until_date` attributes each default to midnight on the date specified. For example, in order to list usages for January 20th, you would need to append the following to the URL. + +``` +?since_date=2016-01-20&until_date=2016-01-21 +``` + +## Read Usage by Handle + +Use this endpoint to read the previously recorded components for a subscription. You can now specify either the component id (integer) or the component handle prefixed by "handle:" to specify the unique identifier for the component you are working with. ```python -def bulk_reset_subscription_components_price_points(self, - subscription_id) +def list_usages(self, + options=dict()) ``` ## Parameters @@ -277,190 +136,90 @@ def bulk_reset_subscription_components_price_points(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `component_id` | int \| str | Template, Required | This is a container for one-of cases. | +| `since_id` | `long\|int` | Query, Optional | Returns usages with an id greater than or equal to the one specified | +| `max_id` | `long\|int` | Query, Optional | Returns usages with an id less than or equal to the one specified | +| `since_date` | `date` | Query, Optional | Returns usages with a created_at date greater than or equal to midnight (12:00 AM) on the date specified. | +| `until_date` | `date` | Query, Optional | Returns usages with a created_at date less than or equal to midnight (12:00 AM) on the date specified. | +| `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`. | +| `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`. | ## Response Type -[`SubscriptionResponse`](../../doc/models/subscription-response.md) +[`List[UsageResponse]`](../../doc/models/usage-response.md) ## Example Usage ```python -subscription_id = 222 - -result = subscription_components_controller.bulk_reset_subscription_components_price_points(subscription_id) +collect = { + 'subscription_id': 222, + 'component_id': 144, + 'page': 2, + 'per_page': 50 +} +result = subscription_components_controller.list_usages(collect) ``` ## Example Response *(as JSON)* ```json -{ - "subscription": { - "id": 80293620, - "state": "active", - "trial_started_at": null, - "trial_ended_at": null, - "activated_at": "2023-11-23T10:28:34-05:00", - "created_at": "2023-11-23T10:28:34-05:00", - "updated_at": "2023-11-23T10:28:34-05:00", - "expires_at": null, - "balance_in_cents": 50504234, - "current_period_ends_at": "2023-11-23T10:28:34-05:00", - "next_assessment_at": "2023-11-23T10:28:34-05:00", - "canceled_at": null, - "cancellation_message": "lorem ipsum", - "next_product_id": null, - "cancel_at_end_of_period": false, - "payment_collection_method": "remittance", - "snap_day": null, - "cancellation_method": "dunning", - "current_period_started_at": "2023-11-23T10:28:34-05:00", - "previous_state": "active", - "signup_payment_id": -45156092, - "signup_revenue": "do aliquip ea", - "delayed_cancel_at": null, - "coupon_code": null, - "total_revenue_in_cents": -49740952, - "product_price_in_cents": 87617888, - "product_version_number": 13656635, - "payment_type": null, - "referral_code": null, - "coupon_use_count": null, - "coupon_uses_allowed": null, - "reason_code": null, - "automatically_resume_at": null, - "current_billing_amount_in_cents": -26151968, - "customer": { - "id": 15208337, - "first_name": "ipsum culpa in labore eiusmod", - "last_name": "esse", - "organization": null, - "email": "ex eiusmod", - "created_at": "2021-05-05T16:00:21-04:00", - "updated_at": "2021-05-05T16:00:21-04:00", - "reference": "laboris ea cupidatat", - "address": null, - "address_2": null, - "city": "id eiusmod proident", - "state": "magna eiusmod anim non", - "zip": null, - "country": null, - "phone": null, - "portal_invite_last_sent_at": null, - "portal_invite_last_accepted_at": "2021-05-05T20:00:21-04:00", - "portal_customer_created_at": "2021-05-05T16:00:21-04:00", - "cc_emails": "eiusmod sunt", - "tax_exempt": true - }, - "product": { - "id": -74447756, - "name": "eu mollit nulla ut aute", - "handle": "esse dolor anim", - "description": "Lorem ut et non", - "accounting_code": "nisi", - "request_credit_card": false, - "expiration_interval": 1, - "expiration_interval_unit": "day", - "created_at": "2022-11-23T10:28:34-05:00", - "updated_at": "2022-11-23T10:28:34-05:00", - "price_in_cents": -4151649, - "interval": 20680876, - "interval_unit": "day", - "initial_charge_in_cents": null, - "trial_price_in_cents": null, - "trial_interval": null, - "trial_interval_unit": "day", - "archived_at": null, - "require_credit_card": true, - "return_params": "magna eu", - "taxable": true, - "update_return_url": "exercitation in", - "tax_code": "Excepteur aliqua sunt in", - "initial_charge_after_trial": true, - "version_number": 41642597, - "update_return_params": "dolore labore", - "product_family": { - "id": -5356997, - "name": "officia amet Lorem proident enim", - "description": "Duis", - "handle": "ea dolore dolore sunt", - "accounting_code": null - } +[ + { + "usage": { + "id": 178534642, + "memo": "20", + "created_at": "2018-08-03T11:58:42-05:00", + "price_point_id": 242632, + "quantity": "20.0", + "component_id": 500093, + "component_handle": "handle", + "subscription_id": 22824464 + } + }, + { + "usage": { + "id": 178534591, + "memo": "10", + "created_at": "2018-08-03T11:58:29-05:00", + "price_point_id": 242632, + "quantity": "10.0", + "component_id": 500093, + "component_handle": "handle", + "subscription_id": 22824464 } } -} +] ``` -# Allocate Component - -This endpoint creates a new allocation, setting the current allocated quantity for the Component and recording a memo. - -**Notice**: Allocations can only be updated for Quantity, On/Off, and Prepaid Components. - -## Allocations Documentation - -Full documentation on how to record Allocations in the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24251883961485-Component-Allocations-Overview). It is focused on how allocations operate within the Advanced Billing UI.It goes into greater detail on how the user interface will react when recording allocations. - -This documentation also goes into greater detail on how proration is taken into consideration when applying component allocations. - -## Proration Schemes - -Changing the allocated quantity of a component mid-period can result in either a Charge or Credit being applied to the subscription. When creating an allocation via the API, you can pass the `upgrade_charge`, `downgrade_credit`, and `accrue_charge` to be applied. - -**Notice:** These proration and accural fields will be ignored for Prepaid Components since this component type always generate charges immediately without proration. - -For background information on prorated components and upgrade/downgrade schemes, see [Setting Component Allocations.](https://maxio.zendesk.com/hc/en-us/articles/24251906165133-Component-Allocations-Proration). -See the tables below for valid values. - -| upgrade_charge | Definition                                                        | -|----------------|-------------------------------------------------------------------| -| `full`         | A charge is added for the full price of the component.            | -| `prorated`     | A charge is added for the prorated price of the component change. | -| `none`         | No charge is added.                                               | - -| downgrade_credit | Definition                                        | -|------------------|---------------------------------------------------| -| `full`           | A full price credit is added for the amount owed. | -| `prorated`       | A prorated credit is added for the amount owed.   | -| `none`           | No charge is added.                               | - -| accrue_charge | Definition                                                                                               | -|---------------|------------------------------------------------------------------------------------------------------------| -| `true`        | Attempt to charge the customer at next renewal. | -| `false`       | Attempt to charge the customer right away. If it fails, the charge will be accrued until the next renewal. | - -### Order of Resolution for upgrade_charge and downgrade_credit +# Activate Event Based Component -1. Per allocation in API call (within a single allocation of the `allocations` array) -2. [Component-level default value](https://maxio.zendesk.com/hc/en-us/articles/24251883961485-Component-Allocations-Overview) -3. Allocation API call top level (outside of the `allocations` array) -4. [Site-level default value](https://maxio.zendesk.com/hc/en-us/articles/24251906165133-Component-Allocations-Proration#proration-schemes) +In order to bill your subscribers on your Events data under the Events-Based Billing feature, the components must be activated for the subscriber. -### Order of Resolution for accrue charge +Learn more about the role of activation in the [Events-Based Billing docs](https://maxio.zendesk.com/hc/en-us/articles/24260323329805-Events-Based-Billing-Overview). -1. Allocation API call top level (outside of the `allocations` array) -2. [Site-level default value](https://maxio.zendesk.com/hc/en-us/articles/24251906165133-Component-Allocations-Proration#proration-schemes) +Use this endpoint to activate an event-based component for a single subscription. Activating an event-based component causes Advanced Billing to bill for events when the subscription is renewed. -**NOTE: Proration uses the current price of the component as well as the current tax rates. Changes to either may cause the prorated charge/credit to be wrong.** +*Note: it is possible to stream events for a subscription at any time, regardless of component activation status. The activation status only determines if the subscription should be billed for event-based component usage at renewal.* ```python -def allocate_component(self, - subscription_id, - component_id, - body=None) +def activate_event_based_component(self, + subscription_id, + component_id, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `subscription_id` | `int` | Template, Required | The Advanced Billing id of the subscription | | `component_id` | `int` | Template, Required | The Advanced Billing id of the component | -| `body` | [`CreateAllocationRequest`](../../doc/models/create-allocation-request.md) | Body, Optional | - | +| `body` | [`ActivateEventBasedComponent`](../../doc/models/activate-event-based-component.md) | Body, Optional | - | ## Response Type -[`AllocationResponse`](../../doc/models/allocation-response.md) +`void` ## Example Usage @@ -469,83 +228,104 @@ subscription_id = 222 component_id = 222 -body = CreateAllocationRequest( - allocation=CreateAllocation( - quantity=5, - memo='Recoding component purchase of Acme Support' +body = ActivateEventBasedComponent( + price_point_id=1, + billing_schedule=BillingSchedule( + initial_billing_at=dateutil.parser.parse('2022-01-01').date() + ), + custom_price=ComponentCustomPrice( + prices=[ + Price( + starting_quantity=1, + unit_price='5.0' + ) + ], + tax_included=False, + pricing_scheme=PricingScheme.PER_UNIT, + interval=30, + interval_unit=IntervalUnit.DAY ) ) -result = subscription_components_controller.allocate_component( +subscription_components_controller.activate_event_based_component( subscription_id, component_id, body=body ) ``` -## Example Response *(as JSON)* -```json -{ - "allocation": { - "component_id": 4034995, - "subscription_id": 23737320, - "quantity": 3, - "previous_quantity": 2, - "memo": "dolore cupidatat elit", - "timestamp": "2022-11-23T10:28:34-05:00", - "proration_upgrade_scheme": "laboris ipsum dolore", - "proration_downgrade_scheme": "eiusmod dolore", - "price_point_id": -69720370, - "previous_price_point_id": -76493052, - "accrue_charge": true, - "upgrade_charge": "full", - "downgrade_credit": "full", - "payment": { - "id": -44566528, - "amount_in_cents": 123, - "success": false, - "memo": "aliqua" - } - } -} -``` +# List Subscription Components for Site -## Errors +This request will list components applied to each subscription. -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +```python +def list_subscription_components_for_site(self, + options=dict()) +``` +## Parameters -# List Allocations +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `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`. | +| `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`. | +| `sort` | [`ListSubscriptionComponentsSort`](../../doc/models/list-subscription-components-sort.md) | Query, Optional | The attribute by which to sort. Use in query: `sort=updated_at`. | +| `direction` | [`SortingDirection`](../../doc/models/sorting-direction.md) | Query, Optional | Controls the order in which results are returned.
Use in query `direction=asc`. | +| `filter` | [`ListSubscriptionComponentsForSiteFilter`](../../doc/models/list-subscription-components-for-site-filter.md) | Query, Optional | Filter to use for List Subscription Components For Site operation | +| `date_field` | [`SubscriptionListDateField`](../../doc/models/subscription-list-date-field.md) | Query, Optional | The type of filter you'd like to apply to your search. Use in query: `date_field=updated_at`. | +| `start_date` | `str` | Query, Optional | The start date (format YYYY-MM-DD) with which to filter the date_field. Returns components with a timestamp at or after midnight (12:00:00 AM) in your site’s time zone on the date specified. Use in query `start_date=2011-12-15`. | +| `start_datetime` | `str` | Query, Optional | The start date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns components with a timestamp at or after 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 start_date. Use in query `start_datetime=2022-07-01 09:00:05`. | +| `end_date` | `str` | Query, Optional | The end date (format YYYY-MM-DD) with which to filter the date_field. Returns components with a timestamp up to and including 11:59:59PM in your site’s time zone on the date specified. Use in query `end_date=2011-12-16`. | +| `end_datetime` | `str` | Query, Optional | The end date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns components 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 `end_datetime=2022-07-01 09:00:05`. | +| `subscription_ids` | `List[int]` | Query, Optional | Allows fetching components allocation with matching subscription id based on provided ids. Use in query `subscription_ids=1,2,3`. | +| `price_point_ids` | [`IncludeNotNull`](../../doc/models/include-not-null.md) | Query, Optional | Allows fetching components allocation only if price point id is present. Use in query `price_point_ids=not_null`. | +| `product_family_ids` | `List[int]` | Query, Optional | Allows fetching components allocation with matching product family id based on provided ids. Use in query `product_family_ids=1,2,3`. | +| `include` | [`ListSubscriptionComponentsInclude`](../../doc/models/list-subscription-components-include.md) | Query, Optional | Allows including additional data in the response. Use in query `include=subscription,historic_usages`. | -This endpoint returns the 50 most recent Allocations, ordered by most recent first. +## Response Type -## On/Off Components +[`ListSubscriptionComponentsResponse`](../../doc/models/list-subscription-components-response.md) -When a subscription's on/off component has been toggled to on (`1`) or off (`0`), usage will be logged in this response. +## Example Usage -## Querying data via Advanced Billing gem +```python +collect = { + 'page': 2, + 'per_page': 50, + 'sort': ListSubscriptionComponentsSort.UPDATED_AT, + 'filter': ListSubscriptionComponentsForSiteFilter( + currencies=[ + 'EUR', + 'USD' + ] + ), + 'date_field': SubscriptionListDateField.UPDATED_AT, + 'subscription_ids': [ + 1, + 2, + 3 + ], + 'price_point_ids': IncludeNotNull.NOT_NULL, + 'product_family_ids': [ + 1, + 2, + 3 + ], + 'include': ListSubscriptionComponentsInclude.SUBSCRIPTION +} +result = subscription_components_controller.list_subscription_components_for_site(collect) +``` -You can also query the current quantity via the [official Advanced Billing Gem.](http://github.com/chargify/chargify_api_ares) -```# First way -component = Chargify::Subscription::Component.find(1, :params => {:subscription_id => 7}) -puts component.allocated_quantity -# => 23 +# Read Subscription Component -# Second way -component = Chargify::Subscription.find(7).component(1) -puts component.allocated_quantity -# => 23 -``` +This request will list information regarding a specific component owned by a subscription. ```python -def list_allocations(self, - subscription_id, - component_id, - page=1) +def read_subscription_component(self, + subscription_id, + component_id) ``` ## Parameters @@ -553,12 +333,11 @@ def list_allocations(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `component_id` | `int` | Template, Required | The Advanced Billing id of the component | -| `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`. | +| `component_id` | `int` | Template, Required | The Advanced Billing id of the component. Alternatively, the component's handle prefixed by `handle:` | ## Response Type -[`List[AllocationResponse]`](../../doc/models/allocation-response.md) +[`SubscriptionComponentResponse`](../../doc/models/subscription-component-response.md) ## Example Usage @@ -567,58 +346,29 @@ subscription_id = 222 component_id = 222 -page = 2 - -result = subscription_components_controller.list_allocations( +result = subscription_components_controller.read_subscription_component( subscription_id, - component_id, - page=page + component_id ) ``` ## Example Response *(as JSON)* ```json -[ - { - "allocation": { - "allocation_id": 2370199, - "component_id": 41028, - "subscription_id": 352827, - "quantity": 10, - "previous_quantity": 0, - "memo": "Recoding component allocation", - "timestamp": "2024-02-28T09:31:05Z", - "proration_upgrade_scheme": "full-price-attempt-capture", - "proration_downgrade_scheme": "no-prorate", - "price_point_id": 2957424, - "price_point_handle": "uuid:03190e20-b84a-013c-ca77-0286551bb34f", - "price_point_name": "Original", - "previous_price_point_id": 2957424, - "component_handle": "test-prepaid-component-4982065948", - "accrue_charge": false, - "upgrade_charge": "full", - "downgrade_credit": "none", - "created_at": "2024-02-28T04:31:05-05:00", - "initiate_dunning": false, - "expires_at": "2024-08-03T20:00:00-04:00", - "used_quantity": 5, - "charge_id": 11586076 - } - }, - { - "allocation": { - "memo": null, - "timestamp": "2012-11-20T21:48:09Z", - "quantity": 3, - "previous_quantity": 0, - "component_id": 11960, - "subscription_id": 2585595, - "proration_upgrade_scheme": "no-prorate", - "proration_downgrade_scheme": "no-prorate" - } +{ + "component": { + "component_id": 193028, + "subscription_id": 14593192, + "allocated_quantity": 1, + "pricing_scheme": "per_unit", + "name": "Users", + "kind": "quantity_based_component", + "unit_name": "Users", + "price_point_id": 1, + "price_point_handle": "top-tier", + "enabled": true } -] +} ``` ## Errors @@ -626,7 +376,6 @@ result = subscription_components_controller.list_allocations( | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | | 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | # Allocate Components @@ -888,33 +637,228 @@ result = subscription_components_controller.preview_allocations( } ``` -## Errors +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ComponentAllocationErrorException`](../../doc/models/component-allocation-error-exception.md) | + + +# Record Event + +## Documentation + +Events-Based Billing is an evolved form of metered billing that is based on data-rich events streamed in real-time from your system to Advanced Billing. + +These events can then be transformed, enriched, or analyzed to form the computed totals of usage charges billed to your customers. + +This API allows you to stream events into the Advanced Billing data ingestion engine. + +Learn more about the feature in general in the [Events-Based Billing help docs](https://maxio.zendesk.com/hc/en-us/articles/24260323329805-Events-Based-Billing-Overview). + +## Record Event + +Use this endpoint to record a single event. + +*Note: this endpoint differs from the standard Chargify API endpoints in that the URL subdomain will be `events` and your site subdomain will be included in the URL path. For example:* + +``` +https://events.chargify.com/my-site-subdomain/events/my-stream-api-handle +``` + +```python +def record_event(self, + subdomain, + api_handle, + store_uid=None, + body=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subdomain` | `str` | Template, Required | Your site's subdomain | +| `api_handle` | `str` | Template, Required | Identifies the Stream for which the event should be published. | +| `store_uid` | `str` | Query, Optional | If you've attached your own Keen project as an Advanced Billing event data-store, use this parameter to indicate the data-store. | +| `body` | [`EBBEvent`](../../doc/models/ebb-event.md) | Body, Optional | - | + +## Response Type + +`void` + +## Example Usage + +```python +subdomain = 'subdomain4' + +api_handle = 'api_handle6' + +body = EBBEvent( + chargify=ChargifyEBB( + timestamp=dateutil.parser.parse('2020-02-27T17:45:50-05:00'), + subscription_id=1 + ) +) + +subscription_components_controller.record_event( + subdomain, + api_handle, + body=body +) +``` + + +# List Subscription Components + +This request will list a subscription's applied components. + +## Archived Components + +When requesting to list components for a given subscription, if the subscription contains **archived** components they will be listed in the server response. + +```python +def list_subscription_components(self, + options=dict()) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `date_field` | [`SubscriptionListDateField`](../../doc/models/subscription-list-date-field.md) | Query, Optional | The type of filter you'd like to apply to your search. Use in query `date_field=updated_at`. | +| `direction` | [`SortingDirection`](../../doc/models/sorting-direction.md) | Query, Optional | Controls the order in which results are returned.
Use in query `direction=asc`. | +| `filter` | [`ListSubscriptionComponentsFilter`](../../doc/models/list-subscription-components-filter.md) | Query, Optional | Filter to use for List Subscription Components operation | +| `end_date` | `str` | Query, Optional | The end date (format YYYY-MM-DD) with which to filter the date_field. Returns components with a timestamp up to and including 11:59:59PM in your site’s time zone on the date specified. | +| `end_datetime` | `str` | Query, Optional | The end date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns components 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. | +| `price_point_ids` | [`IncludeNotNull`](../../doc/models/include-not-null.md) | Query, Optional | Allows fetching components allocation only if price point id is present. Use in query `price_point_ids=not_null`. | +| `product_family_ids` | `List[int]` | Query, Optional | Allows fetching components allocation with matching product family id based on provided ids. Use in query `product_family_ids=1,2,3`. | +| `sort` | [`ListSubscriptionComponentsSort`](../../doc/models/list-subscription-components-sort.md) | Query, Optional | The attribute by which to sort. Use in query `sort=updated_at`. | +| `start_date` | `str` | Query, Optional | The start date (format YYYY-MM-DD) with which to filter the date_field. Returns components with a timestamp at or after midnight (12:00:00 AM) in your site’s time zone on the date specified. | +| `start_datetime` | `str` | Query, Optional | The start date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns components with a timestamp at or after 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 start_date. | +| `include` | [`List[ListSubscriptionComponentsInclude]`](../../doc/models/list-subscription-components-include.md) | Query, Optional | Allows including additional data in the response. Use in query `include=subscription,historic_usages`. | +| `in_use` | `bool` | Query, Optional | If in_use is set to true, it returns only components that are currently in use. However, if it's set to false or not provided, it returns all components connected with the subscription. | + +## Response Type + +[`List[SubscriptionComponentResponse]`](../../doc/models/subscription-component-response.md) + +## Example Usage + +```python +collect = { + 'subscription_id': 222, + 'date_field': SubscriptionListDateField.UPDATED_AT, + 'filter': ListSubscriptionComponentsFilter( + currencies=[ + 'EUR', + 'USD' + ] + ), + 'price_point_ids': IncludeNotNull.NOT_NULL, + 'product_family_ids': [ + 1, + 2, + 3 + ], + 'sort': ListSubscriptionComponentsSort.UPDATED_AT, + 'include': [ + ListSubscriptionComponentsInclude.SUBSCRIPTION, + ListSubscriptionComponentsInclude.HISTORIC_USAGES + ], + 'in_use': True +} +result = subscription_components_controller.list_subscription_components(collect) +``` + +## Example Response *(as JSON)* -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ComponentAllocationErrorException`](../../doc/models/component-allocation-error-exception.md) | +```json +[ + { + "component": { + "component_id": 0, + "subscription_id": 0, + "allocated_quantity": 0, + "pricing_scheme": "per_unit", + "name": "string", + "kind": "quantity_based_component", + "unit_name": "string", + "price_point_id": 0, + "price_point_handle": "string", + "price_point_type": "default", + "price_point_name": "string", + "enabled": true, + "unit_balance": 0, + "id": 0, + "created_at": "2022-02-22T14:07:00-05:00", + "updated_at": "2022-02-22T14:07:00-05:00", + "component_handle": "string", + "archived_at": null + } + } +] +``` -# Update Prepaid Usage Allocation Expiration Date +# Allocate Component -When the expiration interval options are selected on a prepaid usage component price point, all allocations will be created with an expiration date. This expiration date can be changed after the fact to allow for extending or shortening the allocation's active window. +This endpoint creates a new allocation, setting the current allocated quantity for the Component and recording a memo. -In order to change a prepaid usage allocation's expiration date, a PUT call must be made to the allocation's endpoint with a new expiration date. +**Notice**: Allocations can only be updated for Quantity, On/Off, and Prepaid Components. -## Limitations +## Allocations Documentation -A few limitations exist when changing an allocation's expiration date: +Full documentation on how to record Allocations in the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24251883961485-Component-Allocations-Overview). It is focused on how allocations operate within the Advanced Billing UI.It goes into greater detail on how the user interface will react when recording allocations. -- An expiration date can only be changed for an allocation that belongs to a price point with expiration interval options explicitly set. -- An expiration date can be changed towards the future with no limitations. -- An expiration date can be changed towards the past (essentially expiring it) up to the subscription's current period beginning date. +This documentation also goes into greater detail on how proration is taken into consideration when applying component allocations. + +## Proration Schemes + +Changing the allocated quantity of a component mid-period can result in either a Charge or Credit being applied to the subscription. When creating an allocation via the API, you can pass the `upgrade_charge`, `downgrade_credit`, and `accrue_charge` to be applied. + +**Notice:** These proration and accural fields will be ignored for Prepaid Components since this component type always generate charges immediately without proration. + +For background information on prorated components and upgrade/downgrade schemes, see [Setting Component Allocations.](https://maxio.zendesk.com/hc/en-us/articles/24251906165133-Component-Allocations-Proration). +See the tables below for valid values. + +| upgrade_charge | Definition                                                        | +|----------------|-------------------------------------------------------------------| +| `full`         | A charge is added for the full price of the component.            | +| `prorated`     | A charge is added for the prorated price of the component change. | +| `none`         | No charge is added.                                               | + +| downgrade_credit | Definition                                        | +|------------------|---------------------------------------------------| +| `full`           | A full price credit is added for the amount owed. | +| `prorated`       | A prorated credit is added for the amount owed.   | +| `none`           | No charge is added.                               | + +| accrue_charge | Definition                                                                                               | +|---------------|------------------------------------------------------------------------------------------------------------| +| `true`        | Attempt to charge the customer at next renewal. | +| `false`       | Attempt to charge the customer right away. If it fails, the charge will be accrued until the next renewal. | + +### Order of Resolution for upgrade_charge and downgrade_credit + +1. Per allocation in API call (within a single allocation of the `allocations` array) +2. [Component-level default value](https://maxio.zendesk.com/hc/en-us/articles/24251883961485-Component-Allocations-Overview) +3. Allocation API call top level (outside of the `allocations` array) +4. [Site-level default value](https://maxio.zendesk.com/hc/en-us/articles/24251906165133-Component-Allocations-Proration#proration-schemes) + +### Order of Resolution for accrue charge + +1. Allocation API call top level (outside of the `allocations` array) +2. [Site-level default value](https://maxio.zendesk.com/hc/en-us/articles/24251906165133-Component-Allocations-Proration#proration-schemes) + +**NOTE: Proration uses the current price of the component as well as the current tax rates. Changes to either may cause the prorated charge/credit to be wrong.** ```python -def update_prepaid_usage_allocation_expiration_date(self, - subscription_id, - component_id, - allocation_id, - body=None) +def allocate_component(self, + subscription_id, + component_id, + body=None) ``` ## Parameters @@ -923,12 +867,11 @@ def update_prepaid_usage_allocation_expiration_date(self, | --- | --- | --- | --- | | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | | `component_id` | `int` | Template, Required | The Advanced Billing id of the component | -| `allocation_id` | `int` | Template, Required | The Advanced Billing id of the allocation | -| `body` | [`UpdateAllocationExpirationDate`](../../doc/models/update-allocation-expiration-date.md) | Body, Optional | - | +| `body` | [`CreateAllocationRequest`](../../doc/models/create-allocation-request.md) | Body, Optional | - | ## Response Type -`void` +[`AllocationResponse`](../../doc/models/allocation-response.md) ## Example Usage @@ -937,48 +880,75 @@ subscription_id = 222 component_id = 222 -allocation_id = 24 - -body = UpdateAllocationExpirationDate( - allocation=AllocationExpirationDate( - expires_at=dateutil.parser.parse('2021-05-05T16:00:00') +body = CreateAllocationRequest( + allocation=CreateAllocation( + quantity=5, + memo='Recoding component purchase of Acme Support' ) ) -subscription_components_controller.update_prepaid_usage_allocation_expiration_date( +result = subscription_components_controller.allocate_component( subscription_id, component_id, - allocation_id, body=body ) ``` +## Example Response *(as JSON)* + +```json +{ + "allocation": { + "component_id": 4034995, + "subscription_id": 23737320, + "quantity": 3, + "previous_quantity": 2, + "memo": "dolore cupidatat elit", + "timestamp": "2022-11-23T10:28:34-05:00", + "proration_upgrade_scheme": "laboris ipsum dolore", + "proration_downgrade_scheme": "eiusmod dolore", + "price_point_id": -69720370, + "previous_price_point_id": -76493052, + "accrue_charge": true, + "upgrade_charge": "full", + "downgrade_credit": "full", + "payment": { + "id": -44566528, + "amount_in_cents": 123, + "success": false, + "memo": "aliqua" + } + } +} +``` + ## Errors | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`SubscriptionComponentAllocationErrorException`](../../doc/models/subscription-component-allocation-error-exception.md) | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Delete Prepaid Usage Allocation +# Update Prepaid Usage Allocation Expiration Date -Prepaid Usage components are unique in that their allocations are always additive. In order to reduce a subscription's allocated quantity for a prepaid usage component each allocation must be destroyed individually via this endpoint. +When the expiration interval options are selected on a prepaid usage component price point, all allocations will be created with an expiration date. This expiration date can be changed after the fact to allow for extending or shortening the allocation's active window. -## Credit Scheme +In order to change a prepaid usage allocation's expiration date, a PUT call must be made to the allocation's endpoint with a new expiration date. -By default, destroying an allocation will generate a service credit on the subscription. This behavior can be modified with the optional `credit_scheme` parameter on this endpoint. The accepted values are: +## Limitations -1. `none`: The allocation will be destroyed and the balances will be updated but no service credit or refund will be created. -2. `credit`: The allocation will be destroyed and the balances will be updated and a service credit will be generated. This is also the default behavior if the `credit_scheme` param is not passed. -3. `refund`: The allocation will be destroyed and the balances will be updated and a refund will be issued along with a Credit Note. +A few limitations exist when changing an allocation's expiration date: + +- An expiration date can only be changed for an allocation that belongs to a price point with expiration interval options explicitly set. +- An expiration date can be changed towards the future with no limitations. +- An expiration date can be changed towards the past (essentially expiring it) up to the subscription's current period beginning date. ```python -def delete_prepaid_usage_allocation(self, - subscription_id, - component_id, - allocation_id, - body=None) +def update_prepaid_usage_allocation_expiration_date(self, + subscription_id, + component_id, + allocation_id, + body=None) ``` ## Parameters @@ -988,7 +958,7 @@ def delete_prepaid_usage_allocation(self, | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | | `component_id` | `int` | Template, Required | The Advanced Billing id of the component | | `allocation_id` | `int` | Template, Required | The Advanced Billing id of the allocation | -| `body` | [`CreditSchemeRequest`](../../doc/models/credit-scheme-request.md) | Body, Optional | - | +| `body` | [`UpdateAllocationExpirationDate`](../../doc/models/update-allocation-expiration-date.md) | Body, Optional | - | ## Response Type @@ -1003,11 +973,13 @@ component_id = 222 allocation_id = 24 -body = CreditSchemeRequest( - credit_scheme=CreditScheme.NONE +body = UpdateAllocationExpirationDate( + allocation=AllocationExpirationDate( + expires_at=dateutil.parser.parse('2021-05-05T16:00:00') + ) ) -subscription_components_controller.delete_prepaid_usage_allocation( +subscription_components_controller.update_prepaid_usage_allocation_expiration_date( subscription_id, component_id, allocation_id, @@ -1023,70 +995,15 @@ subscription_components_controller.delete_prepaid_usage_allocation( | 422 | Unprocessable Entity (WebDAV) | [`SubscriptionComponentAllocationErrorException`](../../doc/models/subscription-component-allocation-error-exception.md) | -# Create Usage - -## Documentation - -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: - -+ [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) - -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 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. - -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. - -Example: - -Previously recorded: - -```json -{ - "usage": { - "quantity": 5000, - "memo": "Recording 5000 units" - } -} -``` - -At this point, `unit_balance` would be `5000`. To reduce the balance to `0`, POST the following payload: - -```json -{ - "usage": { - "quantity": -5000, - "memo": "Deducting 5000 units" - } -} -``` - -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 +# Bulk Reset Subscription Components Price Points -Q. Is it possible to record metered usage for more than one component at a time? +Resets all of a subscription's components to use the current default. -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. +**Note**: this will update the price point for all of the subscription's components, even ones that have not been allocated yet. ```python -def create_usage(self, - subscription_id, - component_id, - body=None) +def bulk_reset_subscription_components_price_points(self, + subscription_id) ``` ## Parameters @@ -1094,80 +1011,148 @@ def create_usage(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `component_id` | int \| str | Template, Required | This is a container for one-of cases. | -| `body` | [`CreateUsageRequest`](../../doc/models/create-usage-request.md) | Body, Optional | - | ## Response Type -[`UsageResponse`](../../doc/models/usage-response.md) +[`SubscriptionResponse`](../../doc/models/subscription-response.md) ## Example Usage -```python -subscription_id = 222 - -component_id = 144 - -body = CreateUsageRequest( - usage=CreateUsage( - quantity=1000, - price_point_id='149416', - memo='My memo' - ) -) +```python +subscription_id = 222 -result = subscription_components_controller.create_usage( - subscription_id, - component_id, - body=body -) +result = subscription_components_controller.bulk_reset_subscription_components_price_points(subscription_id) ``` ## Example Response *(as JSON)* ```json { - "usage": { - "id": 138522957, - "memo": "My memo", - "created_at": "2017-11-13T10:05:32-06:00", - "price_point_id": 149416, - "quantity": 1000, - "component_id": 500093, - "component_handle": "handle", - "subscription_id": 22824464 + "subscription": { + "id": 80293620, + "state": "active", + "trial_started_at": null, + "trial_ended_at": null, + "activated_at": "2023-11-23T10:28:34-05:00", + "created_at": "2023-11-23T10:28:34-05:00", + "updated_at": "2023-11-23T10:28:34-05:00", + "expires_at": null, + "balance_in_cents": 50504234, + "current_period_ends_at": "2023-11-23T10:28:34-05:00", + "next_assessment_at": "2023-11-23T10:28:34-05:00", + "canceled_at": null, + "cancellation_message": "lorem ipsum", + "next_product_id": null, + "cancel_at_end_of_period": false, + "payment_collection_method": "remittance", + "snap_day": null, + "cancellation_method": "dunning", + "current_period_started_at": "2023-11-23T10:28:34-05:00", + "previous_state": "active", + "signup_payment_id": -45156092, + "signup_revenue": "do aliquip ea", + "delayed_cancel_at": null, + "coupon_code": null, + "total_revenue_in_cents": -49740952, + "product_price_in_cents": 87617888, + "product_version_number": 13656635, + "payment_type": null, + "referral_code": null, + "coupon_use_count": null, + "coupon_uses_allowed": null, + "reason_code": null, + "automatically_resume_at": null, + "current_billing_amount_in_cents": -26151968, + "customer": { + "id": 15208337, + "first_name": "ipsum culpa in labore eiusmod", + "last_name": "esse", + "organization": null, + "email": "ex eiusmod", + "created_at": "2021-05-05T16:00:21-04:00", + "updated_at": "2021-05-05T16:00:21-04:00", + "reference": "laboris ea cupidatat", + "address": null, + "address_2": null, + "city": "id eiusmod proident", + "state": "magna eiusmod anim non", + "zip": null, + "country": null, + "phone": null, + "portal_invite_last_sent_at": null, + "portal_invite_last_accepted_at": "2021-05-05T20:00:21-04:00", + "portal_customer_created_at": "2021-05-05T16:00:21-04:00", + "cc_emails": "eiusmod sunt", + "tax_exempt": true + }, + "product": { + "id": -74447756, + "name": "eu mollit nulla ut aute", + "handle": "esse dolor anim", + "description": "Lorem ut et non", + "accounting_code": "nisi", + "request_credit_card": false, + "expiration_interval": 1, + "expiration_interval_unit": "day", + "created_at": "2022-11-23T10:28:34-05:00", + "updated_at": "2022-11-23T10:28:34-05:00", + "price_in_cents": -4151649, + "interval": 20680876, + "interval_unit": "day", + "initial_charge_in_cents": null, + "trial_price_in_cents": null, + "trial_interval": null, + "trial_interval_unit": "day", + "archived_at": null, + "require_credit_card": true, + "return_params": "magna eu", + "taxable": true, + "update_return_url": "exercitation in", + "tax_code": "Excepteur aliqua sunt in", + "initial_charge_after_trial": true, + "version_number": 41642597, + "update_return_params": "dolore labore", + "product_family": { + "id": -5356997, + "name": "officia amet Lorem proident enim", + "description": "Duis", + "handle": "ea dolore dolore sunt", + "accounting_code": null + } + } } } ``` -## Errors -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +# List Allocations +This endpoint returns the 50 most recent Allocations, ordered by most recent first. -# List Usages +## On/Off Components -This request will return a list of the usages associated with a subscription for a particular metered component. This will display the previously recorded components for a subscription. +When a subscription's on/off component has been toggled to on (`1`) or off (`0`), usage will be logged in this response. -This endpoint is not compatible with quantity-based components. +## Querying data via Advanced Billing gem -## Since Date and Until Date Usage +You can also query the current quantity via the [official Advanced Billing Gem.](http://github.com/chargify/chargify_api_ares) -Note: The `since_date` and `until_date` attributes each default to midnight on the date specified. For example, in order to list usages for January 20th, you would need to append the following to the URL. +```# First way +component = Chargify::Subscription::Component.find(1, :params => {:subscription_id => 7}) +puts component.allocated_quantity +# => 23 +# Second way +component = Chargify::Subscription.find(7).component(1) +puts component.allocated_quantity +# => 23 ``` -?since_date=2016-01-20&until_date=2016-01-21 -``` - -## Read Usage by Handle - -Use this endpoint to read the previously recorded components for a subscription. You can now specify either the component id (integer) or the component handle prefixed by "handle:" to specify the unique identifier for the component you are working with. ```python -def list_usages(self, - options=dict()) +def list_allocations(self, + subscription_id, + component_id, + page=1) ``` ## Parameters @@ -1175,28 +1160,27 @@ def list_usages(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `component_id` | int \| str | Template, Required | This is a container for one-of cases. | -| `since_id` | `long\|int` | Query, Optional | Returns usages with an id greater than or equal to the one specified | -| `max_id` | `long\|int` | Query, Optional | Returns usages with an id less than or equal to the one specified | -| `since_date` | `date` | Query, Optional | Returns usages with a created_at date greater than or equal to midnight (12:00 AM) on the date specified. | -| `until_date` | `date` | Query, Optional | Returns usages with a created_at date less than or equal to midnight (12:00 AM) on the date specified. | +| `component_id` | `int` | Template, Required | The Advanced Billing id of the component | | `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`. | -| `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`. | ## Response Type -[`List[UsageResponse]`](../../doc/models/usage-response.md) +[`List[AllocationResponse]`](../../doc/models/allocation-response.md) ## Example Usage ```python -collect = { - 'subscription_id': 222, - 'component_id': 144, - 'page': 2, - 'per_page': 50 -} -result = subscription_components_controller.list_usages(collect) +subscription_id = 222 + +component_id = 222 + +page = 2 + +result = subscription_components_controller.list_allocations( + subscription_id, + component_id, + page=page +) ``` ## Example Response *(as JSON)* @@ -1204,57 +1188,82 @@ result = subscription_components_controller.list_usages(collect) ```json [ { - "usage": { - "id": 178534642, - "memo": "20", - "created_at": "2018-08-03T11:58:42-05:00", - "price_point_id": 242632, - "quantity": "20.0", - "component_id": 500093, - "component_handle": "handle", - "subscription_id": 22824464 + "allocation": { + "allocation_id": 2370199, + "component_id": 41028, + "subscription_id": 352827, + "quantity": 10, + "previous_quantity": 0, + "memo": "Recoding component allocation", + "timestamp": "2024-02-28T09:31:05Z", + "proration_upgrade_scheme": "full-price-attempt-capture", + "proration_downgrade_scheme": "no-prorate", + "price_point_id": 2957424, + "price_point_handle": "uuid:03190e20-b84a-013c-ca77-0286551bb34f", + "price_point_name": "Original", + "previous_price_point_id": 2957424, + "component_handle": "test-prepaid-component-4982065948", + "accrue_charge": false, + "upgrade_charge": "full", + "downgrade_credit": "none", + "created_at": "2024-02-28T04:31:05-05:00", + "initiate_dunning": false, + "expires_at": "2024-08-03T20:00:00-04:00", + "used_quantity": 5, + "charge_id": 11586076 } }, { - "usage": { - "id": 178534591, - "memo": "10", - "created_at": "2018-08-03T11:58:29-05:00", - "price_point_id": 242632, - "quantity": "10.0", - "component_id": 500093, - "component_handle": "handle", - "subscription_id": 22824464 + "allocation": { + "memo": null, + "timestamp": "2012-11-20T21:48:09Z", + "quantity": 3, + "previous_quantity": 0, + "component_id": 11960, + "subscription_id": 2585595, + "proration_upgrade_scheme": "no-prorate", + "proration_downgrade_scheme": "no-prorate" } } ] ``` +## Errors -# Activate Event Based Component +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -In order to bill your subscribers on your Events data under the Events-Based Billing feature, the components must be activated for the subscriber. -Learn more about the role of activation in the [Events-Based Billing docs](https://maxio.zendesk.com/hc/en-us/articles/24260323329805-Events-Based-Billing-Overview). +# Delete Prepaid Usage Allocation -Use this endpoint to activate an event-based component for a single subscription. Activating an event-based component causes Advanced Billing to bill for events when the subscription is renewed. +Prepaid Usage components are unique in that their allocations are always additive. In order to reduce a subscription's allocated quantity for a prepaid usage component each allocation must be destroyed individually via this endpoint. -*Note: it is possible to stream events for a subscription at any time, regardless of component activation status. The activation status only determines if the subscription should be billed for event-based component usage at renewal.* +## Credit Scheme + +By default, destroying an allocation will generate a service credit on the subscription. This behavior can be modified with the optional `credit_scheme` parameter on this endpoint. The accepted values are: + +1. `none`: The allocation will be destroyed and the balances will be updated but no service credit or refund will be created. +2. `credit`: The allocation will be destroyed and the balances will be updated and a service credit will be generated. This is also the default behavior if the `credit_scheme` param is not passed. +3. `refund`: The allocation will be destroyed and the balances will be updated and a refund will be issued along with a Credit Note. ```python -def activate_event_based_component(self, - subscription_id, - component_id, - body=None) +def delete_prepaid_usage_allocation(self, + subscription_id, + component_id, + allocation_id, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Advanced Billing id of the subscription | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | | `component_id` | `int` | Template, Required | The Advanced Billing id of the component | -| `body` | [`ActivateEventBasedComponent`](../../doc/models/activate-event-based-component.md) | Body, Optional | - | +| `allocation_id` | `int` | Template, Required | The Advanced Billing id of the allocation | +| `body` | [`CreditSchemeRequest`](../../doc/models/credit-scheme-request.md) | Body, Optional | - | ## Response Type @@ -1267,106 +1276,168 @@ subscription_id = 222 component_id = 222 -body = ActivateEventBasedComponent( - price_point_id=1, - billing_schedule=BillingSchedule( - initial_billing_at=dateutil.parser.parse('2022-01-01').date() - ), - custom_price=ComponentCustomPrice( - prices=[ - Price( - starting_quantity=1, - unit_price='5.0' - ) - ], - tax_included=False, - pricing_scheme=PricingScheme.PER_UNIT, - interval=30, - interval_unit=IntervalUnit.DAY - ) +allocation_id = 24 + +body = CreditSchemeRequest( + credit_scheme=CreditScheme.NONE ) -subscription_components_controller.activate_event_based_component( +subscription_components_controller.delete_prepaid_usage_allocation( subscription_id, component_id, + allocation_id, body=body ) ``` +## Errors -# Deactivate Event Based Component +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`SubscriptionComponentAllocationErrorException`](../../doc/models/subscription-component-allocation-error-exception.md) | -Use this endpoint to deactivate an event-based component for a single subscription. Deactivating the event-based component causes Advanced Billing to ignore related events at subscription renewal. + +# Create Usage + +## Documentation + +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: + ++ [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) + +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 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. + +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. + +Example: + +Previously recorded: + +```json +{ + "usage": { + "quantity": 5000, + "memo": "Recording 5000 units" + } +} +``` + +At this point, `unit_balance` would be `5000`. To reduce the balance to `0`, POST the following payload: + +```json +{ + "usage": { + "quantity": -5000, + "memo": "Deducting 5000 units" + } +} +``` + +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 deactivate_event_based_component(self, - subscription_id, - component_id) +def create_usage(self, + subscription_id, + component_id, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Advanced Billing id of the subscription | -| `component_id` | `int` | Template, Required | The Advanced Billing id of the component | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `component_id` | int \| str | Template, Required | This is a container for one-of cases. | +| `body` | [`CreateUsageRequest`](../../doc/models/create-usage-request.md) | Body, Optional | - | ## Response Type -`void` +[`UsageResponse`](../../doc/models/usage-response.md) ## Example Usage ```python subscription_id = 222 -component_id = 222 +component_id = 144 -subscription_components_controller.deactivate_event_based_component( +body = CreateUsageRequest( + usage=CreateUsage( + quantity=1000, + price_point_id='149416', + memo='My memo' + ) +) + +result = subscription_components_controller.create_usage( subscription_id, - component_id + component_id, + body=body ) ``` +## Example Response *(as JSON)* -# Record Event - -## Documentation - -Events-Based Billing is an evolved form of metered billing that is based on data-rich events streamed in real-time from your system to Advanced Billing. - -These events can then be transformed, enriched, or analyzed to form the computed totals of usage charges billed to your customers. - -This API allows you to stream events into the Advanced Billing data ingestion engine. +```json +{ + "usage": { + "id": 138522957, + "memo": "My memo", + "created_at": "2017-11-13T10:05:32-06:00", + "price_point_id": 149416, + "quantity": 1000, + "component_id": 500093, + "component_handle": "handle", + "subscription_id": 22824464 + } +} +``` -Learn more about the feature in general in the [Events-Based Billing help docs](https://maxio.zendesk.com/hc/en-us/articles/24260323329805-Events-Based-Billing-Overview). +## Errors -## Record Event +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -Use this endpoint to record a single event. -*Note: this endpoint differs from the standard Chargify API endpoints in that the URL subdomain will be `events` and your site subdomain will be included in the URL path. For example:* +# Deactivate Event Based Component -``` -https://events.chargify.com/my-site-subdomain/events/my-stream-api-handle -``` +Use this endpoint to deactivate an event-based component for a single subscription. Deactivating the event-based component causes Advanced Billing to ignore related events at subscription renewal. ```python -def record_event(self, - subdomain, - api_handle, - store_uid=None, - body=None) +def deactivate_event_based_component(self, + subscription_id, + component_id) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `subdomain` | `str` | Template, Required | Your site's subdomain | -| `api_handle` | `str` | Template, Required | Identifies the Stream for which the event should be published. | -| `store_uid` | `str` | Query, Optional | If you've attached your own Keen project as an Advanced Billing event data-store, use this parameter to indicate the data-store. | -| `body` | [`EBBEvent`](../../doc/models/ebb-event.md) | Body, Optional | - | +| `subscription_id` | `int` | Template, Required | The Advanced Billing id of the subscription | +| `component_id` | `int` | Template, Required | The Advanced Billing id of the component | ## Response Type @@ -1375,21 +1446,13 @@ def record_event(self, ## Example Usage ```python -subdomain = 'subdomain4' - -api_handle = 'api_handle6' +subscription_id = 222 -body = EBBEvent( - chargify=ChargifyEBB( - timestamp=dateutil.parser.parse('2020-02-27T17:45:50-05:00'), - subscription_id=1 - ) -) +component_id = 222 -subscription_components_controller.record_event( - subdomain, - api_handle, - body=body +subscription_components_controller.deactivate_event_based_component( + subscription_id, + component_id ) ``` @@ -1446,66 +1509,3 @@ subscription_components_controller.bulk_record_events( ) ``` - -# List Subscription Components for Site - -This request will list components applied to each subscription. - -```python -def list_subscription_components_for_site(self, - options=dict()) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `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`. | -| `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`. | -| `sort` | [`ListSubscriptionComponentsSort`](../../doc/models/list-subscription-components-sort.md) | Query, Optional | The attribute by which to sort. Use in query: `sort=updated_at`. | -| `direction` | [`SortingDirection`](../../doc/models/sorting-direction.md) | Query, Optional | Controls the order in which results are returned.
Use in query `direction=asc`. | -| `filter` | [`ListSubscriptionComponentsForSiteFilter`](../../doc/models/list-subscription-components-for-site-filter.md) | Query, Optional | Filter to use for List Subscription Components For Site operation | -| `date_field` | [`SubscriptionListDateField`](../../doc/models/subscription-list-date-field.md) | Query, Optional | The type of filter you'd like to apply to your search. Use in query: `date_field=updated_at`. | -| `start_date` | `str` | Query, Optional | The start date (format YYYY-MM-DD) with which to filter the date_field. Returns components with a timestamp at or after midnight (12:00:00 AM) in your site’s time zone on the date specified. Use in query `start_date=2011-12-15`. | -| `start_datetime` | `str` | Query, Optional | The start date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns components with a timestamp at or after 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 start_date. Use in query `start_datetime=2022-07-01 09:00:05`. | -| `end_date` | `str` | Query, Optional | The end date (format YYYY-MM-DD) with which to filter the date_field. Returns components with a timestamp up to and including 11:59:59PM in your site’s time zone on the date specified. Use in query `end_date=2011-12-16`. | -| `end_datetime` | `str` | Query, Optional | The end date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns components 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 `end_datetime=2022-07-01 09:00:05`. | -| `subscription_ids` | `List[int]` | Query, Optional | Allows fetching components allocation with matching subscription id based on provided ids. Use in query `subscription_ids=1,2,3`. | -| `price_point_ids` | [`IncludeNotNull`](../../doc/models/include-not-null.md) | Query, Optional | Allows fetching components allocation only if price point id is present. Use in query `price_point_ids=not_null`. | -| `product_family_ids` | `List[int]` | Query, Optional | Allows fetching components allocation with matching product family id based on provided ids. Use in query `product_family_ids=1,2,3`. | -| `include` | [`ListSubscriptionComponentsInclude`](../../doc/models/list-subscription-components-include.md) | Query, Optional | Allows including additional data in the response. Use in query `include=subscription,historic_usages`. | - -## Response Type - -[`ListSubscriptionComponentsResponse`](../../doc/models/list-subscription-components-response.md) - -## Example Usage - -```python -collect = { - 'page': 2, - 'per_page': 50, - 'sort': ListSubscriptionComponentsSort.UPDATED_AT, - 'filter': ListSubscriptionComponentsForSiteFilter( - currencies=[ - 'EUR', - 'USD' - ] - ), - 'date_field': SubscriptionListDateField.UPDATED_AT, - 'subscription_ids': [ - 1, - 2, - 3 - ], - 'price_point_ids': IncludeNotNull.NOT_NULL, - 'product_family_ids': [ - 1, - 2, - 3 - ], - 'include': ListSubscriptionComponentsInclude.SUBSCRIPTION -} -result = subscription_components_controller.list_subscription_components_for_site(collect) -``` - diff --git a/doc/controllers/subscription-group-invoice-account.md b/doc/controllers/subscription-group-invoice-account.md index 8e0f544f..82b93cb0 100644 --- a/doc/controllers/subscription-group-invoice-account.md +++ b/doc/controllers/subscription-group-invoice-account.md @@ -10,20 +10,20 @@ subscription_group_invoice_account_controller = client.subscription_group_invoic ## Methods -* [Create Subscription Group Prepayment](../../doc/controllers/subscription-group-invoice-account.md#create-subscription-group-prepayment) +* [Deduct Subscription Group Service Credit](../../doc/controllers/subscription-group-invoice-account.md#deduct-subscription-group-service-credit) * [List Prepayments for Subscription Group](../../doc/controllers/subscription-group-invoice-account.md#list-prepayments-for-subscription-group) +* [Create Subscription Group Prepayment](../../doc/controllers/subscription-group-invoice-account.md#create-subscription-group-prepayment) * [Issue Subscription Group Service Credit](../../doc/controllers/subscription-group-invoice-account.md#issue-subscription-group-service-credit) -* [Deduct Subscription Group Service Credit](../../doc/controllers/subscription-group-invoice-account.md#deduct-subscription-group-service-credit) -# Create Subscription Group Prepayment +# Deduct Subscription Group Service Credit -A prepayment can be added for a subscription group identified by the group's `uid`. This endpoint requires a `amount`, `details`, `method`, and `memo`. On success, the prepayment will be added to the group's prepayment balance. +Credit can be deducted for a subscription group identified by the group's `uid`. Credit will be deducted from the group in the amount specified in the request body. ```python -def create_subscription_group_prepayment(self, - uid, - body=None) +def deduct_subscription_group_service_credit(self, + uid, + body=None) ``` ## Parameters @@ -31,29 +31,39 @@ def create_subscription_group_prepayment(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `uid` | `str` | Template, Required | The uid of the subscription group | -| `body` | [`SubscriptionGroupPrepaymentRequest`](../../doc/models/subscription-group-prepayment-request.md) | Body, Optional | - | +| `body` | [`DeductServiceCreditRequest`](../../doc/models/deduct-service-credit-request.md) | Body, Optional | - | ## Response Type -[`SubscriptionGroupPrepaymentResponse`](../../doc/models/subscription-group-prepayment-response.md) +[`ServiceCredit`](../../doc/models/service-credit.md) ## Example Usage ```python uid = 'uid0' -result = subscription_group_invoice_account_controller.create_subscription_group_prepayment(uid) +body = DeductServiceCreditRequest( + deduction=DeductServiceCredit( + amount=10, + memo='Deduct from group account' + ) +) + +result = subscription_group_invoice_account_controller.deduct_subscription_group_service_credit( + uid, + body=body +) ``` ## Example Response *(as JSON)* ```json { - "id": 6049554, - "amount_in_cents": 10000, - "ending_balance_in_cents": 5000, + "id": 100, + "amount_in_cents": 1000, + "ending_balance_in_cents": 0, "entry_type": "Debit", - "memo": "Debit from invoice account." + "memo": "Debit from group account" } ``` @@ -131,14 +141,14 @@ result = subscription_group_invoice_account_controller.list_prepayments_for_subs | 404 | Not Found | `APIException` | -# Issue Subscription Group Service Credit +# Create Subscription Group Prepayment -Credit can be issued for a subscription group identified by the group's `uid`. Credit will be added to the group in the amount specified in the request body. The credit will be applied to group member invoices as they are generated. +A prepayment can be added for a subscription group identified by the group's `uid`. This endpoint requires a `amount`, `details`, `method`, and `memo`. On success, the prepayment will be added to the group's prepayment balance. ```python -def issue_subscription_group_service_credit(self, - uid, - body=None) +def create_subscription_group_prepayment(self, + uid, + body=None) ``` ## Parameters @@ -146,41 +156,29 @@ def issue_subscription_group_service_credit(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `uid` | `str` | Template, Required | The uid of the subscription group | -| `body` | [`IssueServiceCreditRequest`](../../doc/models/issue-service-credit-request.md) | Body, Optional | - | +| `body` | [`SubscriptionGroupPrepaymentRequest`](../../doc/models/subscription-group-prepayment-request.md) | Body, Optional | - | ## Response Type -[`ServiceCreditResponse`](../../doc/models/service-credit-response.md) +[`SubscriptionGroupPrepaymentResponse`](../../doc/models/subscription-group-prepayment-response.md) ## Example Usage ```python uid = 'uid0' -body = IssueServiceCreditRequest( - service_credit=IssueServiceCredit( - amount=10, - memo='Credit the group account' - ) -) - -result = subscription_group_invoice_account_controller.issue_subscription_group_service_credit( - uid, - body=body -) +result = subscription_group_invoice_account_controller.create_subscription_group_prepayment(uid) ``` ## Example Response *(as JSON)* ```json { - "service_credit": { - "id": 101, - "amount_in_cents": 1000, - "ending_balance_in_cents": 2000, - "entry_type": "Credit", - "memo": "Credit to group account" - } + "id": 6049554, + "amount_in_cents": 10000, + "ending_balance_in_cents": 5000, + "entry_type": "Debit", + "memo": "Debit from invoice account." } ``` @@ -191,14 +189,14 @@ result = subscription_group_invoice_account_controller.issue_subscription_group_ | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Deduct Subscription Group Service Credit +# Issue Subscription Group Service Credit -Credit can be deducted for a subscription group identified by the group's `uid`. Credit will be deducted from the group in the amount specified in the request body. +Credit can be issued for a subscription group identified by the group's `uid`. Credit will be added to the group in the amount specified in the request body. The credit will be applied to group member invoices as they are generated. ```python -def deduct_subscription_group_service_credit(self, - uid, - body=None) +def issue_subscription_group_service_credit(self, + uid, + body=None) ``` ## Parameters @@ -206,25 +204,25 @@ def deduct_subscription_group_service_credit(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `uid` | `str` | Template, Required | The uid of the subscription group | -| `body` | [`DeductServiceCreditRequest`](../../doc/models/deduct-service-credit-request.md) | Body, Optional | - | +| `body` | [`IssueServiceCreditRequest`](../../doc/models/issue-service-credit-request.md) | Body, Optional | - | ## Response Type -[`ServiceCredit`](../../doc/models/service-credit.md) +[`ServiceCreditResponse`](../../doc/models/service-credit-response.md) ## Example Usage ```python uid = 'uid0' -body = DeductServiceCreditRequest( - deduction=DeductServiceCredit( +body = IssueServiceCreditRequest( + service_credit=IssueServiceCredit( amount=10, - memo='Deduct from group account' + memo='Credit the group account' ) ) -result = subscription_group_invoice_account_controller.deduct_subscription_group_service_credit( +result = subscription_group_invoice_account_controller.issue_subscription_group_service_credit( uid, body=body ) @@ -234,11 +232,13 @@ result = subscription_group_invoice_account_controller.deduct_subscription_group ```json { - "id": 100, - "amount_in_cents": 1000, - "ending_balance_in_cents": 0, - "entry_type": "Debit", - "memo": "Debit from group account" + "service_credit": { + "id": 101, + "amount_in_cents": 1000, + "ending_balance_in_cents": 2000, + "entry_type": "Credit", + "memo": "Credit to group account" + } } ``` diff --git a/doc/controllers/subscription-group-status.md b/doc/controllers/subscription-group-status.md index 57835a02..716999a3 100644 --- a/doc/controllers/subscription-group-status.md +++ b/doc/controllers/subscription-group-status.md @@ -10,22 +10,21 @@ subscription_group_status_controller = client.subscription_group_status ## Methods -* [Cancel Subscriptions in Group](../../doc/controllers/subscription-group-status.md#cancel-subscriptions-in-group) * [Initiate Delayed Cancellation for Group](../../doc/controllers/subscription-group-status.md#initiate-delayed-cancellation-for-group) +* [Cancel Subscriptions in Group](../../doc/controllers/subscription-group-status.md#cancel-subscriptions-in-group) * [Cancel Delayed Cancellation for Group](../../doc/controllers/subscription-group-status.md#cancel-delayed-cancellation-for-group) * [Reactivate Subscription Group](../../doc/controllers/subscription-group-status.md#reactivate-subscription-group) -# Cancel Subscriptions in Group +# Initiate Delayed Cancellation for 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. +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. -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. +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. ```python -def cancel_subscriptions_in_group(self, - uid, - body=None) +def initiate_delayed_cancellation_for_group(self, + uid) ``` ## Parameters @@ -33,7 +32,6 @@ def cancel_subscriptions_in_group(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `uid` | `str` | Template, Required | The uid of the subscription group | -| `body` | [`CancelGroupedSubscriptionsRequest`](../../doc/models/cancel-grouped-subscriptions-request.md) | Body, Optional | - | ## Response Type @@ -44,14 +42,7 @@ def cancel_subscriptions_in_group(self, ```python uid = 'uid0' -body = CancelGroupedSubscriptionsRequest( - charge_unbilled_usage=True -) - -subscription_group_status_controller.cancel_subscriptions_in_group( - uid, - body=body -) +subscription_group_status_controller.initiate_delayed_cancellation_for_group(uid) ``` ## Errors @@ -61,15 +52,16 @@ subscription_group_status_controller.cancel_subscriptions_in_group( | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Initiate Delayed Cancellation for Group +# Cancel Subscriptions in 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 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. -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. +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. ```python -def initiate_delayed_cancellation_for_group(self, - uid) +def cancel_subscriptions_in_group(self, + uid, + body=None) ``` ## Parameters @@ -77,6 +69,7 @@ def initiate_delayed_cancellation_for_group(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `uid` | `str` | Template, Required | The uid of the subscription group | +| `body` | [`CancelGroupedSubscriptionsRequest`](../../doc/models/cancel-grouped-subscriptions-request.md) | Body, Optional | - | ## Response Type @@ -87,7 +80,14 @@ def initiate_delayed_cancellation_for_group(self, ```python uid = 'uid0' -subscription_group_status_controller.initiate_delayed_cancellation_for_group(uid) +body = CancelGroupedSubscriptionsRequest( + charge_unbilled_usage=True +) + +subscription_group_status_controller.cancel_subscriptions_in_group( + uid, + body=body +) ``` ## Errors diff --git a/doc/controllers/subscription-groups.md b/doc/controllers/subscription-groups.md index 32f00e11..a9da90e9 100644 --- a/doc/controllers/subscription-groups.md +++ b/doc/controllers/subscription-groups.md @@ -10,145 +10,17 @@ subscription_groups_controller = client.subscription_groups ## Methods +* [List Subscription Groups](../../doc/controllers/subscription-groups.md#list-subscription-groups) +* [Find Subscription Group](../../doc/controllers/subscription-groups.md#find-subscription-group) * [Signup With Subscription Group](../../doc/controllers/subscription-groups.md#signup-with-subscription-group) * [Create Subscription Group](../../doc/controllers/subscription-groups.md#create-subscription-group) -* [List Subscription Groups](../../doc/controllers/subscription-groups.md#list-subscription-groups) -* [Read Subscription Group](../../doc/controllers/subscription-groups.md#read-subscription-group) -* [Update Subscription Group Members](../../doc/controllers/subscription-groups.md#update-subscription-group-members) * [Delete Subscription Group](../../doc/controllers/subscription-groups.md#delete-subscription-group) -* [Find Subscription Group](../../doc/controllers/subscription-groups.md#find-subscription-group) * [Add Subscription to Group](../../doc/controllers/subscription-groups.md#add-subscription-to-group) +* [Read Subscription Group](../../doc/controllers/subscription-groups.md#read-subscription-group) +* [Update Subscription Group Members](../../doc/controllers/subscription-groups.md#update-subscription-group-members) * [Remove Subscription From Group](../../doc/controllers/subscription-groups.md#remove-subscription-from-group) -# Signup With Subscription Group - -Create multiple subscriptions at once under the same customer and consolidate them into a subscription group. - -You must provide one and only one of the `payer_id`/`payer_reference`/`payer_attributes` for the customer attached to the group. - -You must provide one and only one of the `payment_profile_id`/`credit_card_attributes`/`bank_account_attributes` for the payment profile attached to the group. - -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. - -```python -def signup_with_subscription_group(self, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `body` | [`SubscriptionGroupSignupRequest`](../../doc/models/subscription-group-signup-request.md) | Body, Optional | - | - -## Response Type - -[`SubscriptionGroupSignupResponse`](../../doc/models/subscription-group-signup-response.md) - -## Example Usage - -```python -body = SubscriptionGroupSignupRequest( - subscription_group=SubscriptionGroupSignup( - subscriptions=[ - SubscriptionGroupSignupItem( - product_id=11, - primary=True - ), - SubscriptionGroupSignupItem( - product_id=12 - ), - SubscriptionGroupSignupItem( - product_id=13 - ) - ], - payment_profile_id=123, - payer_id=123 - ) -) - -result = subscription_groups_controller.signup_with_subscription_group( - body=body -) -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`SubscriptionGroupSignupErrorResponseException`](../../doc/models/subscription-group-signup-error-response-exception.md) | - - -# Create Subscription Group - -Creates a subscription group with given members. - -```python -def create_subscription_group(self, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `body` | [`CreateSubscriptionGroupRequest`](../../doc/models/create-subscription-group-request.md) | Body, Optional | - | - -## Response Type - -[`SubscriptionGroupResponse`](../../doc/models/subscription-group-response.md) - -## Example Usage - -```python -body = CreateSubscriptionGroupRequest( - subscription_group=CreateSubscriptionGroup( - subscription_id=1, - member_ids=[ - 2, - 3, - 4 - ] - ) -) - -result = subscription_groups_controller.create_subscription_group( - body=body -) -``` - -## Example Response *(as JSON)* - -```json -{ - "subscription_group": { - "customer_id": 1, - "payment_profile": { - "id": 1, - "first_name": "t", - "last_name": "t", - "masked_card_number": "XXXX-XXXX-XXXX-1" - }, - "payment_collection_method": "automatic", - "subscription_ids": [ - 1, - 2 - ], - "created_at": "2021-01-21T05:47:38-05:00" - } -} -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`SubscriptionGroupCreateErrorResponseException`](../../doc/models/subscription-group-create-error-response-exception.md) | - - # List Subscription Groups Returns an array of subscription groups for the site. The response is paginated and will return a `meta` key with pagination information. @@ -226,26 +98,22 @@ result = subscription_groups_controller.list_subscription_groups(collect) ``` -# Read Subscription Group - -Use this endpoint to find subscription group details. +# Find Subscription Group -#### Current Billing Amount in Cents +Use this endpoint to find subscription group associated with subscription. -Current billing amount for the subscription group is not returned by default. If this information is desired, the `include[]=current_billing_amount_in_cents` parameter must be provided with the request. +If the subscription is not in a group endpoint will return 404 code. ```python -def read_subscription_group(self, - uid, - include=None) +def find_subscription_group(self, + subscription_id) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `uid` | `str` | Template, Required | The uid of the subscription group | -| `include` | [`List[SubscriptionGroupInclude]`](../../doc/models/subscription-group-include.md) | Query, Optional | Allows including additional data in the response. Use in query: `include[]=current_billing_amount_in_cents`. | +| `subscription_id` | `str` | Query, Required | The Advanced Billing id of the subscription associated with the subscription group | ## Response Type @@ -254,16 +122,9 @@ def read_subscription_group(self, ## Example Usage ```python -uid = 'uid0' - -include = [ - SubscriptionGroupInclude.CURRENT_BILLING_AMOUNT_IN_CENTS -] +subscription_id = 'subscription_id0' -result = subscription_groups_controller.read_subscription_group( - uid, - include=include -) +result = subscription_groups_controller.find_subscription_group(subscription_id) ``` ## Example Response *(as JSON)* @@ -283,7 +144,6 @@ result = subscription_groups_controller.read_subscription_group( "next_assessment_at": "2020-08-01T14:00:00-05:00", "state": "active", "cancel_at_end_of_period": false, - "current_billing_amount_in_cents": 11500, "customer": { "first_name": "Mark", "last_name": "Wannabewahlberg", @@ -308,46 +168,108 @@ result = subscription_groups_controller.read_subscription_group( } ``` +## Errors -# Update Subscription Group Members +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | -Use this endpoint to update subscription group members. -`"member_ids"` should contain an array of both subscription IDs to set as group members and subscription IDs already present in the groups. Not including them will result in removing them from subscription group. To clean up members, just leave the array empty. + +# Signup With Subscription Group + +Create multiple subscriptions at once under the same customer and consolidate them into a subscription group. + +You must provide one and only one of the `payer_id`/`payer_reference`/`payer_attributes` for the customer attached to the group. + +You must provide one and only one of the `payment_profile_id`/`credit_card_attributes`/`bank_account_attributes` for the payment profile attached to the group. + +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. ```python -def update_subscription_group_members(self, - uid, - body=None) +def signup_with_subscription_group(self, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `uid` | `str` | Template, Required | The uid of the subscription group | -| `body` | [`UpdateSubscriptionGroupRequest`](../../doc/models/update-subscription-group-request.md) | Body, Optional | - | +| `body` | [`SubscriptionGroupSignupRequest`](../../doc/models/subscription-group-signup-request.md) | Body, Optional | - | ## Response Type -[`SubscriptionGroupResponse`](../../doc/models/subscription-group-response.md) +[`SubscriptionGroupSignupResponse`](../../doc/models/subscription-group-signup-response.md) ## Example Usage ```python -uid = 'uid0' +body = SubscriptionGroupSignupRequest( + subscription_group=SubscriptionGroupSignup( + subscriptions=[ + SubscriptionGroupSignupItem( + product_id=11, + primary=True + ), + SubscriptionGroupSignupItem( + product_id=12 + ), + SubscriptionGroupSignupItem( + product_id=13 + ) + ], + payment_profile_id=123, + payer_id=123 + ) +) -body = UpdateSubscriptionGroupRequest( - subscription_group=UpdateSubscriptionGroup( +result = subscription_groups_controller.signup_with_subscription_group( + body=body +) +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`SubscriptionGroupSignupErrorResponseException`](../../doc/models/subscription-group-signup-error-response-exception.md) | + + +# Create Subscription Group + +Creates a subscription group with given members. + +```python +def create_subscription_group(self, + body=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `body` | [`CreateSubscriptionGroupRequest`](../../doc/models/create-subscription-group-request.md) | Body, Optional | - | + +## Response Type + +[`SubscriptionGroupResponse`](../../doc/models/subscription-group-response.md) + +## Example Usage + +```python +body = CreateSubscriptionGroupRequest( + subscription_group=CreateSubscriptionGroup( + subscription_id=1, member_ids=[ - 1, 2, - 3 + 3, + 4 ] ) ) -result = subscription_groups_controller.update_subscription_group_members( - uid, +result = subscription_groups_controller.create_subscription_group( body=body ) ``` @@ -366,7 +288,8 @@ result = subscription_groups_controller.update_subscription_group_members( }, "payment_collection_method": "automatic", "subscription_ids": [ - 1 + 1, + 2 ], "created_at": "2021-01-21T05:47:38-05:00" } @@ -377,7 +300,7 @@ result = subscription_groups_controller.update_subscription_group_members( | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`SubscriptionGroupUpdateErrorResponseException`](../../doc/models/subscription-group-update-error-response-exception.md) | +| 422 | Unprocessable Entity (WebDAV) | [`SubscriptionGroupCreateErrorResponseException`](../../doc/models/subscription-group-create-error-response-exception.md) | # Delete Subscription Group @@ -424,22 +347,108 @@ result = subscription_groups_controller.delete_subscription_group(uid) | 404 | Not Found | `APIException` | -# Find Subscription Group +# Add Subscription to Group -Use this endpoint to find subscription group associated with subscription. +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#customer-hierarchies) features, it is possible to add existing subscriptions to subscription groups. -If the subscription is not in a group endpoint will return 404 code. +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. + +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, +* `"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: +[Create Subscription in a Subscription Group](https://developers.chargify.com/docs/api-docs/d571659cf0f24-create-subscription#subscription-in-a-subscription-group) ```python -def find_subscription_group(self, - subscription_id) +def add_subscription_to_group(self, + subscription_id, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `subscription_id` | `str` | Query, Required | The Advanced Billing id of the subscription associated with the subscription group | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `body` | [`AddSubscriptionToAGroup`](../../doc/models/add-subscription-to-a-group.md) | Body, Optional | - | + +## Response Type + +[`SubscriptionGroupResponse`](../../doc/models/subscription-group-response.md) + +## Example Usage + +```python +subscription_id = 222 + +body = AddSubscriptionToAGroup( + group=GroupSettings( + target=GroupTarget( + mtype=GroupTargetType.SUBSCRIPTION, + id=32987 + ), + billing=GroupBilling( + accrue=True, + align_date=True, + prorate=True + ) + ) +) + +result = subscription_groups_controller.add_subscription_to_group( + subscription_id, + body=body +) +``` + +## Example Response *(as JSON)* + +```json +{ + "subscription_group": { + "customer_id": 130690, + "payment_profile": { + "id": 32055, + "first_name": "Marty", + "last_name": "McFly", + "masked_card_number": "XXXX-XXXX-XXXX-1111" + }, + "subscription_ids": [ + 32988, + 33060, + 32986 + ], + "created_at": "2018-08-30T17:14:30-04:00" + } +} +``` + + +# Read Subscription Group + +Use this endpoint to find subscription group details. + +#### Current Billing Amount in Cents + +Current billing amount for the subscription group is not returned by default. If this information is desired, the `include[]=current_billing_amount_in_cents` parameter must be provided with the request. + +```python +def read_subscription_group(self, + uid, + include=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `uid` | `str` | Template, Required | The uid of the subscription group | +| `include` | [`List[SubscriptionGroupInclude]`](../../doc/models/subscription-group-include.md) | Query, Optional | Allows including additional data in the response. Use in query: `include[]=current_billing_amount_in_cents`. | ## Response Type @@ -448,9 +457,16 @@ def find_subscription_group(self, ## Example Usage ```python -subscription_id = 'subscription_id0' +uid = 'uid0' -result = subscription_groups_controller.find_subscription_group(subscription_id) +include = [ + SubscriptionGroupInclude.CURRENT_BILLING_AMOUNT_IN_CENTS +] + +result = subscription_groups_controller.read_subscription_group( + uid, + include=include +) ``` ## Example Response *(as JSON)* @@ -470,6 +486,7 @@ result = subscription_groups_controller.find_subscription_group(subscription_id) "next_assessment_at": "2020-08-01T14:00:00-05:00", "state": "active", "cancel_at_end_of_period": false, + "current_billing_amount_in_cents": 11500, "customer": { "first_name": "Mark", "last_name": "Wannabewahlberg", @@ -494,42 +511,24 @@ result = subscription_groups_controller.find_subscription_group(subscription_id) } ``` -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | - - -# Add Subscription to Group - -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#customer-hierarchies) features, it is possible to add existing subscriptions to subscription groups. - -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. -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, -* `"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. +# Update Subscription Group Members -To create a new subscription into a subscription group, please reference the following: -[Create Subscription in a Subscription Group](https://developers.chargify.com/docs/api-docs/d571659cf0f24-create-subscription#subscription-in-a-subscription-group) +Use this endpoint to update subscription group members. +`"member_ids"` should contain an array of both subscription IDs to set as group members and subscription IDs already present in the groups. Not including them will result in removing them from subscription group. To clean up members, just leave the array empty. ```python -def add_subscription_to_group(self, - subscription_id, - body=None) +def update_subscription_group_members(self, + uid, + body=None) ``` ## Parameters | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `body` | [`AddSubscriptionToAGroup`](../../doc/models/add-subscription-to-a-group.md) | Body, Optional | - | +| `uid` | `str` | Template, Required | The uid of the subscription group | +| `body` | [`UpdateSubscriptionGroupRequest`](../../doc/models/update-subscription-group-request.md) | Body, Optional | - | ## Response Type @@ -538,24 +537,20 @@ def add_subscription_to_group(self, ## Example Usage ```python -subscription_id = 222 +uid = 'uid0' -body = AddSubscriptionToAGroup( - group=GroupSettings( - target=GroupTarget( - mtype=GroupTargetType.SUBSCRIPTION, - id=32987 - ), - billing=GroupBilling( - accrue=True, - align_date=True, - prorate=True - ) +body = UpdateSubscriptionGroupRequest( + subscription_group=UpdateSubscriptionGroup( + member_ids=[ + 1, + 2, + 3 + ] ) ) -result = subscription_groups_controller.add_subscription_to_group( - subscription_id, +result = subscription_groups_controller.update_subscription_group_members( + uid, body=body ) ``` @@ -565,23 +560,28 @@ result = subscription_groups_controller.add_subscription_to_group( ```json { "subscription_group": { - "customer_id": 130690, + "customer_id": 1, "payment_profile": { - "id": 32055, - "first_name": "Marty", - "last_name": "McFly", - "masked_card_number": "XXXX-XXXX-XXXX-1111" + "id": 1, + "first_name": "t", + "last_name": "t", + "masked_card_number": "XXXX-XXXX-XXXX-1" }, + "payment_collection_method": "automatic", "subscription_ids": [ - 32988, - 33060, - 32986 + 1 ], - "created_at": "2018-08-30T17:14:30-04:00" + "created_at": "2021-01-21T05:47:38-05:00" } } ``` +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`SubscriptionGroupUpdateErrorResponseException`](../../doc/models/subscription-group-update-error-response-exception.md) | + # Remove Subscription From Group diff --git a/doc/controllers/subscription-invoice-account.md b/doc/controllers/subscription-invoice-account.md index 6ede5a36..d9fb3b22 100644 --- a/doc/controllers/subscription-invoice-account.md +++ b/doc/controllers/subscription-invoice-account.md @@ -10,40 +10,12 @@ subscription_invoice_account_controller = client.subscription_invoice_account ## Methods -* [Read Account Balances](../../doc/controllers/subscription-invoice-account.md#read-account-balances) * [Create Prepayment](../../doc/controllers/subscription-invoice-account.md#create-prepayment) * [List Prepayments](../../doc/controllers/subscription-invoice-account.md#list-prepayments) +* [Refund Prepayment](../../doc/controllers/subscription-invoice-account.md#refund-prepayment) +* [Read Account Balances](../../doc/controllers/subscription-invoice-account.md#read-account-balances) * [Issue Service Credit](../../doc/controllers/subscription-invoice-account.md#issue-service-credit) * [Deduct Service Credit](../../doc/controllers/subscription-invoice-account.md#deduct-service-credit) -* [Refund Prepayment](../../doc/controllers/subscription-invoice-account.md#refund-prepayment) - - -# Read Account Balances - -Returns the `balance_in_cents` of the Subscription's Pending Discount, Service Credit, and Prepayment accounts, as well as the sum of the Subscription's open, payable invoices. - -```python -def read_account_balances(self, - subscription_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | - -## Response Type - -[`AccountBalances`](../../doc/models/account-balances.md) - -## Example Usage - -```python -subscription_id = 222 - -result = subscription_invoice_account_controller.read_account_balances(subscription_id) -``` # Create Prepayment @@ -182,6 +154,81 @@ result = subscription_invoice_account_controller.list_prepayments(collect) | 404 | Not Found | `APIException` | +# Refund Prepayment + +This endpoint will refund, completely or partially, a particular prepayment applied to a subscription. The `prepayment_id` will be the account transaction ID of the original payment. The prepayment must have some amount remaining in order to be refunded. + +The amount may be passed either as a decimal, with `amount`, or an integer in cents, with `amount_in_cents`. + +```python +def refund_prepayment(self, + subscription_id, + prepayment_id, + body=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `prepayment_id` | `long\|int` | Template, Required | id of prepayment | +| `body` | [`RefundPrepaymentRequest`](../../doc/models/refund-prepayment-request.md) | Body, Optional | - | + +## Response Type + +[`PrepaymentResponse`](../../doc/models/prepayment-response.md) + +## Example Usage + +```python +subscription_id = 222 + +prepayment_id = 228 + +result = subscription_invoice_account_controller.refund_prepayment( + subscription_id, + prepayment_id +) +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 400 | Bad Request | [`RefundPrepaymentBaseErrorsResponseException`](../../doc/models/refund-prepayment-base-errors-response-exception.md) | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity | `APIException` | + + +# Read Account Balances + +Returns the `balance_in_cents` of the Subscription's Pending Discount, Service Credit, and Prepayment accounts, as well as the sum of the Subscription's open, payable invoices. + +```python +def read_account_balances(self, + subscription_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | + +## Response Type + +[`AccountBalances`](../../doc/models/account-balances.md) + +## Example Usage + +```python +subscription_id = 222 + +result = subscription_invoice_account_controller.read_account_balances(subscription_id) +``` + + # Issue Service Credit Credit will be added to the subscription in the amount specified in the request body. The credit is subsequently applied to the next generated invoice. @@ -284,50 +331,3 @@ subscription_invoice_account_controller.deduct_service_credit( | --- | --- | --- | | 422 | Unprocessable Entity (WebDAV) | `APIException` | - -# Refund Prepayment - -This endpoint will refund, completely or partially, a particular prepayment applied to a subscription. The `prepayment_id` will be the account transaction ID of the original payment. The prepayment must have some amount remaining in order to be refunded. - -The amount may be passed either as a decimal, with `amount`, or an integer in cents, with `amount_in_cents`. - -```python -def refund_prepayment(self, - subscription_id, - prepayment_id, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `prepayment_id` | `long\|int` | Template, Required | id of prepayment | -| `body` | [`RefundPrepaymentRequest`](../../doc/models/refund-prepayment-request.md) | Body, Optional | - | - -## Response Type - -[`PrepaymentResponse`](../../doc/models/prepayment-response.md) - -## Example Usage - -```python -subscription_id = 222 - -prepayment_id = 228 - -result = subscription_invoice_account_controller.refund_prepayment( - subscription_id, - prepayment_id -) -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 400 | Bad Request | [`RefundPrepaymentBaseErrorsResponseException`](../../doc/models/refund-prepayment-base-errors-response-exception.md) | -| 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity | `APIException` | - diff --git a/doc/controllers/subscription-notes.md b/doc/controllers/subscription-notes.md index 8fdd3673..8eda17c6 100644 --- a/doc/controllers/subscription-notes.md +++ b/doc/controllers/subscription-notes.md @@ -10,59 +10,11 @@ subscription_notes_controller = client.subscription_notes ## Methods -* [Create Subscription Note](../../doc/controllers/subscription-notes.md#create-subscription-note) * [List Subscription Notes](../../doc/controllers/subscription-notes.md#list-subscription-notes) +* [Delete Subscription Note](../../doc/controllers/subscription-notes.md#delete-subscription-note) +* [Create Subscription Note](../../doc/controllers/subscription-notes.md#create-subscription-note) * [Read Subscription Note](../../doc/controllers/subscription-notes.md#read-subscription-note) * [Update Subscription Note](../../doc/controllers/subscription-notes.md#update-subscription-note) -* [Delete Subscription Note](../../doc/controllers/subscription-notes.md#delete-subscription-note) - - -# Create Subscription Note - -Use the following method to create a note for a subscription. - -## How to Use Subscription Notes - -Notes allow you to record information about a particular Subscription in a free text format. - -If you have structured data such as birth date, color, etc., consider using Metadata instead. - -Full documentation on how to use Notes in the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24251712214413-Subscription-Summary-Overview). - -```python -def create_subscription_note(self, - subscription_id, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `body` | [`UpdateSubscriptionNoteRequest`](../../doc/models/update-subscription-note-request.md) | Body, Optional | Updatable fields for Subscription Note | - -## Response Type - -[`SubscriptionNoteResponse`](../../doc/models/subscription-note-response.md) - -## Example Usage - -```python -subscription_id = 222 - -body = UpdateSubscriptionNoteRequest( - note=UpdateSubscriptionNote( - body='New test note.', - sticky=True - ) -) - -result = subscription_notes_controller.create_subscription_note( - subscription_id, - body=body -) -``` # List Subscription Notes @@ -125,6 +77,89 @@ result = subscription_notes_controller.list_subscription_notes(collect) ``` +# Delete Subscription Note + +Use the following method to delete a note for a Subscription. + +```python +def delete_subscription_note(self, + subscription_id, + note_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `note_id` | `int` | Template, Required | The Advanced Billing id of the note | + +## Response Type + +`void` + +## Example Usage + +```python +subscription_id = 222 + +note_id = 66 + +subscription_notes_controller.delete_subscription_note( + subscription_id, + note_id +) +``` + + +# Create Subscription Note + +Use the following method to create a note for a subscription. + +## How to Use Subscription Notes + +Notes allow you to record information about a particular Subscription in a free text format. + +If you have structured data such as birth date, color, etc., consider using Metadata instead. + +Full documentation on how to use Notes in the Advanced Billing UI can be located [here](https://maxio.zendesk.com/hc/en-us/articles/24251712214413-Subscription-Summary-Overview). + +```python +def create_subscription_note(self, + subscription_id, + body=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `body` | [`UpdateSubscriptionNoteRequest`](../../doc/models/update-subscription-note-request.md) | Body, Optional | Updatable fields for Subscription Note | + +## Response Type + +[`SubscriptionNoteResponse`](../../doc/models/subscription-note-response.md) + +## Example Usage + +```python +subscription_id = 222 + +body = UpdateSubscriptionNoteRequest( + note=UpdateSubscriptionNote( + body='New test note.', + sticky=True + ) +) + +result = subscription_notes_controller.create_subscription_note( + subscription_id, + body=body +) +``` + + # Read Subscription Note Once you have obtained the ID of the note you wish to read, use this method to show a particular note attached to a subscription. @@ -219,38 +254,3 @@ result = subscription_notes_controller.update_subscription_note( ) ``` - -# Delete Subscription Note - -Use the following method to delete a note for a Subscription. - -```python -def delete_subscription_note(self, - subscription_id, - note_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `note_id` | `int` | Template, Required | The Advanced Billing id of the note | - -## Response Type - -`void` - -## Example Usage - -```python -subscription_id = 222 - -note_id = 66 - -subscription_notes_controller.delete_subscription_note( - subscription_id, - note_id -) -``` - diff --git a/doc/controllers/subscription-status.md b/doc/controllers/subscription-status.md index c4b91b5f..9bafeeec 100644 --- a/doc/controllers/subscription-status.md +++ b/doc/controllers/subscription-status.md @@ -10,33 +10,32 @@ subscription_status_controller = client.subscription_status ## Methods -* [Retry Subscription](../../doc/controllers/subscription-status.md#retry-subscription) -* [Cancel Subscription](../../doc/controllers/subscription-status.md#cancel-subscription) -* [Resume Subscription](../../doc/controllers/subscription-status.md#resume-subscription) -* [Pause Subscription](../../doc/controllers/subscription-status.md#pause-subscription) * [Update Automatic Subscription Resumption](../../doc/controllers/subscription-status.md#update-automatic-subscription-resumption) -* [Reactivate Subscription](../../doc/controllers/subscription-status.md#reactivate-subscription) * [Initiate Delayed Cancellation](../../doc/controllers/subscription-status.md#initiate-delayed-cancellation) * [Cancel Delayed Cancellation](../../doc/controllers/subscription-status.md#cancel-delayed-cancellation) -* [Cancel Dunning](../../doc/controllers/subscription-status.md#cancel-dunning) * [Preview Renewal](../../doc/controllers/subscription-status.md#preview-renewal) +* [Resume Subscription](../../doc/controllers/subscription-status.md#resume-subscription) +* [Pause Subscription](../../doc/controllers/subscription-status.md#pause-subscription) +* [Retry Subscription](../../doc/controllers/subscription-status.md#retry-subscription) +* [Cancel Subscription](../../doc/controllers/subscription-status.md#cancel-subscription) +* [Cancel Dunning](../../doc/controllers/subscription-status.md#cancel-dunning) +* [Reactivate Subscription](../../doc/controllers/subscription-status.md#reactivate-subscription) -# Retry Subscription - -Advanced Billing offers the ability to retry collecting the balance due on a past due Subscription without waiting for the next scheduled attempt. +# Update Automatic Subscription Resumption -## Successful Reactivation +Once a subscription has been paused / put on hold, you can update the date which was specified to automatically resume the subscription. -The response will be `200 OK` with the updated Subscription. +To update a subscription's resume date, use this method to change or update the `automatically_resume_at` date. -## Failed Reactivation +### Remove the resume date -The response will be `422 "Unprocessable Entity`. +Alternately, you can change the `automatically_resume_at` to `null` if you would like the subscription to not have a resume date. ```python -def retry_subscription(self, - subscription_id) +def update_automatic_subscription_resumption(self, + subscription_id, + body=None) ``` ## Parameters @@ -44,6 +43,7 @@ def retry_subscription(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `body` | [`PauseRequest`](../../doc/models/pause-request.md) | Body, Optional | Allows to pause a Subscription | ## Response Type @@ -54,7 +54,16 @@ def retry_subscription(self, ```python subscription_id = 222 -result = subscription_status_controller.retry_subscription(subscription_id) +body = PauseRequest( + hold=AutoResume( + automatically_resume_at=dateutil.parser.parse('2019-01-20T00:00:00') + ) +) + +result = subscription_status_controller.update_automatic_subscription_resumption( + subscription_id, + body=body +) ``` ## Example Response *(as JSON)* @@ -62,94 +71,75 @@ result = subscription_status_controller.retry_subscription(subscription_id) ```json { "subscription": { - "id": 46330, - "state": "active", + "id": 20359140, + "state": "on_hold", "trial_started_at": null, "trial_ended_at": null, - "activated_at": "2018-10-22T13:10:46-06:00", - "created_at": "2018-10-22T13:10:46-06:00", - "updated_at": "2021-06-10T09:23:43-06:00", + "activated_at": "2018-01-05T17:15:50-06:00", + "created_at": "2018-01-05T17:15:49-06:00", + "updated_at": "2018-01-09T10:26:14-06:00", "expires_at": null, - "balance_in_cents": 18600, - "current_period_ends_at": "2021-06-22T13:10:46-06:00", - "next_assessment_at": "2021-06-22T13:10:46-06:00", + "balance_in_cents": 0, + "current_period_ends_at": "2023-01-05T17:15:00-06:00", + "next_assessment_at": "2023-01-05T17:15:00-06:00", "canceled_at": null, "cancellation_message": null, "next_product_id": null, - "cancel_at_end_of_period": null, + "cancel_at_end_of_period": false, "payment_collection_method": "automatic", "snap_day": null, "cancellation_method": null, - "product_price_point_id": 3464, - "next_product_price_point_id": null, - "receives_invoice_emails": null, - "net_terms": null, - "locale": null, - "currency": "USD", - "reference": null, - "scheduled_cancellation_at": null, - "current_period_started_at": "2021-05-22T13:10:46-06:00", - "previous_state": "past_due", - "signup_payment_id": 651268, - "signup_revenue": "6.00", + "current_period_started_at": "2018-01-05T17:15:49-06:00", + "previous_state": "active", + "signup_payment_id": 219829722, + "signup_revenue": "100.00", "delayed_cancel_at": null, "coupon_code": null, - "total_revenue_in_cents": 600, - "product_price_in_cents": 600, - "product_version_number": 501, - "payment_type": null, - "referral_code": "rzqvrx", + "total_revenue_in_cents": 10009991, + "product_price_in_cents": 10000, + "product_version_number": 1, + "payment_type": "credit_card", + "referral_code": "8y7jqr", "coupon_use_count": null, "coupon_uses_allowed": null, "reason_code": null, - "automatically_resume_at": null, - "offer_id": null, - "credit_balance_in_cents": 0, - "prepayment_balance_in_cents": 0, - "payer_id": 142365, - "stored_credential_transaction_id": null, - "next_product_handle": null, - "on_hold_at": null, - "prepaid_dunning": false, + "automatically_resume_at": "2019-01-20T00:00:00-06:00", "customer": { - "id": 142365, - "first_name": "Lavern", - "last_name": "Fahey", - "organization": null, - "email": "millie2@example.com", - "created_at": "2018-10-22T13:10:46-06:00", - "updated_at": "2018-10-22T13:10:46-06:00", + "id": 19948683, + "first_name": "Vanessa", + "last_name": "Test", + "organization": "", + "email": "vanessa@example.com", + "created_at": "2018-01-05T17:15:49-06:00", + "updated_at": "2018-01-05T17:15:51-06:00", "reference": null, - "address": null, - "address_2": null, - "city": null, - "state": null, - "zip": null, - "country": null, - "phone": null, - "portal_invite_last_sent_at": null, + "address": "123 Anywhere Ln", + "address_2": "", + "city": "Boston", + "state": "MA", + "zip": "02120", + "country": "US", + "phone": "555-555-1212", + "portal_invite_last_sent_at": "2018-01-05T17:15:51-06:00", "portal_invite_last_accepted_at": null, - "verified": false, - "portal_customer_created_at": "2018-10-22T13:10:46-06:00", - "vat_number": null, - "cc_emails": "john@example.com, sue@example.com", - "tax_exempt": false, - "parent_id": null, - "locale": null + "verified": null, + "portal_customer_created_at": "2018-01-05T17:15:51-06:00", + "cc_emails": null, + "tax_exempt": false }, "product": { - "id": 8080, - "name": "Pro Versions", - "handle": null, + "id": 4535643, + "name": "Annual Product", + "handle": "annual-product", "description": "", "accounting_code": "", "request_credit_card": true, "expiration_interval": null, - "expiration_interval_unit": "month", - "created_at": "2019-02-15T10:15:00-07:00", - "updated_at": "2019-02-15T10:30:34-07:00", - "price_in_cents": 600, - "interval": 1, + "expiration_interval_unit": "never", + "created_at": "2017-08-25T10:25:31-05:00", + "updated_at": "2017-08-25T10:25:31-05:00", + "price_in_cents": 10000, + "interval": 12, "interval_unit": "month", "initial_charge_in_cents": null, "trial_price_in_cents": null, @@ -158,36 +148,39 @@ result = subscription_status_controller.retry_subscription(subscription_id) "archived_at": null, "require_credit_card": true, "return_params": "", - "require_shipping_address": false, - "request_billing_address": false, - "require_billing_address": false, "taxable": false, "update_return_url": "", "tax_code": "", "initial_charge_after_trial": false, - "default_product_price_point_id": 3464, - "version_number": 501, + "version_number": 1, "update_return_params": "", - "product_price_point_id": 3464, - "product_price_point_name": "Default", - "product_price_point_handle": "uuid:5305c3f0-1375-0137-5619-065dfbfdc636", "product_family": { - "id": 37, - "name": "Acme Projects", - "description": null, - "handle": "acme-projects", - "accounting_code": null, - "created_at": "2013-02-20T15:05:51-07:00", - "updated_at": "2013-02-20T15:05:51-07:00" - }, - "public_signup_pages": [ - { - "id": 1540, - "return_url": null, - "return_params": "", - "url": "https://acme-test.staging-chargifypay.com/subscribe/2f6y53rrqgsf" - } - ] + "id": 1025627, + "name": "Acme Products", + "description": "", + "handle": "acme-products", + "accounting_code": null + } + }, + "credit_card": { + "id": 13826563, + "first_name": "Bomb 3", + "last_name": "Test", + "masked_card_number": "XXXX-XXXX-XXXX-1", + "card_type": "bogus", + "expiration_month": 1, + "expiration_year": 2028, + "customer_id": 19948683, + "current_vault": "bogus", + "vault_token": "1", + "billing_address": "123 Anywhere Lane", + "billing_city": "Boston", + "billing_state": "Ma", + "billing_zip": "02120", + "billing_country": "US", + "customer_vault_token": null, + "billing_address_2": "", + "payment_type": "credit_card" } } } @@ -200,14 +193,18 @@ result = subscription_status_controller.retry_subscription(subscription_id) | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Cancel Subscription +# Initiate Delayed Cancellation -The DELETE action causes the cancellation of the Subscription. This means, the method sets the Subscription state to "canceled". +Advanced Billing offers the ability to cancel a subscription at the end of the current billing period. This period is set by its current product. + +Requesting to cancel the subscription at the end of the period sets the `cancel_at_end_of_period` flag to true. + +Note that you cannot set `cancel_at_end_of_period` at subscription creation, or if the subscription is past due. ```python -def cancel_subscription(self, - subscription_id, - body=None) +def initiate_delayed_cancellation(self, + subscription_id, + body=None) ``` ## Parameters @@ -219,148 +216,180 @@ def cancel_subscription(self, ## Response Type -[`SubscriptionResponse`](../../doc/models/subscription-response.md) +[`DelayedCancellationResponse`](../../doc/models/delayed-cancellation-response.md) ## Example Usage ```python subscription_id = 222 -result = subscription_status_controller.cancel_subscription(subscription_id) +result = subscription_status_controller.initiate_delayed_cancellation(subscription_id) ``` -## Example Response *(as JSON)* +## Errors -```json -{ - "subscription": { - "id": 15254809, - "state": "canceled", - "trial_started_at": null, - "trial_ended_at": null, - "activated_at": "2016-11-15T15:33:44-05:00", - "created_at": "2016-11-15T15:33:44-05:00", - "updated_at": "2016-11-15T17:13:06-05:00", - "expires_at": null, - "balance_in_cents": 0, - "current_period_ends_at": "2017-08-29T12:00:00-04:00", - "next_assessment_at": "2017-08-29T12:00:00-04:00", - "canceled_at": "2016-11-15T17:13:06-05:00", - "cancellation_message": "Canceling the subscription via the API", - "next_product_id": null, - "cancel_at_end_of_period": false, - "payment_collection_method": "automatic", - "snap_day": null, - "cancellation_method": "merchant_api", - "current_period_started_at": "2016-11-15T15:33:44-05:00", - "previous_state": "active", - "signup_payment_id": 0, - "signup_revenue": "0.00", - "delayed_cancel_at": null, - "coupon_code": null, - "total_revenue_in_cents": 0, - "product_price_in_cents": 1000, - "product_version_number": 7, - "payment_type": "credit_card", - "referral_code": "tg8qbq", - "coupon_use_count": null, - "coupon_uses_allowed": null, - "customer": { - "id": 14731081, - "first_name": "John", - "last_name": "Doe", - "organization": "Acme Widgets", - "email": "john.doe@example.com", - "created_at": "2016-11-15T15:33:44-05:00", - "updated_at": "2016-11-15T15:33:45-05:00", - "reference": "123", - "address": null, - "address_2": null, - "city": null, - "state": null, - "zip": null, - "country": null, - "phone": null, - "portal_invite_last_sent_at": "2016-11-15T15:33:45-05:00", - "portal_invite_last_accepted_at": null, - "verified": false, - "portal_customer_created_at": "2016-11-15T15:33:45-05:00", - "cc_emails": null - }, - "product": { - "id": 3792003, - "name": "$10 Basic Plan", - "handle": "basic", - "description": "lorem ipsum", - "accounting_code": "basic", - "request_credit_card": false, - "expiration_interval": null, - "expiration_interval_unit": "never", - "created_at": "2016-03-24T13:38:39-04:00", - "updated_at": "2016-11-03T13:03:05-04:00", - "price_in_cents": 1000, - "interval": 1, - "interval_unit": "day", - "initial_charge_in_cents": null, - "trial_price_in_cents": null, - "trial_interval": null, - "trial_interval_unit": "month", - "archived_at": null, - "require_credit_card": false, - "return_params": "", - "taxable": false, - "update_return_url": "", - "initial_charge_after_trial": false, - "version_number": 7, - "update_return_params": "", - "product_family": { - "id": 527890, - "name": "Acme Projects", - "description": "", - "handle": "billing-plans", - "accounting_code": null +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | + + +# Cancel Delayed Cancellation + +Removing the delayed cancellation on a subscription will ensure that it doesn't get canceled at the end of the period that it is in. The request will reset the `cancel_at_end_of_period` flag to `false`. + +This endpoint is idempotent. If the subscription was not set to cancel in the future, removing the delayed cancellation has no effect and the call will be successful. + +```python +def cancel_delayed_cancellation(self, + subscription_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | + +## Response Type + +[`DelayedCancellationResponse`](../../doc/models/delayed-cancellation-response.md) + +## Example Usage + +```python +subscription_id = 222 + +result = subscription_status_controller.cancel_delayed_cancellation(subscription_id) +``` + +## Example Response *(as JSON)* + +```json +{ + "message": "This subscription will no longer be canceled" +} +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | + + +# Preview Renewal + +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). + +## Optional Component Fields + +This endpoint is particularly useful due to the fact that it will return the computed billing amount for the base product and the components which are in use by a subscriber. + +By default, the preview will include billing details for all components _at their **current** quantities_. This means: + +* Current `allocated_quantity` for quantity-based components +* Current enabled/disabled status for on/off components +* Current metered usage `unit_balance` for metered components +* Current metric quantity value for events recorded thus far for events-based components + +In the above statements, "current" means the quantity or value as of the call to the renewal preview endpoint. We do not predict end-of-period values for components, so metered or events-based usage may be less than it will eventually be at the end of the period. + +Optionally, **you may provide your own custom quantities** for any component to see a billing preview for non-current quantities. This is accomplished by sending a request body with data under the `components` key. See the request body documentation below. + +## Subscription Side Effects + +You can request a `POST` to obtain this data from the endpoint without any side effects. Plain and simple, this will preview data, not log any changes against a subscription. + +```python +def preview_renewal(self, + subscription_id, + body=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `body` | [`RenewalPreviewRequest`](../../doc/models/renewal-preview-request.md) | Body, Optional | - | + +## Response Type + +[`RenewalPreviewResponse`](../../doc/models/renewal-preview-response.md) + +## Example Usage + +```python +subscription_id = 222 + +body = RenewalPreviewRequest( + components=[ + RenewalPreviewComponent( + component_id=10708, + quantity=10000 + ), + RenewalPreviewComponent( + component_id='handle:small-instance-hours', + quantity=10000, + price_point_id=8712 + ), + RenewalPreviewComponent( + component_id='handle:large-instance-hours', + quantity=100, + price_point_id='handle:startup-pricing' + ) + ] +) + +result = subscription_status_controller.preview_renewal( + subscription_id, + body=body +) +``` + +## Example Response *(as JSON)* + +```json +{ + "renewal_preview": { + "next_assessment_at": "2017-03-13T12:50:55-04:00", + "subtotal_in_cents": 6000, + "total_tax_in_cents": 0, + "total_discount_in_cents": 0, + "total_in_cents": 6000, + "existing_balance_in_cents": 0, + "total_amount_due_in_cents": 6000, + "uncalculated_taxes": false, + "line_items": [ + { + "transaction_type": "charge", + "kind": "baseline", + "amount_in_cents": 5000, + "memo": "Gold Product (03/13/2017 - 04/13/2017)", + "discount_amount_in_cents": 0, + "taxable_amount_in_cents": 0, + "product_id": 1, + "product_handle": "gold-product", + "product_name": "Gold Product", + "period_range_start": "01/10/2024", + "period_range_end": "02/10/2024" }, - "public_signup_pages": [ - { - "id": 281054, - "return_url": "http://www.example.com?successfulsignup", - "return_params": "", - "url": "https://general-goods.chargify.com/subscribe/kqvmfrbgd89q/basic" - }, - { - "id": 281240, - "return_url": "", - "return_params": "", - "url": "https://general-goods.chargify.com/subscribe/dkffht5dxfd8/basic" - }, - { - "id": 282694, - "return_url": "", - "return_params": "", - "url": "https://general-goods.chargify.com/subscribe/jwffwgdd95s8/basic" - } - ] - }, - "credit_card": { - "id": 10202898, - "first_name": "John", - "last_name": "Doe", - "masked_card_number": "XXXX-XXXX-XXXX-1111", - "card_type": "visa", - "expiration_month": 12, - "expiration_year": 2020, - "customer_id": 14731081, - "current_vault": "authorizenet", - "vault_token": "12345", - "billing_address": null, - "billing_city": null, - "billing_state": null, - "billing_zip": null, - "billing_country": null, - "customer_vault_token": "67890", - "billing_address_2": null, - "payment_type": "credit_card" - } + { + "transaction_type": "charge", + "kind": "quantity_based_component", + "amount_in_cents": 1000, + "memo": "Quantity Component: 10 Quantity Components", + "discount_amount_in_cents": 0, + "taxable_amount_in_cents": 0, + "component_id": 104, + "component_handle": "quantity-component", + "component_name": "Quantity Component", + "period_range_start": "01/10/2024", + "period_range_end": "02/10/2024" + } + ] } } ``` @@ -369,8 +398,7 @@ result = subscription_status_controller.cancel_subscription(subscription_id) | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | # Resume Subscription @@ -623,17 +651,186 @@ result = subscription_status_controller.pause_subscription( "tax_exempt": true }, "product": { - "id": 4470347, - "name": "Zero Dollar Product", - "handle": "zero-dollar-product", + "id": 4470347, + "name": "Zero Dollar Product", + "handle": "zero-dollar-product", + "description": "", + "accounting_code": "", + "request_credit_card": true, + "expiration_interval": null, + "expiration_interval_unit": "never", + "created_at": "2017-03-23T10:54:12-05:00", + "updated_at": "2017-04-20T15:18:46-05:00", + "price_in_cents": 0, + "interval": 1, + "interval_unit": "month", + "initial_charge_in_cents": null, + "trial_price_in_cents": null, + "trial_interval": null, + "trial_interval_unit": "month", + "archived_at": null, + "require_credit_card": false, + "return_params": "", + "taxable": false, + "update_return_url": "", + "tax_code": "", + "initial_charge_after_trial": false, + "version_number": 1, + "update_return_params": "", + "product_family": { + "id": 997233, + "name": "Acme Products", + "description": "", + "handle": "acme-products", + "accounting_code": null + }, + "public_signup_pages": [ + { + "id": 316810, + "return_url": "", + "return_params": "", + "url": "https://general-goods.chargify.com/subscribe/69x825m78v3d/zero-dollar-product" + } + ] + } + } +} +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + + +# Retry Subscription + +Advanced Billing offers the ability to retry collecting the balance due on a past due Subscription without waiting for the next scheduled attempt. + +## Successful Reactivation + +The response will be `200 OK` with the updated Subscription. + +## Failed Reactivation + +The response will be `422 "Unprocessable Entity`. + +```python +def retry_subscription(self, + subscription_id) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | + +## Response Type + +[`SubscriptionResponse`](../../doc/models/subscription-response.md) + +## Example Usage + +```python +subscription_id = 222 + +result = subscription_status_controller.retry_subscription(subscription_id) +``` + +## Example Response *(as JSON)* + +```json +{ + "subscription": { + "id": 46330, + "state": "active", + "trial_started_at": null, + "trial_ended_at": null, + "activated_at": "2018-10-22T13:10:46-06:00", + "created_at": "2018-10-22T13:10:46-06:00", + "updated_at": "2021-06-10T09:23:43-06:00", + "expires_at": null, + "balance_in_cents": 18600, + "current_period_ends_at": "2021-06-22T13:10:46-06:00", + "next_assessment_at": "2021-06-22T13:10:46-06:00", + "canceled_at": null, + "cancellation_message": null, + "next_product_id": null, + "cancel_at_end_of_period": null, + "payment_collection_method": "automatic", + "snap_day": null, + "cancellation_method": null, + "product_price_point_id": 3464, + "next_product_price_point_id": null, + "receives_invoice_emails": null, + "net_terms": null, + "locale": null, + "currency": "USD", + "reference": null, + "scheduled_cancellation_at": null, + "current_period_started_at": "2021-05-22T13:10:46-06:00", + "previous_state": "past_due", + "signup_payment_id": 651268, + "signup_revenue": "6.00", + "delayed_cancel_at": null, + "coupon_code": null, + "total_revenue_in_cents": 600, + "product_price_in_cents": 600, + "product_version_number": 501, + "payment_type": null, + "referral_code": "rzqvrx", + "coupon_use_count": null, + "coupon_uses_allowed": null, + "reason_code": null, + "automatically_resume_at": null, + "offer_id": null, + "credit_balance_in_cents": 0, + "prepayment_balance_in_cents": 0, + "payer_id": 142365, + "stored_credential_transaction_id": null, + "next_product_handle": null, + "on_hold_at": null, + "prepaid_dunning": false, + "customer": { + "id": 142365, + "first_name": "Lavern", + "last_name": "Fahey", + "organization": null, + "email": "millie2@example.com", + "created_at": "2018-10-22T13:10:46-06:00", + "updated_at": "2018-10-22T13:10:46-06:00", + "reference": null, + "address": null, + "address_2": null, + "city": null, + "state": null, + "zip": null, + "country": null, + "phone": null, + "portal_invite_last_sent_at": null, + "portal_invite_last_accepted_at": null, + "verified": false, + "portal_customer_created_at": "2018-10-22T13:10:46-06:00", + "vat_number": null, + "cc_emails": "john@example.com, sue@example.com", + "tax_exempt": false, + "parent_id": null, + "locale": null + }, + "product": { + "id": 8080, + "name": "Pro Versions", + "handle": null, "description": "", "accounting_code": "", "request_credit_card": true, "expiration_interval": null, - "expiration_interval_unit": "never", - "created_at": "2017-03-23T10:54:12-05:00", - "updated_at": "2017-04-20T15:18:46-05:00", - "price_in_cents": 0, + "expiration_interval_unit": "month", + "created_at": "2019-02-15T10:15:00-07:00", + "updated_at": "2019-02-15T10:30:34-07:00", + "price_in_cents": 600, "interval": 1, "interval_unit": "month", "initial_charge_in_cents": null, @@ -641,27 +838,36 @@ result = subscription_status_controller.pause_subscription( "trial_interval": null, "trial_interval_unit": "month", "archived_at": null, - "require_credit_card": false, + "require_credit_card": true, "return_params": "", + "require_shipping_address": false, + "request_billing_address": false, + "require_billing_address": false, "taxable": false, "update_return_url": "", "tax_code": "", "initial_charge_after_trial": false, - "version_number": 1, + "default_product_price_point_id": 3464, + "version_number": 501, "update_return_params": "", + "product_price_point_id": 3464, + "product_price_point_name": "Default", + "product_price_point_handle": "uuid:5305c3f0-1375-0137-5619-065dfbfdc636", "product_family": { - "id": 997233, - "name": "Acme Products", - "description": "", - "handle": "acme-products", - "accounting_code": null + "id": 37, + "name": "Acme Projects", + "description": null, + "handle": "acme-projects", + "accounting_code": null, + "created_at": "2013-02-20T15:05:51-07:00", + "updated_at": "2013-02-20T15:05:51-07:00" }, "public_signup_pages": [ { - "id": 316810, - "return_url": "", + "id": 1540, + "return_url": null, "return_params": "", - "url": "https://general-goods.chargify.com/subscribe/69x825m78v3d/zero-dollar-product" + "url": "https://acme-test.staging-chargifypay.com/subscribe/2f6y53rrqgsf" } ] } @@ -676,20 +882,14 @@ result = subscription_status_controller.pause_subscription( | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Update Automatic Subscription Resumption - -Once a subscription has been paused / put on hold, you can update the date which was specified to automatically resume the subscription. - -To update a subscription's resume date, use this method to change or update the `automatically_resume_at` date. - -### Remove the resume date +# Cancel Subscription -Alternately, you can change the `automatically_resume_at` to `null` if you would like the subscription to not have a resume date. +The DELETE action causes the cancellation of the Subscription. This means, the method sets the Subscription state to "canceled". ```python -def update_automatic_subscription_resumption(self, - subscription_id, - body=None) +def cancel_subscription(self, + subscription_id, + body=None) ``` ## Parameters @@ -697,7 +897,7 @@ def update_automatic_subscription_resumption(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `body` | [`PauseRequest`](../../doc/models/pause-request.md) | Body, Optional | Allows to pause a Subscription | +| `body` | [`CancellationRequest`](../../doc/models/cancellation-request.md) | Body, Optional | - | ## Response Type @@ -708,16 +908,7 @@ def update_automatic_subscription_resumption(self, ```python subscription_id = 222 -body = PauseRequest( - hold=AutoResume( - automatically_resume_at=dateutil.parser.parse('2019-01-20T00:00:00') - ) -) - -result = subscription_status_controller.update_automatic_subscription_resumption( - subscription_id, - body=body -) +result = subscription_status_controller.cancel_subscription(subscription_id) ``` ## Example Response *(as JSON)* @@ -725,126 +916,171 @@ result = subscription_status_controller.update_automatic_subscription_resumption ```json { "subscription": { - "id": 20359140, - "state": "on_hold", + "id": 15254809, + "state": "canceled", "trial_started_at": null, "trial_ended_at": null, - "activated_at": "2018-01-05T17:15:50-06:00", - "created_at": "2018-01-05T17:15:49-06:00", - "updated_at": "2018-01-09T10:26:14-06:00", + "activated_at": "2016-11-15T15:33:44-05:00", + "created_at": "2016-11-15T15:33:44-05:00", + "updated_at": "2016-11-15T17:13:06-05:00", "expires_at": null, "balance_in_cents": 0, - "current_period_ends_at": "2023-01-05T17:15:00-06:00", - "next_assessment_at": "2023-01-05T17:15:00-06:00", - "canceled_at": null, - "cancellation_message": null, + "current_period_ends_at": "2017-08-29T12:00:00-04:00", + "next_assessment_at": "2017-08-29T12:00:00-04:00", + "canceled_at": "2016-11-15T17:13:06-05:00", + "cancellation_message": "Canceling the subscription via the API", "next_product_id": null, "cancel_at_end_of_period": false, "payment_collection_method": "automatic", "snap_day": null, - "cancellation_method": null, - "current_period_started_at": "2018-01-05T17:15:49-06:00", + "cancellation_method": "merchant_api", + "current_period_started_at": "2016-11-15T15:33:44-05:00", "previous_state": "active", - "signup_payment_id": 219829722, - "signup_revenue": "100.00", + "signup_payment_id": 0, + "signup_revenue": "0.00", "delayed_cancel_at": null, "coupon_code": null, - "total_revenue_in_cents": 10009991, - "product_price_in_cents": 10000, - "product_version_number": 1, + "total_revenue_in_cents": 0, + "product_price_in_cents": 1000, + "product_version_number": 7, "payment_type": "credit_card", - "referral_code": "8y7jqr", + "referral_code": "tg8qbq", "coupon_use_count": null, "coupon_uses_allowed": null, - "reason_code": null, - "automatically_resume_at": "2019-01-20T00:00:00-06:00", "customer": { - "id": 19948683, - "first_name": "Vanessa", - "last_name": "Test", - "organization": "", - "email": "vanessa@example.com", - "created_at": "2018-01-05T17:15:49-06:00", - "updated_at": "2018-01-05T17:15:51-06:00", - "reference": null, - "address": "123 Anywhere Ln", - "address_2": "", - "city": "Boston", - "state": "MA", - "zip": "02120", - "country": "US", - "phone": "555-555-1212", - "portal_invite_last_sent_at": "2018-01-05T17:15:51-06:00", + "id": 14731081, + "first_name": "John", + "last_name": "Doe", + "organization": "Acme Widgets", + "email": "john.doe@example.com", + "created_at": "2016-11-15T15:33:44-05:00", + "updated_at": "2016-11-15T15:33:45-05:00", + "reference": "123", + "address": null, + "address_2": null, + "city": null, + "state": null, + "zip": null, + "country": null, + "phone": null, + "portal_invite_last_sent_at": "2016-11-15T15:33:45-05:00", "portal_invite_last_accepted_at": null, - "verified": null, - "portal_customer_created_at": "2018-01-05T17:15:51-06:00", - "cc_emails": null, - "tax_exempt": false + "verified": false, + "portal_customer_created_at": "2016-11-15T15:33:45-05:00", + "cc_emails": null }, "product": { - "id": 4535643, - "name": "Annual Product", - "handle": "annual-product", - "description": "", - "accounting_code": "", - "request_credit_card": true, + "id": 3792003, + "name": "$10 Basic Plan", + "handle": "basic", + "description": "lorem ipsum", + "accounting_code": "basic", + "request_credit_card": false, "expiration_interval": null, "expiration_interval_unit": "never", - "created_at": "2017-08-25T10:25:31-05:00", - "updated_at": "2017-08-25T10:25:31-05:00", - "price_in_cents": 10000, - "interval": 12, - "interval_unit": "month", + "created_at": "2016-03-24T13:38:39-04:00", + "updated_at": "2016-11-03T13:03:05-04:00", + "price_in_cents": 1000, + "interval": 1, + "interval_unit": "day", "initial_charge_in_cents": null, "trial_price_in_cents": null, "trial_interval": null, "trial_interval_unit": "month", "archived_at": null, - "require_credit_card": true, + "require_credit_card": false, "return_params": "", "taxable": false, "update_return_url": "", - "tax_code": "", "initial_charge_after_trial": false, - "version_number": 1, + "version_number": 7, "update_return_params": "", "product_family": { - "id": 1025627, - "name": "Acme Products", + "id": 527890, + "name": "Acme Projects", "description": "", - "handle": "acme-products", + "handle": "billing-plans", "accounting_code": null - } + }, + "public_signup_pages": [ + { + "id": 281054, + "return_url": "http://www.example.com?successfulsignup", + "return_params": "", + "url": "https://general-goods.chargify.com/subscribe/kqvmfrbgd89q/basic" + }, + { + "id": 281240, + "return_url": "", + "return_params": "", + "url": "https://general-goods.chargify.com/subscribe/dkffht5dxfd8/basic" + }, + { + "id": 282694, + "return_url": "", + "return_params": "", + "url": "https://general-goods.chargify.com/subscribe/jwffwgdd95s8/basic" + } + ] }, "credit_card": { - "id": 13826563, - "first_name": "Bomb 3", - "last_name": "Test", - "masked_card_number": "XXXX-XXXX-XXXX-1", - "card_type": "bogus", - "expiration_month": 1, - "expiration_year": 2028, - "customer_id": 19948683, - "current_vault": "bogus", - "vault_token": "1", - "billing_address": "123 Anywhere Lane", - "billing_city": "Boston", - "billing_state": "Ma", - "billing_zip": "02120", - "billing_country": "US", - "customer_vault_token": null, - "billing_address_2": "", + "id": 10202898, + "first_name": "John", + "last_name": "Doe", + "masked_card_number": "XXXX-XXXX-XXXX-1111", + "card_type": "visa", + "expiration_month": 12, + "expiration_year": 2020, + "customer_id": 14731081, + "current_vault": "authorizenet", + "vault_token": "12345", + "billing_address": null, + "billing_city": null, + "billing_state": null, + "billing_zip": null, + "billing_country": null, + "customer_vault_token": "67890", + "billing_address_2": null, "payment_type": "credit_card" } } } ``` -## Errors +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | `APIException` | + + +# Cancel Dunning + +If a subscription is currently in dunning, the subscription will be set to active and the active Dunner will be resolved. + +```python +def cancel_dunning(self, + subscription_id) +``` + +## Parameters -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | + +## Response Type + +[`SubscriptionResponse`](../../doc/models/subscription-response.md) + +## Example Usage + +```python +subscription_id = 222 + +result = subscription_status_controller.cancel_dunning(subscription_id) +``` # Reactivate Subscription @@ -1164,239 +1400,3 @@ result = subscription_status_controller.reactivate_subscription( | --- | --- | --- | | 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - -# Initiate Delayed Cancellation - -Advanced Billing offers the ability to cancel a subscription at the end of the current billing period. This period is set by its current product. - -Requesting to cancel the subscription at the end of the period sets the `cancel_at_end_of_period` flag to true. - -Note that you cannot set `cancel_at_end_of_period` at subscription creation, or if the subscription is past due. - -```python -def initiate_delayed_cancellation(self, - subscription_id, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `body` | [`CancellationRequest`](../../doc/models/cancellation-request.md) | Body, Optional | - | - -## Response Type - -[`DelayedCancellationResponse`](../../doc/models/delayed-cancellation-response.md) - -## Example Usage - -```python -subscription_id = 222 - -result = subscription_status_controller.initiate_delayed_cancellation(subscription_id) -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | - - -# Cancel Delayed Cancellation - -Removing the delayed cancellation on a subscription will ensure that it doesn't get canceled at the end of the period that it is in. The request will reset the `cancel_at_end_of_period` flag to `false`. - -This endpoint is idempotent. If the subscription was not set to cancel in the future, removing the delayed cancellation has no effect and the call will be successful. - -```python -def cancel_delayed_cancellation(self, - subscription_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | - -## Response Type - -[`DelayedCancellationResponse`](../../doc/models/delayed-cancellation-response.md) - -## Example Usage - -```python -subscription_id = 222 - -result = subscription_status_controller.cancel_delayed_cancellation(subscription_id) -``` - -## Example Response *(as JSON)* - -```json -{ - "message": "This subscription will no longer be canceled" -} -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | - - -# Cancel Dunning - -If a subscription is currently in dunning, the subscription will be set to active and the active Dunner will be resolved. - -```python -def cancel_dunning(self, - subscription_id) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | - -## Response Type - -[`SubscriptionResponse`](../../doc/models/subscription-response.md) - -## Example Usage - -```python -subscription_id = 222 - -result = subscription_status_controller.cancel_dunning(subscription_id) -``` - - -# Preview Renewal - -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). - -## Optional Component Fields - -This endpoint is particularly useful due to the fact that it will return the computed billing amount for the base product and the components which are in use by a subscriber. - -By default, the preview will include billing details for all components _at their **current** quantities_. This means: - -* Current `allocated_quantity` for quantity-based components -* Current enabled/disabled status for on/off components -* Current metered usage `unit_balance` for metered components -* Current metric quantity value for events recorded thus far for events-based components - -In the above statements, "current" means the quantity or value as of the call to the renewal preview endpoint. We do not predict end-of-period values for components, so metered or events-based usage may be less than it will eventually be at the end of the period. - -Optionally, **you may provide your own custom quantities** for any component to see a billing preview for non-current quantities. This is accomplished by sending a request body with data under the `components` key. See the request body documentation below. - -## Subscription Side Effects - -You can request a `POST` to obtain this data from the endpoint without any side effects. Plain and simple, this will preview data, not log any changes against a subscription. - -```python -def preview_renewal(self, - subscription_id, - body=None) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `body` | [`RenewalPreviewRequest`](../../doc/models/renewal-preview-request.md) | Body, Optional | - | - -## Response Type - -[`RenewalPreviewResponse`](../../doc/models/renewal-preview-response.md) - -## Example Usage - -```python -subscription_id = 222 - -body = RenewalPreviewRequest( - components=[ - RenewalPreviewComponent( - component_id=10708, - quantity=10000 - ), - RenewalPreviewComponent( - component_id='handle:small-instance-hours', - quantity=10000, - price_point_id=8712 - ), - RenewalPreviewComponent( - component_id='handle:large-instance-hours', - quantity=100, - price_point_id='handle:startup-pricing' - ) - ] -) - -result = subscription_status_controller.preview_renewal( - subscription_id, - body=body -) -``` - -## Example Response *(as JSON)* - -```json -{ - "renewal_preview": { - "next_assessment_at": "2017-03-13T12:50:55-04:00", - "subtotal_in_cents": 6000, - "total_tax_in_cents": 0, - "total_discount_in_cents": 0, - "total_in_cents": 6000, - "existing_balance_in_cents": 0, - "total_amount_due_in_cents": 6000, - "uncalculated_taxes": false, - "line_items": [ - { - "transaction_type": "charge", - "kind": "baseline", - "amount_in_cents": 5000, - "memo": "Gold Product (03/13/2017 - 04/13/2017)", - "discount_amount_in_cents": 0, - "taxable_amount_in_cents": 0, - "product_id": 1, - "product_handle": "gold-product", - "product_name": "Gold Product", - "period_range_start": "01/10/2024", - "period_range_end": "02/10/2024" - }, - { - "transaction_type": "charge", - "kind": "quantity_based_component", - "amount_in_cents": 1000, - "memo": "Quantity Component: 10 Quantity Components", - "discount_amount_in_cents": 0, - "taxable_amount_in_cents": 0, - "component_id": 104, - "component_handle": "quantity-component", - "component_name": "Quantity Component", - "period_range_start": "01/10/2024", - "period_range_end": "02/10/2024" - } - ] - } -} -``` - -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - diff --git a/doc/controllers/subscriptions.md b/doc/controllers/subscriptions.md index 2306b35d..ee32e1c0 100644 --- a/doc/controllers/subscriptions.md +++ b/doc/controllers/subscriptions.md @@ -10,672 +10,422 @@ subscriptions_controller = client.subscriptions ## Methods -* [Create Subscription](../../doc/controllers/subscriptions.md#create-subscription) * [List Subscriptions](../../doc/controllers/subscriptions.md#list-subscriptions) +* [Purge Subscription](../../doc/controllers/subscriptions.md#purge-subscription) +* [Apply Coupons to Subscription](../../doc/controllers/subscriptions.md#apply-coupons-to-subscription) +* [Update Prepaid Subscription Configuration](../../doc/controllers/subscriptions.md#update-prepaid-subscription-configuration) +* [Preview Subscription](../../doc/controllers/subscriptions.md#preview-subscription) +* [Create Subscription](../../doc/controllers/subscriptions.md#create-subscription) * [Update Subscription](../../doc/controllers/subscriptions.md#update-subscription) * [Read Subscription](../../doc/controllers/subscriptions.md#read-subscription) * [Override Subscription](../../doc/controllers/subscriptions.md#override-subscription) * [Find Subscription](../../doc/controllers/subscriptions.md#find-subscription) -* [Purge Subscription](../../doc/controllers/subscriptions.md#purge-subscription) -* [Update Prepaid Subscription Configuration](../../doc/controllers/subscriptions.md#update-prepaid-subscription-configuration) -* [Preview Subscription](../../doc/controllers/subscriptions.md#preview-subscription) -* [Apply Coupons to Subscription](../../doc/controllers/subscriptions.md#apply-coupons-to-subscription) * [Remove Coupon From Subscription](../../doc/controllers/subscriptions.md#remove-coupon-from-subscription) * [Activate Subscription](../../doc/controllers/subscriptions.md#activate-subscription) -# Create Subscription +# List Subscriptions -Full documentation on how subscriptions operate within Advanced Billing can be located under the following topics: +This method will return an array of subscriptions from a Site. Pay close attention to query string filters and pagination in order to control responses from the server. -+ [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) +## Search for a subscription -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)). +Use the query strings below to search for a subscription using the criteria available. The return value will be an array. -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`. +## Self-Service Page token -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`. +Self-Service Page token for the subscriptions is not returned by default. If this information is desired, the include[]=self_service_page_token parameter must be provided with the request. -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). +```python +def list_subscriptions(self, + options=dict()) +``` -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`. +## Parameters -## Taxable Subscriptions +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `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`. | +| `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`. | +| `state` | [`SubscriptionStateFilter`](../../doc/models/subscription-state-filter.md) | Query, Optional | The current state of the subscription | +| `product` | `int` | Query, Optional | The product id of the subscription. (Note that the product handle cannot be used.) | +| `product_price_point_id` | `int` | Query, Optional | The ID of the product price point. If supplied, product is required | +| `coupon` | `int` | Query, Optional | The numeric id of the coupon currently applied to the subscription. (This can be found in the URL when editing a coupon. Note that the coupon code cannot be used.) | +| `date_field` | [`SubscriptionDateField`](../../doc/models/subscription-date-field.md) | Query, Optional | The type of filter you'd like to apply to your search. Allowed Values: , current_period_ends_at, current_period_starts_at, created_at, activated_at, canceled_at, expires_at, trial_started_at, trial_ended_at, updated_at | +| `start_date` | `date` | Query, Optional | The start date (format YYYY-MM-DD) with which to filter the date_field. Returns subscriptions with a timestamp at or after midnight (12:00:00 AM) in your site’s time zone on the date specified. Use in query `start_date=2022-07-01`. | +| `end_date` | `date` | Query, Optional | The end date (format YYYY-MM-DD) with which to filter the date_field. Returns subscriptions with a timestamp up to and including 11:59:59PM in your site’s time zone on the date specified. Use in query `end_date=2022-08-01`. | +| `start_datetime` | `datetime` | Query, Optional | The start date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns subscriptions with a timestamp at or after 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 start_date. Use in query `start_datetime=2022-07-01 09:00:05`. | +| `end_datetime` | `datetime` | Query, Optional | The end date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns subscriptions 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 `end_datetime=2022-08-01 10:00:05`. | +| `metadata` | `Dict[str, str]` | Query, Optional | The value of the metadata field specified in the parameter. Use in query `metadata[my-field]=value&metadata[other-field]=another_value`. | +| `direction` | [`SortingDirection`](../../doc/models/sorting-direction.md) | Query, Optional | Controls the order in which results are returned.
Use in query `direction=asc`. | +| `sort` | [`SubscriptionSort`](../../doc/models/subscription-sort.md) | Query, Optional | The attribute by which to sort | +| `include` | [`List[SubscriptionListInclude]`](../../doc/models/subscription-list-include.md) | Query, Optional | Allows including additional data in the response. Use in query: `include[]=self_service_page_token`. | -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: +## Response Type -+ 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. +[`List[SubscriptionResponse]`](../../doc/models/subscription-response.md) -## Subscription Request Examples +## Example Usage -The subscription examples below will be split into two sections. +```python +collect = { + 'page': 2, + 'per_page': 50, + 'start_date': dateutil.parser.parse('2022-07-01').date(), + 'end_date': dateutil.parser.parse('2022-08-01').date(), + 'start_datetime': dateutil.parser.parse('2022-07-01 09:00:05'), + 'end_datetime': dateutil.parser.parse('2022-08-01 10:00:05'), + 'sort': SubscriptionSort.SIGNUP_DATE, + 'include': [ + SubscriptionListInclude.SELF_SERVICE_PAGE_TOKEN + ] +} +result = subscriptions_controller.list_subscriptions(collect) +``` -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. +# Purge Subscription -# Subscription Customization +For sites in test mode, you may purge individual subscriptions. -## With Components +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` -Different components require slightly different data. For example, quantity-based and on/off components accept `allocated_quantity`, while metered components accept `unit_balance`. +If you need to remove subscriptions from a live site, please contact support to discuss your use case. -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. +### Delete customer and payment profile -Note: if an invalid `price_point_id` is used, the subscription will still proceed but will use the component's default price point. +The query params will be: `?ack={customer_id}&cascade[]=customer&cascade[]=payment_profile` -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. +```python +def purge_subscription(self, + subscription_id, + ack, + cascade=None) +``` -## With Coupon(s) +## Parameters -Pass an array of `coupon_codes`. See the example request body "With Coupon". +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `ack` | `int` | Query, Required | id of the customer. | +| `cascade` | [`List[SubscriptionPurgeType]`](../../doc/models/subscription-purge-type.md) | Query, Optional | Options are "customer" or "payment_profile".
Use in query: `cascade[]=customer&cascade[]=payment_profile`. | -## With Manual Invoice Collection +## Response Type -The `invoice` collection method works only on legacy Statement Architecture. +`void` -On Relationship Invoicing Architecture use the `remittance` collection method. +## Example Usage -## Prepaid Subscription +```python +subscription_id = 222 -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`. +ack = 252 -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). +cascade = [ + SubscriptionPurgeType.CUSTOMER, + SubscriptionPurgeType.PAYMENT_PROFILE +] -Prepaid subscriptions do not work on legacy Statement Architecture. +subscriptions_controller.purge_subscription( + subscription_id, + ack, + cascade=cascade +) +``` -## With Metafields -Metafields can either attach to subscriptions or customers. Metafields are popuplated with the supplied metadata to the resource specified. +# Apply Coupons to Subscription -If the metafield doesn't exist yet, it will be created on-the-fly. +An existing subscription can accommodate multiple discounts/coupon codes. This is only applicable if each coupon is stackable. For more information on stackable coupons, we recommend reviewing our [coupon documentation.](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupons-and-Subscriptions#stackability-rules) -## With Custom Pricing +## Query Parameters vs Request Body Parameters -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 in a coupon code as a query parameter will add the code to the subscription, completely replacing all existing coupon codes on the subscription. -# Passing Payment Information +For this reason, using this query parameter on this endpoint has been deprecated in favor of using the request body parameters as described below. When passing in request body parameters, the list of coupon codes will simply be added to any existing list of codes on the subscription. -## Subscription with Chargify.js token +```python +def apply_coupons_to_subscription(self, + subscription_id, + code=None, + body=None) +``` -The `chargify_token` can be obtained using [Chargify.js](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDI0-overview). The token represents payment profile attributes that were provided by the customer in their browser and stored at the payment gateway. +## Parameters -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`. +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `code` | `str` | Query, Optional | A code for the coupon that would be applied to a subscription | +| `body` | [`AddCouponsRequest`](../../doc/models/add-coupons-request.md) | Body, Optional | - | -```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" - } - } -} -``` +## Response Type -## Subscription with vault token +[`SubscriptionResponse`](../../doc/models/subscription-response.md) -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. +## Example Usage -```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" - } -} -``` +```python +subscription_id = 222 -## Subscription with Credit Card +body = AddCouponsRequest( + codes=[ + 'COUPON_1', + 'COUPON_2' + ] +) -```json -"subscription": { - "product_handle": "basic", - "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." - }, - "credit_card_attributes": { - "last_name": "Smith", - "first_name": "Joe", - "full_number": "4111111111111111", - "expiration_year": "2021", - "expiration_month": "1", - "card_type": "visa", - "billing_zip": "02120", - "billing_state": "MA", - "billing_country": "US", - "billing_city": "Boston", - "billing_address_2": null, - "billing_address": "123 Mass Ave." - } -} +result = subscriptions_controller.apply_coupons_to_subscription( + subscription_id, + body=body +) ``` -## Subscription with ACH as Payment Profile +## Example Response *(as JSON)* ```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://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#minimal-example-with-direct-debit-gocardless-gateway) - -+ [Using Chargify.js with GoCardless - full example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#full-example-with-direct-debit-gocardless-gateway) - -```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://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#minimal-example-with-sepa-or-becs-direct-debit-stripe-gateway) - -+ [Using Chargify.js with Stripe SEPA Direct Debit - full example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#full-example-with-sepa-direct-debit-stripe-gateway) - -```json -{ - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" + "id": 21607180, + "state": "active", + "trial_started_at": null, + "trial_ended_at": null, + "activated_at": "2018-04-20T14:20:57-05:00", + "created_at": "2018-04-20T14:20:57-05:00", + "updated_at": "2018-05-11T13:53:44-05:00", + "expires_at": null, + "balance_in_cents": 49000, + "current_period_ends_at": "2018-05-12T11:33:03-05:00", + "next_assessment_at": "2018-05-12T11:33:03-05:00", + "canceled_at": null, + "cancellation_message": null, + "next_product_id": null, + "cancel_at_end_of_period": false, + "payment_collection_method": "remittance", + "snap_day": null, + "cancellation_method": null, + "current_period_started_at": "2018-05-11T11:33:03-05:00", + "previous_state": "active", + "signup_payment_id": 237154761, + "signup_revenue": "0.00", + "delayed_cancel_at": null, + "coupon_code": "COUPONA", + "total_revenue_in_cents": 52762, + "product_price_in_cents": 100000, + "product_version_number": 2, + "payment_type": "credit_card", + "referral_code": "x45nc8", + "coupon_use_count": 0, + "coupon_uses_allowed": 1, + "reason_code": null, + "automatically_resume_at": null, + "coupon_codes": [ + "COUPONA", + "COUPONB" + ], + "customer": { + "id": 21259051, + "first_name": "K", + "last_name": "C", + "organization": "", + "email": "example@chargify.com", + "created_at": "2018-04-20T14:20:57-05:00", + "updated_at": "2018-04-23T15:29:28-05:00", + "reference": null, + "address": "", + "address_2": "", + "city": "", + "state": "", + "zip": "", + "country": "", + "phone": "", + "portal_invite_last_sent_at": "2018-04-20T14:20:59-05:00", + "portal_invite_last_accepted_at": null, + "verified": false, + "portal_customer_created_at": "2018-04-20T14:20:59-05:00", + "cc_emails": "", + "tax_exempt": false }, - "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-Stripe-SEPA-and-BECS-Direct-Debit) - -+ [Using Chargify.js with Stripe SEPA, BECS or BACS Direct Debit - minimal example](page:development-tools/chargify-js/examples#minimal-example-with-sepa-becs-or-bacs-direct-debit-stripe-gateway) - -+ [Using Chargify.js with Stripe BECS Direct Debit - full example](page:development-tools/chargify-js/examples#full-example-with-becs-direct-debit-stripe-gateway) - -```json -{ - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", - "last_name": "Doe", - "email": "jd@chargify.test" + "product": { + "id": 4581816, + "name": "Basic", + "handle": "basic", + "description": "", + "accounting_code": "", + "request_credit_card": true, + "expiration_interval": null, + "expiration_interval_unit": "never", + "created_at": "2017-11-02T15:00:11-05:00", + "updated_at": "2018-04-10T09:02:59-05:00", + "price_in_cents": 100000, + "interval": 1, + "interval_unit": "month", + "initial_charge_in_cents": 100000, + "trial_price_in_cents": 1000, + "trial_interval": 10, + "trial_interval_unit": "month", + "archived_at": null, + "require_credit_card": true, + "return_params": "", + "taxable": false, + "update_return_url": "", + "tax_code": "", + "initial_charge_after_trial": false, + "version_number": 2, + "update_return_params": "", + "product_family": { + "id": 1025627, + "name": "My Product Family", + "description": "", + "handle": "acme-products", + "accounting_code": null + }, + "public_signup_pages": [ + { + "id": 333589, + "return_url": "", + "return_params": "", + "url": "https://general-goods.chargifypay.com/subscribe/hbwtd98j3hk2/basic" + }, + { + "id": 335926, + "return_url": "", + "return_params": "", + "url": "https://general-goods.chargifypay.com/subscribe/g366zy67c7rm/basic" + }, + { + "id": 345555, + "return_url": "", + "return_params": "", + "url": "https://general-goods.chargifypay.com/subscribe/txqyyqk7d8rz/basic" + }, + { + "id": 345556, + "return_url": "", + "return_params": "", + "url": "https://general-goods.chargifypay.com/subscribe/2zss3qpf4249/basic" + } + ] }, - "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-Stripe-SEPA-and-BECS-Direct-Debit) - -+ [Using Chargify.js with Stripe SEPA, BECS or BACS Direct Debit - minimal example](page:development-tools/chargify-js/examples#minimal-example-with-sepa-becs-or-bacs-direct-debit-stripe-gateway) - -+ [Using Chargify.js with Stripe BACS Direct Debit - full example](page:development-tools/chargify-js/examples#full-example-with-bacs-direct-debit-stripe-gateway) - -```json -{ - "subscription": { - "product_handle": "gold-product", - "customer_attributes": { - "first_name": "Jane", + "credit_card": { + "id": 14839830, + "first_name": "John", "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" + "masked_card_number": "XXXX-XXXX-XXXX-1", + "card_type": "bogus", + "expiration_month": 1, + "expiration_year": 2028, + "customer_id": 21259051, + "current_vault": "bogus", + "vault_token": "1", + "billing_address": null, + "billing_city": null, + "billing_state": null, + "billing_zip": "99999", + "billing_country": null, + "customer_vault_token": null, + "billing_address_2": null, + "payment_type": "credit_card" + } + } } ``` -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. +## Errors -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`. +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`SubscriptionAddCouponErrorException`](../../doc/models/subscription-add-coupon-error-exception.md) | -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 +# Update Prepaid Subscription Configuration -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: +Use this endpoint to update a subscription's prepaid configuration. -```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" -} +```python +def update_prepaid_subscription_configuration(self, + subscription_id, + body=None) ``` -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 +## Parameters -+ signup_failure +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `body` | [`UpsertPrepaidConfigurationRequest`](../../doc/models/upsert-prepaid-configuration-request.md) | Body, Optional | - | -#### Webhooks fired when next_billing_at is reached: +## Response Type -+ `renewal_success or renewal_failure` -+ `payment_success or payment_failure` +[`PrepaidConfigurationResponse`](../../doc/models/prepaid-configuration-response.md) -### Date and Time Formats +## Example Usage -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 . +```python +subscription_id = 222 -The following are all equivalent and will work as input to `next_billing_at`: +body = UpsertPrepaidConfigurationRequest( + prepaid_configuration=UpsertPrepaidConfiguration( + initial_funding_amount_in_cents=50000, + replenish_to_amount_in_cents=50000, + auto_replenish=True, + replenish_threshold_amount_in_cents=10000 + ) +) -``` -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 +result = subscriptions_controller.update_prepaid_subscription_configuration( + subscription_id, + body=body +) ``` -You may also pass just a date, in which case we will assume the time to be noon +## Example Response *(as JSON)* +```json +{ + "prepaid_configuration": { + "id": 55, + "initial_funding_amount_in_cents": 2500, + "auto_replenish": true, + "replenish_to_amount_in_cents": 50000, + "replenish_threshold_amount_in_cents": 10000 + } +} ``` -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 +# Preview Subscription -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`. +The Chargify API allows you to preview a subscription by POSTing the same JSON or XML as for a subscription creation. -```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" - } - } -} -``` +The "Next Billing" amount and "Next Billing" date are represented in each Subscriber's Summary. For more information, please see our documentation [here](https://maxio.zendesk.com/hc/en-us/articles/24252493695757-Subscriber-Interface-Overview). -**For Maxio Payments subscriptions, the agreement acceptance params are required, with at least terms_url provided.** +## Side effects -## Providing ACH Agreement params +A subscription will not be created by sending a POST to this endpoint. It is meant to serve as a prediction. -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. +## Taxable Subscriptions -```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" - } - } -``` +This endpoint will preview taxes applicable to a purchase. In order for taxes to be previewed, the following conditions must be met: + ++ Taxes must be configured on the subscription ++ 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) + +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 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. ```python -def create_subscription(self, - body=None) +def preview_subscription(self, + body=None) ``` ## Parameters @@ -686,46 +436,18 @@ def create_subscription(self, ## Response Type -[`SubscriptionResponse`](../../doc/models/subscription-response.md) +[`SubscriptionPreviewResponse`](../../doc/models/subscription-preview-response.md) ## Example Usage ```python body = CreateSubscriptionRequest( subscription=CreateSubscription( - product_handle='basic', - customer_attributes=CustomerAttributes( - first_name='Joe', - last_name='Blow', - email='joe@example.com', - organization='Acme', - reference='XYZ', - address='123 Mass Ave.', - address_2='address_24', - city='Boston', - state='MA', - zip='02120', - country='US', - phone='(617) 111 - 0000' - ), - credit_card_attributes=PaymentProfileAttributes( - first_name='Joe', - last_name='Smith', - full_number='4111111111111111', - card_type=CardType.VISA, - expiration_month='1', - expiration_year='2021', - billing_address='123 Mass Ave.', - billing_address_2='billing_address_22', - billing_city='Boston', - billing_state='MA', - billing_country='US', - billing_zip='02120' - ) + product_handle='gold-product' ) ) -result = subscriptions_controller.create_subscription( +result = subscriptions_controller.preview_subscription( body=body ) ``` @@ -734,819 +456,775 @@ result = subscriptions_controller.create_subscription( ```json { - "subscription": { - "id": 15236915, - "state": "active", - "balance_in_cents": 0, - "total_revenue_in_cents": 14000, - "product_price_in_cents": 1000, - "product_version_number": 7, - "current_period_ends_at": "2016-11-15T14:48:10-05:00", - "next_assessment_at": "2016-11-15T14:48:10-05:00", - "trial_started_at": null, - "trial_ended_at": null, - "activated_at": "2016-11-14T14:48:12-05:00", - "expires_at": null, - "created_at": "2016-11-14T14:48:10-05:00", - "updated_at": "2016-11-14T15:24:41-05:00", - "cancellation_message": null, - "cancellation_method": "merchant_api", - "cancel_at_end_of_period": null, - "canceled_at": null, - "current_period_started_at": "2016-11-14T14:48:10-05:00", - "previous_state": "active", - "signup_payment_id": 162269766, - "signup_revenue": "260.00", - "delayed_cancel_at": null, - "coupon_code": "5SNN6HFK3GBH", - "payment_collection_method": "automatic", - "snap_day": null, - "reason_code": null, - "receives_invoice_emails": false, - "customer": { - "first_name": "Curtis", - "last_name": "Test", - "email": "curtis@example.com", - "cc_emails": "jeff@example.com", - "organization": "", - "reference": null, - "id": 14714298, - "created_at": "2016-11-14T14:48:10-05:00", - "updated_at": "2016-11-14T14:48:13-05:00", - "address": "123 Anywhere Street", - "address_2": "", - "city": "Boulder", - "state": "CO", - "zip": "80302", - "country": "US", - "phone": "", - "verified": false, - "portal_customer_created_at": "2016-11-14T14:48:13-05:00", - "portal_invite_last_sent_at": "2016-11-14T14:48:13-05:00", - "portal_invite_last_accepted_at": null, - "tax_exempt": false, - "vat_number": "012345678" - }, - "product": { - "id": 3792003, - "name": "$10 Basic Plan", - "handle": "basic", - "description": "lorem ipsum", - "accounting_code": "basic", - "price_in_cents": 1000, - "interval": 1, - "interval_unit": "day", - "initial_charge_in_cents": null, - "expiration_interval": null, - "expiration_interval_unit": "never", - "trial_price_in_cents": null, - "trial_interval": null, - "trial_interval_unit": "month", - "initial_charge_after_trial": false, - "return_params": "", - "request_credit_card": false, - "require_credit_card": false, - "created_at": "2016-03-24T13:38:39-04:00", - "updated_at": "2016-11-03T13:03:05-04:00", - "archived_at": null, - "update_return_url": "", - "update_return_params": "", - "product_family": { - "id": 527890, - "name": "Acme Projects", - "handle": "billing-plans", - "accounting_code": null, - "description": "" - }, - "public_signup_pages": [ + "subscription_preview": { + "current_billing_manifest": { + "line_items": [ { - "id": 281054, - "url": "https://general-goods.chargify.com/subscribe/kqvmfrbgd89q/basic" + "transaction_type": "charge", + "kind": "baseline", + "amount_in_cents": 5000, + "memo": "Gold Product (08/21/2018 - 09/21/2018)", + "discount_amount_in_cents": 0, + "taxable_amount_in_cents": 0, + "product_id": 1, + "product_handle": "gold-product", + "product_name": "Gold Product", + "period_range_start": "13 Oct 2023", + "period_range_end": "13 Nov 2023" }, { - "id": 281240, - "url": "https://general-goods.chargify.com/subscribe/dkffht5dxfd8/basic" + "transaction_type": "charge", + "kind": "component", + "amount_in_cents": 28000, + "memo": "Component name: 14 Unit names", + "discount_amount_in_cents": 0, + "taxable_amount_in_cents": 0, + "component_id": 462149, + "component_handle": "handle", + "component_name": "Component name" }, { - "id": 282694, - "url": "https://general-goods.chargify.com/subscribe/jwffwgdd95s8/basic" + "transaction_type": "charge", + "kind": "component", + "amount_in_cents": 2000, + "memo": "Fractional Metered Components: 20.0 Fractional Metereds", + "discount_amount_in_cents": 0, + "taxable_amount_in_cents": 0, + "component_id": 426665, + "component_handle": "handle", + "component_name": "Fractional Metered Components" + }, + { + "transaction_type": "charge", + "kind": "component", + "amount_in_cents": 0, + "memo": "On/Off Component", + "discount_amount_in_cents": 0, + "taxable_amount_in_cents": 0, + "component_id": 426670, + "component_handle": "handle", + "component_name": "On/Off Component" + }, + { + "transaction_type": "adjustment", + "kind": "coupon", + "amount_in_cents": 0, + "memo": "Coupon: 1DOLLAR - You only get $1.00 off", + "discount_amount_in_cents": 0, + "taxable_amount_in_cents": 0 } ], - "taxable": false, - "version_number": 7, - "product_price_point_name": "Default" - }, - "credit_card": { - "id": 10191713, - "payment_type": "credit_card", - "first_name": "Curtis", - "last_name": "Test", - "masked_card_number": "XXXX-XXXX-XXXX-1", - "card_type": "bogus", - "expiration_month": 1, - "expiration_year": 2026, - "billing_address": "123 Anywhere Street", - "billing_address_2": "", - "billing_city": "Boulder", - "billing_state": null, - "billing_country": "", - "billing_zip": "80302", - "current_vault": "bogus", - "vault_token": "1", - "customer_vault_token": null, - "customer_id": 14714298 + "total_in_cents": 35000, + "total_discount_in_cents": 0, + "total_tax_in_cents": 0, + "subtotal_in_cents": 35000, + "start_date": "2018-08-21T21:25:21Z", + "end_date": "2018-09-21T21:25:21Z", + "period_type": "recurring", + "existing_balance_in_cents": 0 }, - "payment_type": "credit_card", - "referral_code": "w7kjc9", - "next_product_id": null, - "coupon_use_count": 1, - "coupon_uses_allowed": 1, - "next_product_handle": null, - "stored_credential_transaction_id": 125566112256688, - "dunning_communication_delay_enabled": true, - "dunning_communication_delay_time_zone": "Eastern Time (US & Canada)" + "next_billing_manifest": { + "line_items": [ + { + "transaction_type": "charge", + "kind": "baseline", + "amount_in_cents": 5000, + "memo": "Gold Product (09/21/2018 - 10/21/2018)", + "discount_amount_in_cents": 0, + "taxable_amount_in_cents": 0, + "product_id": 1, + "product_handle": "gold-product", + "product_name": "Gold Product" + }, + { + "transaction_type": "charge", + "kind": "component", + "amount_in_cents": 28000, + "memo": "Component name: 14 Unit names", + "discount_amount_in_cents": 0, + "taxable_amount_in_cents": 0, + "component_id": 462149, + "component_handle": "handle", + "component_name": "Component name" + }, + { + "transaction_type": "charge", + "kind": "component", + "amount_in_cents": 0, + "memo": "On/Off Component", + "discount_amount_in_cents": 0, + "taxable_amount_in_cents": 0, + "component_id": 426670, + "component_handle": "handle", + "component_name": "On/Off Component" + } + ], + "total_in_cents": 33000, + "total_discount_in_cents": 0, + "total_tax_in_cents": 0, + "subtotal_in_cents": 33000, + "start_date": "2018-09-21T21:25:21Z", + "end_date": "2018-10-21T21:25:21Z", + "period_type": "recurring", + "existing_balance_in_cents": 0 + } } } ``` -## Errors -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +# Create Subscription +Full documentation on how subscriptions operate within Advanced Billing can be located under the following topics: -# List Subscriptions ++ [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) -This method will return an array of subscriptions from a Site. Pay close attention to query string filters and pagination in order to control responses from the server. +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)). -## Search for a subscription +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`. -Use the query strings below to search for a subscription using the criteria available. The return value will be an array. +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`. -## Self-Service Page token +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). -Self-Service Page token for the subscriptions is not returned by default. If this information is desired, the include[]=self_service_page_token parameter must be provided with the request. +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`. -```python -def list_subscriptions(self, - options=dict()) -``` +## Taxable Subscriptions -## Parameters +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: -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `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`. | -| `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`. | -| `state` | [`SubscriptionStateFilter`](../../doc/models/subscription-state-filter.md) | Query, Optional | The current state of the subscription | -| `product` | `int` | Query, Optional | The product id of the subscription. (Note that the product handle cannot be used.) | -| `product_price_point_id` | `int` | Query, Optional | The ID of the product price point. If supplied, product is required | -| `coupon` | `int` | Query, Optional | The numeric id of the coupon currently applied to the subscription. (This can be found in the URL when editing a coupon. Note that the coupon code cannot be used.) | -| `date_field` | [`SubscriptionDateField`](../../doc/models/subscription-date-field.md) | Query, Optional | The type of filter you'd like to apply to your search. Allowed Values: , current_period_ends_at, current_period_starts_at, created_at, activated_at, canceled_at, expires_at, trial_started_at, trial_ended_at, updated_at | -| `start_date` | `date` | Query, Optional | The start date (format YYYY-MM-DD) with which to filter the date_field. Returns subscriptions with a timestamp at or after midnight (12:00:00 AM) in your site’s time zone on the date specified. Use in query `start_date=2022-07-01`. | -| `end_date` | `date` | Query, Optional | The end date (format YYYY-MM-DD) with which to filter the date_field. Returns subscriptions with a timestamp up to and including 11:59:59PM in your site’s time zone on the date specified. Use in query `end_date=2022-08-01`. | -| `start_datetime` | `datetime` | Query, Optional | The start date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns subscriptions with a timestamp at or after 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 start_date. Use in query `start_datetime=2022-07-01 09:00:05`. | -| `end_datetime` | `datetime` | Query, Optional | The end date and time (format YYYY-MM-DD HH:MM:SS) with which to filter the date_field. Returns subscriptions 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 `end_datetime=2022-08-01 10:00:05`. | -| `metadata` | `Dict[str, str]` | Query, Optional | The value of the metadata field specified in the parameter. Use in query `metadata[my-field]=value&metadata[other-field]=another_value`. | -| `direction` | [`SortingDirection`](../../doc/models/sorting-direction.md) | Query, Optional | Controls the order in which results are returned.
Use in query `direction=asc`. | -| `sort` | [`SubscriptionSort`](../../doc/models/subscription-sort.md) | Query, Optional | The attribute by which to sort | -| `include` | [`List[SubscriptionListInclude]`](../../doc/models/subscription-list-include.md) | Query, Optional | Allows including additional data in the response. Use in query: `include[]=self_service_page_token`. | ++ 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. -## Response Type +## Subscription Request Examples -[`List[SubscriptionResponse]`](../../doc/models/subscription-response.md) +The subscription examples below will be split into two sections. -## Example Usage +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 -collect = { - 'page': 2, - 'per_page': 50, - 'start_date': dateutil.parser.parse('2022-07-01').date(), - 'end_date': dateutil.parser.parse('2022-08-01').date(), - 'start_datetime': dateutil.parser.parse('2022-07-01 09:00:05'), - 'end_datetime': dateutil.parser.parse('2022-08-01 10:00:05'), - 'sort': SubscriptionSort.SIGNUP_DATE, - 'include': [ - SubscriptionListInclude.SELF_SERVICE_PAGE_TOKEN - ] -} -result = subscriptions_controller.list_subscriptions(collect) -``` +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 -# Update Subscription +## With Components -The subscription endpoint allows you to instantly update one or many attributes about a subscription in a single call. +Different components require slightly different data. For example, quantity-based and on/off components accept `allocated_quantity`, while metered components accept `unit_balance`. -## Update Subscription Payment Method +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. -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: if an invalid `price_point_id` is used, the subscription will still proceed but will use the component's default price point. -Note that partial card updates for **Authorize.Net** are not allowed via this endpoint. The existing Payment Profile must be directly updated instead. +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. -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**. +## With Coupon(s) -## Product Change +Pass an array of `coupon_codes`. See the example request body "With Coupon". -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. +## With Manual Invoice Collection -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. +The `invoice` collection method works only on legacy Statement Architecture. -### Delayed Product Change +On Relationship Invoicing Architecture use the `remittance` collection method. -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. +## Prepaid Subscription -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. +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`. -You can also perform a delayed change to the price point by passing in either `product_price_point_id` or `product_price_point_handle` +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). -**Note: To cancel a delayed product change, set `next_product_id` to an empty string.** +Prepaid subscriptions do not work on legacy Statement Architecture. -## Billing Date Changes +## With Metafields -### Regular Billing Date Changes +Metafields can either attach to subscriptions or customers. Metafields are popuplated with the supplied metadata to the resource specified. -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. +If the metafield doesn't exist yet, it will be created on-the-fly. -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. +## 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://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDI0-overview). 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 Credit Card + +```json +"subscription": { + "product_handle": "basic", + "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." + }, + "credit_card_attributes": { + "last_name": "Smith", + "first_name": "Joe", + "full_number": "4111111111111111", + "expiration_year": "2021", + "expiration_month": "1", + "card_type": "visa", + "billing_zip": "02120", + "billing_state": "MA", + "billing_country": "US", + "billing_city": "Boston", + "billing_address_2": null, + "billing_address": "123 Mass Ave." + } +} +``` + +## 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" + } + } +} +``` -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. +## Subscription with PayPal payment profile -### Snap Day Changes +### With the nonce from Braintree JS -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**. +```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" + } + } +``` -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`. +### With the Braintree Customer ID as the vault token: -```python -def update_subscription(self, - subscription_id, - body=None) +```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" + } + } ``` -## Parameters +## Subscription using GoCardless Bank Number -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `body` | [`UpdateSubscriptionRequest`](../../doc/models/update-subscription-request.md) | Body, Optional | - | +These examples creates a customer, bank account and mandate in GoCardless. -## Response Type +For more information on GoCardless, please view the following two resources: -[`SubscriptionResponse`](../../doc/models/subscription-response.md) ++ [Payment Profiles via API for GoCardless](https://developers.chargify.com/docs/api-docs/1f10a4f170405-create-payment-profile#gocardless) -## Example Usage ++ [Full documentation on GoCardless](https://maxio.zendesk.com/hc/en-us/articles/24176159136909-GoCardless) -```python -subscription_id = 222 ++ [Using Chargify.js with GoCardless - minimal example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#minimal-example-with-direct-debit-gocardless-gateway) -body = UpdateSubscriptionRequest( - subscription=UpdateSubscription( - credit_card_attributes=CreditCardAttributes( - full_number='4111111111111111', - expiration_month='10', - expiration_year='2030' - ), - next_billing_at=dateutil.parser.parse('2010-08-06T15:34:00Z') - ) -) ++ [Using Chargify.js with GoCardless - full example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#full-example-with-direct-debit-gocardless-gateway) -result = subscriptions_controller.update_subscription( - subscription_id, - body=body -) +```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" + } + } +} ``` -## Example Response *(as JSON)* +## Subscription using GoCardless IBAN Number ```json { "subscription": { - "id": 18220670, - "state": "active", - "trial_started_at": null, - "trial_ended_at": null, - "activated_at": "2017-06-27T13:45:15-05:00", - "created_at": "2017-06-27T13:45:13-05:00", - "updated_at": "2017-06-30T09:26:50-05:00", - "expires_at": null, - "balance_in_cents": 10000, - "current_period_ends_at": "2017-06-30T12:00:00-05:00", - "next_assessment_at": "2017-06-30T12:00:00-05:00", - "canceled_at": null, - "cancellation_message": null, - "next_product_id": null, - "cancel_at_end_of_period": false, - "payment_collection_method": "automatic", - "snap_day": "end", - "cancellation_method": null, - "current_period_started_at": "2017-06-27T13:45:13-05:00", - "previous_state": "active", - "signup_payment_id": 191819284, - "signup_revenue": "0.00", - "delayed_cancel_at": null, - "coupon_code": null, - "total_revenue_in_cents": 0, - "product_price_in_cents": 0, - "product_version_number": 1, - "payment_type": null, - "referral_code": "d3pw7f", - "coupon_use_count": null, - "coupon_uses_allowed": null, - "reason_code": null, - "automatically_resume_at": null, - "current_billing_amount_in_cents": 10000, - "receives_invoice_emails": false, - "customer": { - "id": 17780587, - "first_name": "Catie", - "last_name": "Test", - "organization": "Acme, Inc.", - "email": "catie@example.com", - "created_at": "2017-06-27T13:01:05-05:00", - "updated_at": "2017-06-30T09:23:10-05:00", - "reference": "123ABC", - "address": "123 Anywhere Street", - "address_2": "Apartment #10", - "city": "Los Angeles", - "state": "CA", - "zip": "90210", - "country": "US", - "phone": "555-555-5555", - "portal_invite_last_sent_at": "2017-06-27T13:45:16-05:00", - "portal_invite_last_accepted_at": null, - "verified": true, - "portal_customer_created_at": "2017-06-27T13:01:08-05:00", - "cc_emails": "support@example.com", - "tax_exempt": true + "product_handle": "gold-product", + "customer_attributes": { + "first_name": "Jane", + "last_name": "Doe", + "email": "jd@chargify.test" }, - "product": { - "id": 4470347, - "name": "Zero Dollar Product", - "handle": "zero-dollar-product", - "description": "", - "accounting_code": "", - "request_credit_card": true, - "expiration_interval": null, - "expiration_interval_unit": "never", - "created_at": "2017-03-23T10:54:12-05:00", - "updated_at": "2017-04-20T15:18:46-05:00", - "price_in_cents": 0, - "interval": 1, - "interval_unit": "month", - "initial_charge_in_cents": null, - "trial_price_in_cents": null, - "trial_interval": null, - "trial_interval_unit": "month", - "archived_at": null, - "require_credit_card": false, - "return_params": "", - "taxable": false, - "update_return_url": "", - "tax_code": "", - "initial_charge_after_trial": false, - "version_number": 1, - "update_return_params": "", - "product_family": { - "id": 997233, - "name": "Acme Products", - "description": "", - "handle": "acme-products", - "accounting_code": null - }, - "public_signup_pages": [ - { - "id": 316810, - "return_url": "", - "return_params": "", - "url": "https://general-goods.chargify.com/subscribe/69x825m78v3d/zero-dollar-product" - } - ] + "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" } } } ``` -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +## Subscription using Stripe SEPA Direct Debit +For more information on Stripe Direct Debit, please view the following two resources: -# Read Subscription ++ [Payment Profiles via API for Stripe SEPA Direct Debit](https://developers.chargify.com/docs/api-docs/1f10a4f170405-create-payment-profile#sepa-direct-debit) -Use this endpoint to find subscription details. ++ [Full documentation on Stripe Direct Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Stripe-SEPA-and-BECS-Direct-Debit) -## Self-Service Page token ++ [Using Chargify.js with Stripe SEPA or BECS Direct Debit - minimal example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#minimal-example-with-sepa-or-becs-direct-debit-stripe-gateway) -Self-Service Page token for the subscription is not returned by default. If this information is desired, the include[]=self_service_page_token parameter must be provided with the request. ++ [Using Chargify.js with Stripe SEPA Direct Debit - full example](https://developers.chargify.com/docs/developer-docs/ZG9jOjE0NjAzNDIy-examples#full-example-with-sepa-direct-debit-stripe-gateway) -```python -def read_subscription(self, - subscription_id, - include=None) +```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" + } + } +} ``` -## Parameters +## 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-Stripe-SEPA-and-BECS-Direct-Debit) + ++ [Using Chargify.js with Stripe SEPA, BECS or BACS Direct Debit - minimal example](page:development-tools/chargify-js/examples#minimal-example-with-sepa-becs-or-bacs-direct-debit-stripe-gateway) -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `include` | [`List[SubscriptionInclude]`](../../doc/models/subscription-include.md) | Query, Optional | Allows including additional data in the response. Use in query: `include[]=coupons&include[]=self_service_page_token`. | ++ [Using Chargify.js with Stripe BECS Direct Debit - full example](page:development-tools/chargify-js/examples#full-example-with-becs-direct-debit-stripe-gateway) -## Response Type +```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" + } + } +} +``` -[`SubscriptionResponse`](../../doc/models/subscription-response.md) +## Subscription using Stripe BACS Direct Debit -## Example Usage +For more information on Stripe Direct Debit, please view the following two resources: -```python -subscription_id = 222 ++ [Payment Profiles via API for Stripe BACS Direct Debit]($e/Payment%20Profiles/createPaymentProfile) -include = [ - SubscriptionInclude.COUPONS, - SubscriptionInclude.SELF_SERVICE_PAGE_TOKEN -] ++ [Full documentation on Stripe Direct Debit](https://maxio.zendesk.com/hc/en-us/articles/24176170430093-Stripe-SEPA-and-BECS-Direct-Debit) -result = subscriptions_controller.read_subscription( - subscription_id, - include=include -) -``` ++ [Using Chargify.js with Stripe SEPA, BECS or BACS Direct Debit - minimal example](page:development-tools/chargify-js/examples#minimal-example-with-sepa-becs-or-bacs-direct-debit-stripe-gateway) -## Example Response *(as JSON)* ++ [Using Chargify.js with Stripe BACS Direct Debit - full example](page:development-tools/chargify-js/examples#full-example-with-bacs-direct-debit-stripe-gateway) ```json { "subscription": { - "id": 15236915, - "state": "active", - "balance_in_cents": 0, - "total_revenue_in_cents": 14000, - "product_price_in_cents": 1000, - "product_version_number": 7, - "current_period_ends_at": "2016-11-15T14:48:10-05:00", - "next_assessment_at": "2016-11-15T14:48:10-05:00", - "trial_started_at": null, - "trial_ended_at": null, - "activated_at": "2016-11-14T14:48:12-05:00", - "expires_at": null, - "created_at": "2016-11-14T14:48:10-05:00", - "updated_at": "2016-11-14T15:24:41-05:00", - "cancellation_message": null, - "cancellation_method": null, - "cancel_at_end_of_period": null, - "canceled_at": null, - "current_period_started_at": "2016-11-14T14:48:10-05:00", - "previous_state": "active", - "signup_payment_id": 162269766, - "signup_revenue": "260.00", - "delayed_cancel_at": null, - "coupon_code": "5SNN6HFK3GBH", - "payment_collection_method": "automatic", - "snap_day": null, - "reason_code": null, - "receives_invoice_emails": false, - "net_terms": 0, - "customer": { - "first_name": "Curtis", - "last_name": "Test", - "email": "curtis@example.com", - "cc_emails": "jeff@example.com", - "organization": "", - "reference": null, - "id": 14714298, - "created_at": "2016-11-14T14:48:10-05:00", - "updated_at": "2016-11-14T14:48:13-05:00", - "address": "123 Anywhere Street", - "address_2": "", - "city": "Boulder", - "state": "CO", - "zip": "80302", - "country": "US", - "phone": "", - "verified": false, - "portal_customer_created_at": "2016-11-14T14:48:13-05:00", - "portal_invite_last_sent_at": "2016-11-14T14:48:13-05:00", - "portal_invite_last_accepted_at": null, - "tax_exempt": false, - "vat_number": "012345678" - }, - "product": { - "id": 3792003, - "name": "$10 Basic Plan", - "handle": "basic", - "description": "lorem ipsum", - "accounting_code": "basic", - "price_in_cents": 1000, - "interval": 1, - "interval_unit": "day", - "initial_charge_in_cents": null, - "expiration_interval": null, - "expiration_interval_unit": "never", - "trial_price_in_cents": null, - "trial_interval": null, - "trial_interval_unit": "month", - "initial_charge_after_trial": false, - "return_params": "", - "request_credit_card": false, - "require_credit_card": false, - "created_at": "2016-03-24T13:38:39-04:00", - "updated_at": "2016-11-03T13:03:05-04:00", - "archived_at": null, - "update_return_url": "", - "update_return_params": "", - "product_family": { - "id": 527890, - "name": "Acme Projects", - "handle": "billing-plans", - "accounting_code": null, - "description": "" - }, - "public_signup_pages": [ - { - "id": 281054, - "url": "https://general-goods.chargify.com/subscribe/kqvmfrbgd89q/basic" - }, - { - "id": 281240, - "url": "https://general-goods.chargify.com/subscribe/dkffht5dxfd8/basic" - }, - { - "id": 282694, - "url": "https://general-goods.chargify.com/subscribe/jwffwgdd95s8/basic" - } - ], - "taxable": false, - "version_number": 7, - "product_price_point_name": "Default" - }, - "credit_card": { - "id": 10191713, - "payment_type": "credit_card", - "first_name": "Curtis", - "last_name": "Test", - "masked_card_number": "XXXX-XXXX-XXXX-1", - "card_type": "bogus", - "expiration_month": 1, - "expiration_year": 2026, - "billing_address": "123 Anywhere Street", - "billing_address_2": "", - "billing_city": "Boulder", - "billing_state": null, - "billing_country": "", - "billing_zip": "80302", - "current_vault": "bogus", - "vault_token": "1", - "customer_vault_token": null, - "customer_id": 14714298 + "product_handle": "gold-product", + "customer_attributes": { + "first_name": "Jane", + "last_name": "Doe", + "email": "jd@chargify.test" }, - "payment_type": "credit_card", - "referral_code": "w7kjc9", - "next_product_id": null, - "coupon_use_count": 1, - "coupon_uses_allowed": 1, - "stored_credential_transaction_id": 166411599220288, - "on_hold_at": null, - "scheduled_cancellation_at": "2016-11-14T14:48:13-05:00" + "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 -# Override Subscription - -This API endpoint allows you to set certain subscription fields that are usually managed for you automatically. Some of the fields can be set via the normal Subscriptions Update API, but others can only be set using this endpoint. +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: -This endpoint is provided for cases where you need to “align” Advanced Billing data with data that happened in your system, perhaps before you started using Advanced Billing. For example, you may choose to import your historical subscription data, and would like the activation and cancellation dates in Advanced Billing to match your existing historical dates. Advanced Billing does not backfill historical events (i.e. from the Events API), but some static data can be changed via this API. +```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" +} +``` -Why are some fields only settable from this endpoint, and not the normal subscription create and update endpoints? Because we want users of this endpoint to be aware that these fields are usually managed by Advanced Billing, and using this API means **you are stepping out on your own.** +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: -Changing these fields will not affect any other attributes. For example, adding an expiration date will not affect the next assessment date on the subscription. +- whether the authentication was successful (`success`) +- the gateway ID for the payment (`gateway_payment_id`) +- the subscription ID (`subscription_id`) -If you regularly need to override the current_period_starts_at for new subscriptions, this can also be accomplished by setting both `previous_billing_at` and `next_billing_at` at subscription creation. See the documentation on [Importing Subscriptions](./b3A6MTQxMDgzODg-create-subscription#subscriptions-import) for more information. +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. -## Limitations +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`. -When passing `current_period_starts_at` some validations are made: +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` -1. The subscription needs to be unbilled (no statements or invoices). -2. The value passed must be a valid date/time. We recommend using the iso 8601 format. -3. The value passed must be before the current date/time. +## 3D Secure - Checkout -If unpermitted parameters are sent, a 400 HTTP response is sent along with a string giving the reason for the problem. +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: -```python -def override_subscription(self, - subscription_id, - body=None) +```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" +} ``` -## Parameters +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: -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `body` | [`OverrideSubscriptionRequest`](../../doc/models/override-subscription-request.md) | Body, Optional | Only these fields are available to be set. | +- whether the authentication was successful (`success`) +- the gateway ID for the payment (`gateway_payment_id`) +- the subscription ID (`subscription_id`) -## Response Type +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. -`void` +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`. -## Example Usage +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` -```python -subscription_id = 222 +### Example Redirect Flow -body = OverrideSubscriptionRequest( - subscription=OverrideSubscription( - activated_at=dateutil.parser.parse('1999-12-01T10:28:34-05:00'), - canceled_at=dateutil.parser.parse('2000-12-31T10:28:34-05:00'), - cancellation_message='Original cancellation in 2000', - expires_at=dateutil.parser.parse('2001-07-15T10:28:34-05:00') - ) -) +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: -subscriptions_controller.override_subscription( - subscription_id, - body=body -) -``` +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 -## Errors +## Subscriptions Import -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | +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 -# Find Subscription +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. -Use this endpoint to find a subscription by its reference. +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). -```python -def find_subscription(self, - reference=None) -``` +### Important Notices and Disclaimers regarding Imports -## Parameters +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. -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `reference` | `str` | Query, Optional | Subscription reference | +### Subscription Input Attributes -## Response Type +The following _additional_ attributes to the subscription input attributes make imports possible: `next_billing_at`, `previous_billing_at`, and `import_mrr`. -[`SubscriptionResponse`](../../doc/models/subscription-response.md) +### Current Vault -## Example Usage +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. -```python -result = subscriptions_controller.find_subscription() -``` +### 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. -# Purge Subscription +When importing PayPal type payment profiles, please set `payment_type` to `paypal_account`. -For sites in test mode, you may purge individual subscriptions. +### Stripe ACH Imports -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 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. -If you need to remove subscriptions from a live site, please contact support to discuss your use case. +### Webhooks During Import -### Delete customer and payment profile +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. -The query params will be: `?ack={customer_id}&cascade[]=customer&cascade[]=payment_profile` +#### Successful creation with Billing Date -```python -def purge_subscription(self, - subscription_id, - ack, - cascade=None) -``` +Scenario: If `next_billing_at` provided -## Parameters ++ `signup_success` ++ `billing_date_change` -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `ack` | `int` | Query, Required | id of the customer. | -| `cascade` | [`List[SubscriptionPurgeType]`](../../doc/models/subscription-purge-type.md) | Query, Optional | Options are "customer" or "payment_profile".
Use in query: `cascade[]=customer&cascade[]=payment_profile`. | +#### Successful creation without Billing Date -## Response Type +Scenario: If no `next_billing_at` provided -`void` ++ `signup_success` ++ `payment_success` -## Example Usage +#### Unsuccessful creation -```python -subscription_id = 222 +Scenario: If card can’t be charged, and no `next_billing_at` provided -ack = 252 ++ signup_failure -cascade = [ - SubscriptionPurgeType.CUSTOMER, - SubscriptionPurgeType.PAYMENT_PROFILE -] +#### Webhooks fired when next_billing_at is reached: -subscriptions_controller.purge_subscription( - subscription_id, - ack, - cascade=cascade -) -``` ++ `renewal_success or renewal_failure` ++ `payment_success or payment_failure` +### Date and Time Formats -# Update Prepaid Subscription Configuration +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 . -Use this endpoint to update a subscription's prepaid configuration. +The following are all equivalent and will work as input to `next_billing_at`: -```python -def update_prepaid_subscription_configuration(self, - subscription_id, - body=None) +``` +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 ``` -## Parameters +You may also pass just a date, in which case we will assume the time to be noon -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `body` | [`UpsertPrepaidConfigurationRequest`](../../doc/models/upsert-prepaid-configuration-request.md) | Body, Optional | - | +``` +2010-08-06 +``` -## Response Type +## Subscription Hierarchies & WhoPays -[`PrepaidConfigurationResponse`](../../doc/models/prepaid-configuration-response.md) +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. -## Example Usage +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. -```python -subscription_id = 222 +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. -body = UpsertPrepaidConfigurationRequest( - prepaid_configuration=UpsertPrepaidConfiguration( - initial_funding_amount_in_cents=50000, - replenish_to_amount_in_cents=50000, - auto_replenish=True, - replenish_threshold_amount_in_cents=10000 - ) -) +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. -result = subscriptions_controller.update_prepaid_subscription_configuration( - subscription_id, - body=body -) -``` +### Subscription in a Customer Hierarchy -## Example Response *(as JSON)* +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. -```json -{ - "prepaid_configuration": { - "id": 55, - "initial_funding_amount_in_cents": 2500, - "auto_replenish": true, - "replenish_to_amount_in_cents": 50000, - "replenish_threshold_amount_in_cents": 10000 - } -} -``` ++ 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. -# Preview Subscription +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. -The Chargify API allows you to preview a subscription by POSTing the same JSON or XML as for a subscription creation. +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 "Next Billing" amount and "Next Billing" date are represented in 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 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. -## Side effects +### Subscription in a Subscription Group -A subscription will not be created by sending a POST to this endpoint. It is meant to serve as a prediction. +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. -## Taxable Subscriptions +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. -This endpoint will preview taxes applicable to a purchase. In order for taxes to be previewed, the following conditions must be met: +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. -+ Taxes must be configured on the subscription -+ 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 +## Providing Agreement Acceptance Params -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) +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`. -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. +```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" + } + } +} +``` -You can pass shipping and billing addresses and still decide not to calculate taxes. To do that, pass `skip_billing_manifest_taxes: true` attribute. +**For Maxio Payments subscriptions, the agreement acceptance params are required, with at least terms_url provided.** -## Non-taxable Subscriptions +## Providing ACH Agreement params -If you'd like to calculate subscriptions that do not include tax, please feel free to leave off the billing information. +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" + } + } +``` ```python -def preview_subscription(self, - body=None) +def create_subscription(self, + body=None) ``` ## Parameters @@ -1557,18 +1235,46 @@ def preview_subscription(self, ## Response Type -[`SubscriptionPreviewResponse`](../../doc/models/subscription-preview-response.md) +[`SubscriptionResponse`](../../doc/models/subscription-response.md) ## Example Usage ```python body = CreateSubscriptionRequest( subscription=CreateSubscription( - product_handle='gold-product' + product_handle='basic', + customer_attributes=CustomerAttributes( + first_name='Joe', + last_name='Blow', + email='joe@example.com', + organization='Acme', + reference='XYZ', + address='123 Mass Ave.', + address_2='address_24', + city='Boston', + state='MA', + zip='02120', + country='US', + phone='(617) 111 - 0000' + ), + credit_card_attributes=PaymentProfileAttributes( + first_name='Joe', + last_name='Smith', + full_number='4111111111111111', + card_type=CardType.VISA, + expiration_month='1', + expiration_year='2021', + billing_address='123 Mass Ave.', + billing_address_2='billing_address_22', + billing_city='Boston', + billing_state='MA', + billing_country='US', + billing_zip='02120' + ) ) ) -result = subscriptions_controller.preview_subscription( +result = subscriptions_controller.create_subscription( body=body ) ``` @@ -1577,138 +1283,196 @@ result = subscriptions_controller.preview_subscription( ```json { - "subscription_preview": { - "current_billing_manifest": { - "line_items": [ - { - "transaction_type": "charge", - "kind": "baseline", - "amount_in_cents": 5000, - "memo": "Gold Product (08/21/2018 - 09/21/2018)", - "discount_amount_in_cents": 0, - "taxable_amount_in_cents": 0, - "product_id": 1, - "product_handle": "gold-product", - "product_name": "Gold Product", - "period_range_start": "13 Oct 2023", - "period_range_end": "13 Nov 2023" - }, - { - "transaction_type": "charge", - "kind": "component", - "amount_in_cents": 28000, - "memo": "Component name: 14 Unit names", - "discount_amount_in_cents": 0, - "taxable_amount_in_cents": 0, - "component_id": 462149, - "component_handle": "handle", - "component_name": "Component name" - }, - { - "transaction_type": "charge", - "kind": "component", - "amount_in_cents": 2000, - "memo": "Fractional Metered Components: 20.0 Fractional Metereds", - "discount_amount_in_cents": 0, - "taxable_amount_in_cents": 0, - "component_id": 426665, - "component_handle": "handle", - "component_name": "Fractional Metered Components" - }, - { - "transaction_type": "charge", - "kind": "component", - "amount_in_cents": 0, - "memo": "On/Off Component", - "discount_amount_in_cents": 0, - "taxable_amount_in_cents": 0, - "component_id": 426670, - "component_handle": "handle", - "component_name": "On/Off Component" - }, - { - "transaction_type": "adjustment", - "kind": "coupon", - "amount_in_cents": 0, - "memo": "Coupon: 1DOLLAR - You only get $1.00 off", - "discount_amount_in_cents": 0, - "taxable_amount_in_cents": 0 - } - ], - "total_in_cents": 35000, - "total_discount_in_cents": 0, - "total_tax_in_cents": 0, - "subtotal_in_cents": 35000, - "start_date": "2018-08-21T21:25:21Z", - "end_date": "2018-09-21T21:25:21Z", - "period_type": "recurring", - "existing_balance_in_cents": 0 + "subscription": { + "id": 15236915, + "state": "active", + "balance_in_cents": 0, + "total_revenue_in_cents": 14000, + "product_price_in_cents": 1000, + "product_version_number": 7, + "current_period_ends_at": "2016-11-15T14:48:10-05:00", + "next_assessment_at": "2016-11-15T14:48:10-05:00", + "trial_started_at": null, + "trial_ended_at": null, + "activated_at": "2016-11-14T14:48:12-05:00", + "expires_at": null, + "created_at": "2016-11-14T14:48:10-05:00", + "updated_at": "2016-11-14T15:24:41-05:00", + "cancellation_message": null, + "cancellation_method": "merchant_api", + "cancel_at_end_of_period": null, + "canceled_at": null, + "current_period_started_at": "2016-11-14T14:48:10-05:00", + "previous_state": "active", + "signup_payment_id": 162269766, + "signup_revenue": "260.00", + "delayed_cancel_at": null, + "coupon_code": "5SNN6HFK3GBH", + "payment_collection_method": "automatic", + "snap_day": null, + "reason_code": null, + "receives_invoice_emails": false, + "customer": { + "first_name": "Curtis", + "last_name": "Test", + "email": "curtis@example.com", + "cc_emails": "jeff@example.com", + "organization": "", + "reference": null, + "id": 14714298, + "created_at": "2016-11-14T14:48:10-05:00", + "updated_at": "2016-11-14T14:48:13-05:00", + "address": "123 Anywhere Street", + "address_2": "", + "city": "Boulder", + "state": "CO", + "zip": "80302", + "country": "US", + "phone": "", + "verified": false, + "portal_customer_created_at": "2016-11-14T14:48:13-05:00", + "portal_invite_last_sent_at": "2016-11-14T14:48:13-05:00", + "portal_invite_last_accepted_at": null, + "tax_exempt": false, + "vat_number": "012345678" }, - "next_billing_manifest": { - "line_items": [ + "product": { + "id": 3792003, + "name": "$10 Basic Plan", + "handle": "basic", + "description": "lorem ipsum", + "accounting_code": "basic", + "price_in_cents": 1000, + "interval": 1, + "interval_unit": "day", + "initial_charge_in_cents": null, + "expiration_interval": null, + "expiration_interval_unit": "never", + "trial_price_in_cents": null, + "trial_interval": null, + "trial_interval_unit": "month", + "initial_charge_after_trial": false, + "return_params": "", + "request_credit_card": false, + "require_credit_card": false, + "created_at": "2016-03-24T13:38:39-04:00", + "updated_at": "2016-11-03T13:03:05-04:00", + "archived_at": null, + "update_return_url": "", + "update_return_params": "", + "product_family": { + "id": 527890, + "name": "Acme Projects", + "handle": "billing-plans", + "accounting_code": null, + "description": "" + }, + "public_signup_pages": [ { - "transaction_type": "charge", - "kind": "baseline", - "amount_in_cents": 5000, - "memo": "Gold Product (09/21/2018 - 10/21/2018)", - "discount_amount_in_cents": 0, - "taxable_amount_in_cents": 0, - "product_id": 1, - "product_handle": "gold-product", - "product_name": "Gold Product" + "id": 281054, + "url": "https://general-goods.chargify.com/subscribe/kqvmfrbgd89q/basic" }, { - "transaction_type": "charge", - "kind": "component", - "amount_in_cents": 28000, - "memo": "Component name: 14 Unit names", - "discount_amount_in_cents": 0, - "taxable_amount_in_cents": 0, - "component_id": 462149, - "component_handle": "handle", - "component_name": "Component name" + "id": 281240, + "url": "https://general-goods.chargify.com/subscribe/dkffht5dxfd8/basic" }, { - "transaction_type": "charge", - "kind": "component", - "amount_in_cents": 0, - "memo": "On/Off Component", - "discount_amount_in_cents": 0, - "taxable_amount_in_cents": 0, - "component_id": 426670, - "component_handle": "handle", - "component_name": "On/Off Component" + "id": 282694, + "url": "https://general-goods.chargify.com/subscribe/jwffwgdd95s8/basic" } ], - "total_in_cents": 33000, - "total_discount_in_cents": 0, - "total_tax_in_cents": 0, - "subtotal_in_cents": 33000, - "start_date": "2018-09-21T21:25:21Z", - "end_date": "2018-10-21T21:25:21Z", - "period_type": "recurring", - "existing_balance_in_cents": 0 - } + "taxable": false, + "version_number": 7, + "product_price_point_name": "Default" + }, + "credit_card": { + "id": 10191713, + "payment_type": "credit_card", + "first_name": "Curtis", + "last_name": "Test", + "masked_card_number": "XXXX-XXXX-XXXX-1", + "card_type": "bogus", + "expiration_month": 1, + "expiration_year": 2026, + "billing_address": "123 Anywhere Street", + "billing_address_2": "", + "billing_city": "Boulder", + "billing_state": null, + "billing_country": "", + "billing_zip": "80302", + "current_vault": "bogus", + "vault_token": "1", + "customer_vault_token": null, + "customer_id": 14714298 + }, + "payment_type": "credit_card", + "referral_code": "w7kjc9", + "next_product_id": null, + "coupon_use_count": 1, + "coupon_uses_allowed": 1, + "next_product_handle": null, + "stored_credential_transaction_id": 125566112256688, + "dunning_communication_delay_enabled": true, + "dunning_communication_delay_time_zone": "Eastern Time (US & Canada)" } } ``` +## Errors -# Apply Coupons to Subscription +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -An existing subscription can accommodate multiple discounts/coupon codes. This is only applicable if each coupon is stackable. For more information on stackable coupons, we recommend reviewing our [coupon documentation.](https://maxio.zendesk.com/hc/en-us/articles/24261259337101-Coupons-and-Subscriptions#stackability-rules) -## Query Parameters vs Request Body Parameters +# Update Subscription -Passing in a coupon code as a query parameter will add the code to the subscription, completely replacing all existing coupon codes on the subscription. +The subscription endpoint allows you to instantly update one or many attributes about a subscription in a single call. -For this reason, using this query parameter on this endpoint has been deprecated in favor of using the request body parameters as described below. When passing in request body parameters, the list of coupon codes will simply be added to any existing list of codes on the 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. + +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_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. + +### 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. + +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.** + +## Billing Date Changes + +### 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. + +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 + +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`. ```python -def apply_coupons_to_subscription(self, - subscription_id, - code=None, - body=None) +def update_subscription(self, + subscription_id, + body=None) ``` ## Parameters @@ -1716,8 +1480,7 @@ def apply_coupons_to_subscription(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | | `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | -| `code` | `str` | Query, Optional | A code for the coupon that would be applied to a subscription | -| `body` | [`AddCouponsRequest`](../../doc/models/add-coupons-request.md) | Body, Optional | - | +| `body` | [`UpdateSubscriptionRequest`](../../doc/models/update-subscription-request.md) | Body, Optional | - | ## Response Type @@ -1728,14 +1491,18 @@ def apply_coupons_to_subscription(self, ```python subscription_id = 222 -body = AddCouponsRequest( - codes=[ - 'COUPON_1', - 'COUPON_2' - ] +body = UpdateSubscriptionRequest( + subscription=UpdateSubscription( + credit_card_attributes=CreditCardAttributes( + full_number='4111111111111111', + expiration_month='10', + expiration_year='2030' + ), + next_billing_at=dateutil.parser.parse('2010-08-06T15:34:00Z') + ) ) -result = subscriptions_controller.apply_coupons_to_subscription( +result = subscriptions_controller.update_subscription( subscription_id, body=body ) @@ -1746,156 +1513,389 @@ result = subscriptions_controller.apply_coupons_to_subscription( ```json { "subscription": { - "id": 21607180, + "id": 18220670, "state": "active", "trial_started_at": null, "trial_ended_at": null, - "activated_at": "2018-04-20T14:20:57-05:00", - "created_at": "2018-04-20T14:20:57-05:00", - "updated_at": "2018-05-11T13:53:44-05:00", + "activated_at": "2017-06-27T13:45:15-05:00", + "created_at": "2017-06-27T13:45:13-05:00", + "updated_at": "2017-06-30T09:26:50-05:00", "expires_at": null, - "balance_in_cents": 49000, - "current_period_ends_at": "2018-05-12T11:33:03-05:00", - "next_assessment_at": "2018-05-12T11:33:03-05:00", + "balance_in_cents": 10000, + "current_period_ends_at": "2017-06-30T12:00:00-05:00", + "next_assessment_at": "2017-06-30T12:00:00-05:00", "canceled_at": null, "cancellation_message": null, "next_product_id": null, "cancel_at_end_of_period": false, - "payment_collection_method": "remittance", - "snap_day": null, + "payment_collection_method": "automatic", + "snap_day": "end", + "cancellation_method": null, + "current_period_started_at": "2017-06-27T13:45:13-05:00", + "previous_state": "active", + "signup_payment_id": 191819284, + "signup_revenue": "0.00", + "delayed_cancel_at": null, + "coupon_code": null, + "total_revenue_in_cents": 0, + "product_price_in_cents": 0, + "product_version_number": 1, + "payment_type": null, + "referral_code": "d3pw7f", + "coupon_use_count": null, + "coupon_uses_allowed": null, + "reason_code": null, + "automatically_resume_at": null, + "current_billing_amount_in_cents": 10000, + "receives_invoice_emails": false, + "customer": { + "id": 17780587, + "first_name": "Catie", + "last_name": "Test", + "organization": "Acme, Inc.", + "email": "catie@example.com", + "created_at": "2017-06-27T13:01:05-05:00", + "updated_at": "2017-06-30T09:23:10-05:00", + "reference": "123ABC", + "address": "123 Anywhere Street", + "address_2": "Apartment #10", + "city": "Los Angeles", + "state": "CA", + "zip": "90210", + "country": "US", + "phone": "555-555-5555", + "portal_invite_last_sent_at": "2017-06-27T13:45:16-05:00", + "portal_invite_last_accepted_at": null, + "verified": true, + "portal_customer_created_at": "2017-06-27T13:01:08-05:00", + "cc_emails": "support@example.com", + "tax_exempt": true + }, + "product": { + "id": 4470347, + "name": "Zero Dollar Product", + "handle": "zero-dollar-product", + "description": "", + "accounting_code": "", + "request_credit_card": true, + "expiration_interval": null, + "expiration_interval_unit": "never", + "created_at": "2017-03-23T10:54:12-05:00", + "updated_at": "2017-04-20T15:18:46-05:00", + "price_in_cents": 0, + "interval": 1, + "interval_unit": "month", + "initial_charge_in_cents": null, + "trial_price_in_cents": null, + "trial_interval": null, + "trial_interval_unit": "month", + "archived_at": null, + "require_credit_card": false, + "return_params": "", + "taxable": false, + "update_return_url": "", + "tax_code": "", + "initial_charge_after_trial": false, + "version_number": 1, + "update_return_params": "", + "product_family": { + "id": 997233, + "name": "Acme Products", + "description": "", + "handle": "acme-products", + "accounting_code": null + }, + "public_signup_pages": [ + { + "id": 316810, + "return_url": "", + "return_params": "", + "url": "https://general-goods.chargify.com/subscribe/69x825m78v3d/zero-dollar-product" + } + ] + } + } +} +``` + +## Errors + +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | + + +# Read Subscription + +Use this endpoint to find subscription details. + +## Self-Service Page token + +Self-Service Page token for the subscription is not returned by default. If this information is desired, the include[]=self_service_page_token parameter must be provided with the request. + +```python +def read_subscription(self, + subscription_id, + include=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `include` | [`List[SubscriptionInclude]`](../../doc/models/subscription-include.md) | Query, Optional | Allows including additional data in the response. Use in query: `include[]=coupons&include[]=self_service_page_token`. | + +## Response Type + +[`SubscriptionResponse`](../../doc/models/subscription-response.md) + +## Example Usage + +```python +subscription_id = 222 + +include = [ + SubscriptionInclude.COUPONS, + SubscriptionInclude.SELF_SERVICE_PAGE_TOKEN +] + +result = subscriptions_controller.read_subscription( + subscription_id, + include=include +) +``` + +## Example Response *(as JSON)* + +```json +{ + "subscription": { + "id": 15236915, + "state": "active", + "balance_in_cents": 0, + "total_revenue_in_cents": 14000, + "product_price_in_cents": 1000, + "product_version_number": 7, + "current_period_ends_at": "2016-11-15T14:48:10-05:00", + "next_assessment_at": "2016-11-15T14:48:10-05:00", + "trial_started_at": null, + "trial_ended_at": null, + "activated_at": "2016-11-14T14:48:12-05:00", + "expires_at": null, + "created_at": "2016-11-14T14:48:10-05:00", + "updated_at": "2016-11-14T15:24:41-05:00", + "cancellation_message": null, "cancellation_method": null, - "current_period_started_at": "2018-05-11T11:33:03-05:00", + "cancel_at_end_of_period": null, + "canceled_at": null, + "current_period_started_at": "2016-11-14T14:48:10-05:00", "previous_state": "active", - "signup_payment_id": 237154761, - "signup_revenue": "0.00", + "signup_payment_id": 162269766, + "signup_revenue": "260.00", "delayed_cancel_at": null, - "coupon_code": "COUPONA", - "total_revenue_in_cents": 52762, - "product_price_in_cents": 100000, - "product_version_number": 2, - "payment_type": "credit_card", - "referral_code": "x45nc8", - "coupon_use_count": 0, - "coupon_uses_allowed": 1, + "coupon_code": "5SNN6HFK3GBH", + "payment_collection_method": "automatic", + "snap_day": null, "reason_code": null, - "automatically_resume_at": null, - "coupon_codes": [ - "COUPONA", - "COUPONB" - ], + "receives_invoice_emails": false, + "net_terms": 0, "customer": { - "id": 21259051, - "first_name": "K", - "last_name": "C", + "first_name": "Curtis", + "last_name": "Test", + "email": "curtis@example.com", + "cc_emails": "jeff@example.com", "organization": "", - "email": "example@chargify.com", - "created_at": "2018-04-20T14:20:57-05:00", - "updated_at": "2018-04-23T15:29:28-05:00", "reference": null, - "address": "", + "id": 14714298, + "created_at": "2016-11-14T14:48:10-05:00", + "updated_at": "2016-11-14T14:48:13-05:00", + "address": "123 Anywhere Street", "address_2": "", - "city": "", - "state": "", - "zip": "", - "country": "", + "city": "Boulder", + "state": "CO", + "zip": "80302", + "country": "US", "phone": "", - "portal_invite_last_sent_at": "2018-04-20T14:20:59-05:00", - "portal_invite_last_accepted_at": null, "verified": false, - "portal_customer_created_at": "2018-04-20T14:20:59-05:00", - "cc_emails": "", - "tax_exempt": false + "portal_customer_created_at": "2016-11-14T14:48:13-05:00", + "portal_invite_last_sent_at": "2016-11-14T14:48:13-05:00", + "portal_invite_last_accepted_at": null, + "tax_exempt": false, + "vat_number": "012345678" }, "product": { - "id": 4581816, - "name": "Basic", + "id": 3792003, + "name": "$10 Basic Plan", "handle": "basic", - "description": "", - "accounting_code": "", - "request_credit_card": true, + "description": "lorem ipsum", + "accounting_code": "basic", + "price_in_cents": 1000, + "interval": 1, + "interval_unit": "day", + "initial_charge_in_cents": null, "expiration_interval": null, "expiration_interval_unit": "never", - "created_at": "2017-11-02T15:00:11-05:00", - "updated_at": "2018-04-10T09:02:59-05:00", - "price_in_cents": 100000, - "interval": 1, - "interval_unit": "month", - "initial_charge_in_cents": 100000, - "trial_price_in_cents": 1000, - "trial_interval": 10, + "trial_price_in_cents": null, + "trial_interval": null, "trial_interval_unit": "month", - "archived_at": null, - "require_credit_card": true, + "initial_charge_after_trial": false, "return_params": "", - "taxable": false, + "request_credit_card": false, + "require_credit_card": false, + "created_at": "2016-03-24T13:38:39-04:00", + "updated_at": "2016-11-03T13:03:05-04:00", + "archived_at": null, "update_return_url": "", - "tax_code": "", - "initial_charge_after_trial": false, - "version_number": 2, "update_return_params": "", "product_family": { - "id": 1025627, - "name": "My Product Family", - "description": "", - "handle": "acme-products", - "accounting_code": null + "id": 527890, + "name": "Acme Projects", + "handle": "billing-plans", + "accounting_code": null, + "description": "" }, "public_signup_pages": [ { - "id": 333589, - "return_url": "", - "return_params": "", - "url": "https://general-goods.chargifypay.com/subscribe/hbwtd98j3hk2/basic" - }, - { - "id": 335926, - "return_url": "", - "return_params": "", - "url": "https://general-goods.chargifypay.com/subscribe/g366zy67c7rm/basic" + "id": 281054, + "url": "https://general-goods.chargify.com/subscribe/kqvmfrbgd89q/basic" }, { - "id": 345555, - "return_url": "", - "return_params": "", - "url": "https://general-goods.chargifypay.com/subscribe/txqyyqk7d8rz/basic" + "id": 281240, + "url": "https://general-goods.chargify.com/subscribe/dkffht5dxfd8/basic" }, { - "id": 345556, - "return_url": "", - "return_params": "", - "url": "https://general-goods.chargifypay.com/subscribe/2zss3qpf4249/basic" + "id": 282694, + "url": "https://general-goods.chargify.com/subscribe/jwffwgdd95s8/basic" } - ] + ], + "taxable": false, + "version_number": 7, + "product_price_point_name": "Default" }, "credit_card": { - "id": 14839830, - "first_name": "John", - "last_name": "Doe", + "id": 10191713, + "payment_type": "credit_card", + "first_name": "Curtis", + "last_name": "Test", "masked_card_number": "XXXX-XXXX-XXXX-1", "card_type": "bogus", "expiration_month": 1, - "expiration_year": 2028, - "customer_id": 21259051, + "expiration_year": 2026, + "billing_address": "123 Anywhere Street", + "billing_address_2": "", + "billing_city": "Boulder", + "billing_state": null, + "billing_country": "", + "billing_zip": "80302", "current_vault": "bogus", "vault_token": "1", - "billing_address": null, - "billing_city": null, - "billing_state": null, - "billing_zip": "99999", - "billing_country": null, "customer_vault_token": null, - "billing_address_2": null, - "payment_type": "credit_card" - } + "customer_id": 14714298 + }, + "payment_type": "credit_card", + "referral_code": "w7kjc9", + "next_product_id": null, + "coupon_use_count": 1, + "coupon_uses_allowed": 1, + "stored_credential_transaction_id": 166411599220288, + "on_hold_at": null, + "scheduled_cancellation_at": "2016-11-14T14:48:13-05:00" } } ``` + +# Override Subscription + +This API endpoint allows you to set certain subscription fields that are usually managed for you automatically. Some of the fields can be set via the normal Subscriptions Update API, but others can only be set using this endpoint. + +This endpoint is provided for cases where you need to “align” Advanced Billing data with data that happened in your system, perhaps before you started using Advanced Billing. For example, you may choose to import your historical subscription data, and would like the activation and cancellation dates in Advanced Billing to match your existing historical dates. Advanced Billing does not backfill historical events (i.e. from the Events API), but some static data can be changed via this API. + +Why are some fields only settable from this endpoint, and not the normal subscription create and update endpoints? Because we want users of this endpoint to be aware that these fields are usually managed by Advanced Billing, and using this API means **you are stepping out on your own.** + +Changing these fields will not affect any other attributes. For example, adding an expiration date will not affect the next assessment date on the subscription. + +If you regularly need to override the current_period_starts_at for new subscriptions, this can also be accomplished by setting both `previous_billing_at` and `next_billing_at` at subscription creation. See the documentation on [Importing Subscriptions](./b3A6MTQxMDgzODg-create-subscription#subscriptions-import) for more information. + +## Limitations + +When passing `current_period_starts_at` some validations are made: + +1. The subscription needs to be unbilled (no statements or invoices). +2. The value passed must be a valid date/time. We recommend using the iso 8601 format. +3. The value passed must be before the current date/time. + +If unpermitted parameters are sent, a 400 HTTP response is sent along with a string giving the reason for the problem. + +```python +def override_subscription(self, + subscription_id, + body=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `subscription_id` | `int` | Template, Required | The Chargify id of the subscription | +| `body` | [`OverrideSubscriptionRequest`](../../doc/models/override-subscription-request.md) | Body, Optional | Only these fields are available to be set. | + +## Response Type + +`void` + +## Example Usage + +```python +subscription_id = 222 + +body = OverrideSubscriptionRequest( + subscription=OverrideSubscription( + activated_at=dateutil.parser.parse('1999-12-01T10:28:34-05:00'), + canceled_at=dateutil.parser.parse('2000-12-31T10:28:34-05:00'), + cancellation_message='Original cancellation in 2000', + expires_at=dateutil.parser.parse('2001-07-15T10:28:34-05:00') + ) +) + +subscriptions_controller.override_subscription( + subscription_id, + body=body +) +``` + ## Errors | HTTP Status Code | Error Description | Exception Class | | --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`SubscriptionAddCouponErrorException`](../../doc/models/subscription-add-coupon-error-exception.md) | +| 422 | Unprocessable Entity (WebDAV) | [`SingleErrorResponseException`](../../doc/models/single-error-response-exception.md) | + + +# Find Subscription + +Use this endpoint to find a subscription by its reference. + +```python +def find_subscription(self, + reference=None) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `reference` | `str` | Query, Optional | Subscription reference | + +## Response Type + +[`SubscriptionResponse`](../../doc/models/subscription-response.md) + +## Example Usage + +```python +result = subscriptions_controller.find_subscription() +``` # Remove Coupon From Subscription diff --git a/doc/controllers/webhooks.md b/doc/controllers/webhooks.md index 1e2861a2..59e068cf 100644 --- a/doc/controllers/webhooks.md +++ b/doc/controllers/webhooks.md @@ -10,108 +10,23 @@ webhooks_controller = client.webhooks ## Methods -* [List Webhooks](../../doc/controllers/webhooks.md#list-webhooks) -* [Enable Webhooks](../../doc/controllers/webhooks.md#enable-webhooks) -* [Replay Webhooks](../../doc/controllers/webhooks.md#replay-webhooks) * [Create Endpoint](../../doc/controllers/webhooks.md#create-endpoint) -* [List Endpoints](../../doc/controllers/webhooks.md#list-endpoints) * [Update Endpoint](../../doc/controllers/webhooks.md#update-endpoint) +* [Enable Webhooks](../../doc/controllers/webhooks.md#enable-webhooks) +* [List Endpoints](../../doc/controllers/webhooks.md#list-endpoints) +* [Replay Webhooks](../../doc/controllers/webhooks.md#replay-webhooks) +* [List Webhooks](../../doc/controllers/webhooks.md#list-webhooks) -# List Webhooks - -## Webhooks Intro - -The Webhooks API allows you to view a list of all webhooks and to selectively resend individual or groups of webhooks. Webhooks will be sent on endpoints specified by you. Endpoints can be added via API or Web UI. There is also an option to enable / disable webhooks via API request. - -We recommend that you review Advanced Billing's webhook documentation located in our help site. The following resources will help guide you on how to use webhooks in Advanced Billing, in addition to these webhook endpoints: - -+ [Adding/editing new webhooks](https://maxio.zendesk.com/hc/en-us/articles/24286723085197-Webhooks#configure-webhook-url) -+ [Webhooks introduction and delivery information](https://maxio.zendesk.com/hc/en-us/articles/24266143173901-Webhooks-Overview) -+ [Main webhook reference](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhooks-Reference) -+ [Available webhooks and payloads](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhooks-Reference#events) - -## List Webhooks for a Site - -This method allows you to fetch data about webhooks. You can pass query parameters if you want to filter webhooks. - -```python -def list_webhooks(self, - options=dict()) -``` - -## Parameters - -| Parameter | Type | Tags | Description | -| --- | --- | --- | --- | -| `status` | [`WebhookStatus`](../../doc/models/webhook-status.md) | Query, Optional | Webhooks with matching status would be returned. | -| `since_date` | `str` | Query, Optional | Format YYYY-MM-DD. Returns Webhooks with the created_at date greater than or equal to the one specified. | -| `until_date` | `str` | Query, Optional | Format YYYY-MM-DD. Returns Webhooks with the created_at date less than or equal to the one specified. | -| `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`. | -| `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`. | -| `order` | [`WebhookOrder`](../../doc/models/webhook-order.md) | Query, Optional | The order in which the Webhooks are returned. | -| `subscription` | `int` | Query, Optional | The Advanced Billing id of a subscription you'd like to filter for | - -## Response Type - -[`List[WebhookResponse]`](../../doc/models/webhook-response.md) - -## Example Usage - -```python -collect = { - 'page': 2, - 'per_page': 50 -} -result = webhooks_controller.list_webhooks(collect) -``` - -## Example Response *(as JSON)* - -```json -[ - { - "webhook": { - "event": "statement_settled", - "id": 141765032, - "created_at": "2016-11-08T16:22:26-05:00", - "last_error": "404 Resource Not Found (retry 5 of 5)", - "last_error_at": "2016-11-08T16:43:54-05:00", - "accepted_at": null, - "last_sent_at": "2016-11-08T16:43:54-05:00", - "last_sent_url": "http://requestb.in/11u45x71", - "successful": false, - "body": "id=141765032&event=statement_settled&payload[site][id]=31615&payload[site][subdomain]=general-goods&payload[subscription][id]=15100141&payload[subscription][state]=active&payload[subscription][balance_in_cents]=0&payload[customer][id]=14585695&payload[customer][first_name]=Pookie&payload[customer][last_name]=Test&payload[customer][reference]=&payload[customer][organization]=&payload[customer][address]=&payload[customer][address_2]=&payload[customer][city]=&payload[customer][state]=&payload[customer][zip]=&payload[customer][country]=&payload[customer][email]=pookie999%40example.com&payload[customer][phone]=&payload[statement][closed_at]=2016-11-08%2016%3A22%3A20%20-0500&payload[statement][created_at]=2016-11-08%2016%3A22%3A18%20-0500&payload[statement][id]=80168049&payload[statement][opened_at]=2016-11-07%2016%3A22%3A15%20-0500&payload[statement][settled_at]=2016-11-08%2016%3A22%3A20%20-0500&payload[statement][subscription_id]=15100141&payload[statement][updated_at]=2016-11-08%2016%3A22%3A20%20-0500&payload[statement][starting_balance_in_cents]=0&payload[statement][ending_balance_in_cents]=0&payload[statement][total_in_cents]=6400&payload[statement][memo]=We%20thank%20you%20for%20your%20continued%20business!&payload[statement][events][0][id]=346956565&payload[statement][events][0][key]=renewal_success&payload[statement][events][0][message]=Successful%20renewal%20for%20Pookie%20Test's%20subscription%20to%20%2410%20Basic%20Plan&payload[statement][events][1][id]=346956579&payload[statement][events][1][key]=payment_success&payload[statement][events][1][message]=Successful%20payment%20of%20%2464.00%20for%20Pookie%20Test's%20subscription%20to%20%2410%20Basic%20Plan&payload[statement][events][2][id]=347299359&payload[statement][events][2][key]=renewal_success&payload[statement][events][2][message]=Successful%20renewal%20for%20Pookie%20Test's%20subscription%20to%20%2410%20Basic%20Plan&payload[statement][transactions][0][id]=161537343&payload[statement][transactions][0][subscription_id]=15100141&payload[statement][transactions][0][type]=Charge&payload[statement][transactions][0][kind]=baseline&payload[statement][transactions][0][transaction_type]=charge&payload[statement][transactions][0][success]=true&payload[statement][transactions][0][amount_in_cents]=1000&payload[statement][transactions][0][memo]=%2410%20Basic%20Plan%20(11%2F08%2F2016%20-%2011%2F09%2F2016)&payload[statement][transactions][0][created_at]=2016-11-08%2016%3A22%3A18%20-0500&payload[statement][transactions][0][starting_balance_in_cents]=0&payload[statement][transactions][0][ending_balance_in_cents]=1000&payload[statement][transactions][0][gateway_used]=&payload[statement][transactions][0][gateway_transaction_id]=&payload[statement][transactions][0][gateway_order_id]=&payload[statement][transactions][0][payment_id]=161537369&payload[statement][transactions][0][product_id]=3792003&payload[statement][transactions][0][tax_id]=&payload[statement][transactions][0][component_id]=&payload[statement][transactions][0][statement_id]=80168049&payload[statement][transactions][0][customer_id]=14585695&payload[statement][transactions][0][original_amount_in_cents]=&payload[statement][transactions][0][discount_amount_in_cents]=&payload[statement][transactions][0][taxable_amount_in_cents]=&payload[statement][transactions][1][id]=161537344&payload[statement][transactions][1][subscription_id]=15100141&payload[statement][transactions][1][type]=Charge&payload[statement][transactions][1][kind]=quantity_based_component&payload[statement][transactions][1][transaction_type]=charge&payload[statement][transactions][1][success]=true&payload[statement][transactions][1][amount_in_cents]=5400&payload[statement][transactions][1][memo]=Timesheet%20Users%3A%2018%20Timesheet%20Users&payload[statement][transactions][1][created_at]=2016-11-08%2016%3A22%3A18%20-0500&payload[statement][transactions][1][starting_balance_in_cents]=1000&payload[statement][transactions][1][ending_balance_in_cents]=6400&payload[statement][transactions][1][gateway_used]=&payload[statement][transactions][1][gateway_transaction_id]=&payload[statement][transactions][1][gateway_order_id]=&payload[statement][transactions][1][payment_id]=161537369&payload[statement][transactions][1][product_id]=3792003&payload[statement][transactions][1][tax_id]=&payload[statement][transactions][1][component_id]=277221&payload[statement][transactions][1][statement_id]=80168049&payload[statement][transactions][1][customer_id]=14585695&payload[statement][transactions][1][original_amount_in_cents]=&payload[statement][transactions][1][discount_amount_in_cents]=&payload[statement][transactions][1][taxable_amount_in_cents]=&payload[statement][transactions][2][id]=161537369&payload[statement][transactions][2][subscription_id]=15100141&payload[statement][transactions][2][type]=Payment&payload[statement][transactions][2][kind]=&payload[statement][transactions][2][transaction_type]=payment&payload[statement][transactions][2][success]=true&payload[statement][transactions][2][amount_in_cents]=6400&payload[statement][transactions][2][memo]=Pookie%20Test%20-%20%2410%20Basic%20Plan%3A%20Renewal%20payment&payload[statement][transactions][2][created_at]=2016-11-08%2016%3A22%3A20%20-0500&payload[statement][transactions][2][starting_balance_in_cents]=6400&payload[statement][transactions][2][ending_balance_in_cents]=0&payload[statement][transactions][2][gateway_used]=bogus&payload[statement][transactions][2][gateway_transaction_id]=53433&payload[statement][transactions][2][gateway_order_id]=&payload[statement][transactions][2][payment_id]=&payload[statement][transactions][2][product_id]=3792003&payload[statement][transactions][2][tax_id]=&payload[statement][transactions][2][component_id]=&payload[statement][transactions][2][statement_id]=80168049&payload[statement][transactions][2][customer_id]=14585695&payload[statement][transactions][2][card_number]=XXXX-XXXX-XXXX-1&payload[statement][transactions][2][card_expiration]=10%2F2020&payload[statement][transactions][2][card_type]=bogus&payload[statement][transactions][2][refunded_amount_in_cents]=0&payload[product][id]=3792003&payload[product][name]=%2410%20Basic%20Plan&payload[product_family][id]=527890&payload[product_family][name]=Acme%20Projects&payload[payment_profile][id]=10102821&payload[payment_profile][first_name]=Pookie&payload[payment_profile][last_name]=Test&payload[payment_profile][billing_address]=&payload[payment_profile][billing_address_2]=&payload[payment_profile][billing_city]=&payload[payment_profile][billing_country]=&payload[payment_profile][billing_state]=&payload[payment_profile][billing_zip]=&payload[event_id]=347299384", - "signature": "7c606ec4628ce75ec46e284097ce163a", - "signature_hmac_sha_256": "40f25e83dd324508bb2149e3e525821922fb210535ebfbfa81e7ab951996b41d" - } - }, - { - "webhook": { - "event": "payment_success", - "id": 141765008, - "created_at": "2016-11-08T16:22:25-05:00", - "last_error": "404 Resource Not Found (retry 5 of 5)", - "last_error_at": "2016-11-08T16:43:54-05:00", - "accepted_at": null, - "last_sent_at": "2016-11-08T16:43:54-05:00", - "last_sent_url": "http://requestb.in/11u45x71", - "successful": false, - "body": "id=141765008&event=payment_success&payload[site][id]=31615&payload[site][subdomain]=general-goods&payload[subscription][id]=15100141&payload[subscription][state]=active&payload[subscription][trial_started_at]=&payload[subscription][trial_ended_at]=&payload[subscription][activated_at]=2016-11-04%2017%3A06%3A43%20-0400&payload[subscription][created_at]=2016-11-04%2017%3A06%3A42%20-0400&payload[subscription][updated_at]=2016-11-08%2016%3A22%3A22%20-0500&payload[subscription][expires_at]=&payload[subscription][balance_in_cents]=0&payload[subscription][current_period_ends_at]=2016-11-09%2016%3A06%3A42%20-0500&payload[subscription][next_assessment_at]=2016-11-09%2016%3A06%3A42%20-0500&payload[subscription][canceled_at]=&payload[subscription][cancellation_message]=&payload[subscription][next_product_id]=&payload[subscription][cancel_at_end_of_period]=false&payload[subscription][payment_collection_method]=automatic&payload[subscription][snap_day]=&payload[subscription][cancellation_method]=&payload[subscription][current_period_started_at]=2016-11-08%2016%3A06%3A42%20-0500&payload[subscription][previous_state]=active&payload[subscription][signup_payment_id]=161034048&payload[subscription][signup_revenue]=64.00&payload[subscription][delayed_cancel_at]=&payload[subscription][coupon_code]=&payload[subscription][total_revenue_in_cents]=32000&payload[subscription][product_price_in_cents]=1000&payload[subscription][product_version_number]=7&payload[subscription][payment_type]=credit_card&payload[subscription][referral_code]=pggn84&payload[subscription][coupon_use_count]=&payload[subscription][coupon_uses_allowed]=&payload[subscription][customer][id]=14585695&payload[subscription][customer][first_name]=Test&payload[subscription][customer][last_name]=Test&payload[subscription][customer][organization]=&payload[subscription][customer][email]=pookie999%40example.com&payload[subscription][customer][created_at]=2016-11-04%2017%3A06%3A42%20-0400&payload[subscription][customer][updated_at]=2016-11-04%2017%3A06%3A45%20-0400&payload[subscription][customer][reference]=&payload[subscription][customer][address]=&payload[subscription][customer][address_2]=&payload[subscription][customer][city]=&payload[subscription][customer][state]=&payload[subscription][customer][zip]=&payload[subscription][customer][country]=&payload[subscription][customer][phone]=&payload[subscription][customer][portal_invite_last_sent_at]=2016-11-04%2017%3A06%3A45%20-0400&payload[subscription][customer][portal_invite_last_accepted_at]=&payload[subscription][customer][verified]=false&payload[subscription][customer][portal_customer_created_at]=2016-11-04%2017%3A06%3A45%20-0400&payload[subscription][customer][cc_emails]=&payload[subscription][product][id]=3792003&payload[subscription][product][name]=%2410%20Basic%20Plan&payload[subscription][product][handle]=basic&payload[subscription][product][description]=lorem%20ipsum&payload[subscription][product][accounting_code]=basic&payload[subscription][product][request_credit_card]=false&payload[subscription][product][expiration_interval]=&payload[subscription][product][expiration_interval_unit]=never&payload[subscription][product][created_at]=2016-03-24%2013%3A38%3A39%20-0400&payload[subscription][product][updated_at]=2016-11-03%2013%3A03%3A05%20-0400&payload[subscription][product][price_in_cents]=1000&payload[subscription][product][interval]=1&payload[subscription][product][interval_unit]=day&payload[subscription][product][initial_charge_in_cents]=&payload[subscription][product][trial_price_in_cents]=&payload[subscription][product][trial_interval]=&payload[subscription][product][trial_interval_unit]=month&payload[subscription][product][archived_at]=&payload[subscription][product][require_credit_card]=false&payload[subscription][product][return_params]=&payload[subscription][product][taxable]=false&payload[subscription][product][update_return_url]=&payload[subscription][product][initial_charge_after_trial]=false&payload[subscription][product][version_number]=7&payload[subscription][product][update_return_params]=&payload[subscription][product][product_family][id]=527890&payload[subscription][product][product_family][name]=Acme%20Projects&payload[subscription][product][product_family][description]=&payload[subscription][product][product_family][handle]=billing-plans&payload[subscription][product][product_family][accounting_code]=&payload[subscription][product][public_signup_pages][id]=281054&payload[subscription][product][public_signup_pages][return_url]=http%3A%2F%2Fwww.example.com%3Fsuccessfulsignup&payload[subscription][product][public_signup_pages][return_params]=&payload[subscription][product][public_signup_pages][url]=https%3A%2F%2Fgeneral-goods.chargify.com%2Fsubscribe%2Fkqvmfrbgd89q%2Fbasic&payload[subscription][product][public_signup_pages][id]=281240&payload[subscription][product][public_signup_pages][return_url]=&payload[subscription][product][public_signup_pages][return_params]=&payload[subscription][product][public_signup_pages][url]=https%3A%2F%2Fgeneral-goods.chargify.com%2Fsubscribe%2Fdkffht5dxfd8%2Fbasic&payload[subscription][product][public_signup_pages][id]=282694&payload[subscription][product][public_signup_pages][return_url]=&payload[subscription][product][public_signup_pages][return_params]=&payload[subscription][product][public_signup_pages][url]=https%3A%2F%2Fgeneral-goods.chargify.com%2Fsubscribe%2Fjwffwgdd95s8%2Fbasic&payload[subscription][credit_card][id]=10102821&payload[subscription][credit_card][first_name]=Pookie&payload[subscription][credit_card][last_name]=Test&payload[subscription][credit_card][masked_card_number]=XXXX-XXXX-XXXX-1&payload[subscription][credit_card][card_type]=bogus&payload[subscription][credit_card][expiration_month]=10&payload[subscription][credit_card][expiration_year]=2020&payload[subscription][credit_card][customer_id]=14585695&payload[subscription][credit_card][current_vault]=bogus&payload[subscription][credit_card][vault_token]=1&payload[subscription][credit_card][billing_address]=&payload[subscription][credit_card][billing_city]=&payload[subscription][credit_card][billing_state]=&payload[subscription][credit_card][billing_zip]=&payload[subscription][credit_card][billing_country]=&payload[subscription][credit_card][customer_vault_token]=&payload[subscription][credit_card][billing_address_2]=&payload[subscription][credit_card][payment_type]=credit_card&payload[subscription][credit_card][site_gateway_setting_id]=&payload[subscription][credit_card][gateway_handle]=&payload[transaction][id]=161537369&payload[transaction][subscription_id]=15100141&payload[transaction][type]=Payment&payload[transaction][kind]=&payload[transaction][transaction_type]=payment&payload[transaction][success]=true&payload[transaction][amount_in_cents]=6400&payload[transaction][memo]=Pookie%20Test%20-%20%2410%20Basic%20Plan%3A%20Renewal%20payment&payload[transaction][created_at]=2016-11-08%2016%3A22%3A20%20-0500&payload[transaction][starting_balance_in_cents]=6400&payload[transaction][ending_balance_in_cents]=0&payload[transaction][gateway_used]=bogus&payload[transaction][gateway_transaction_id]=53433&payload[transaction][gateway_response_code]=&payload[transaction][gateway_order_id]=&payload[transaction][payment_id]=&payload[transaction][product_id]=3792003&payload[transaction][tax_id]=&payload[transaction][component_id]=&payload[transaction][statement_id]=80168049&payload[transaction][customer_id]=14585695&payload[transaction][card_number]=XXXX-XXXX-XXXX-1&payload[transaction][card_expiration]=10%2F2020&payload[transaction][card_type]=bogus&payload[transaction][refunded_amount_in_cents]=0&payload[transaction][invoice_id]=&payload[event_id]=347299364", - "signature": "fbcf2f6be579f9658cff90c4373e0ca2", - "signature_hmac_sha_256": "db96654f5456c5460062feb944ac8bb1418f9d181ae04a8ed982fe9ffdca8de1" - } - } -] -``` - +# Create Endpoint -# Enable Webhooks +The Chargify API allows you to create an endpoint and assign a list of webhooks subscriptions (events) to it. -This method allows you to enable webhooks via API for your site +You can check available events here. +[Event keys](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhooks-Reference#events) ```python -def enable_webhooks(self, +def create_endpoint(self, body=None) ``` @@ -119,20 +34,26 @@ def enable_webhooks(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `body` | [`EnableWebhooksRequest`](../../doc/models/enable-webhooks-request.md) | Body, Optional | - | +| `body` | [`CreateOrUpdateEndpointRequest`](../../doc/models/create-or-update-endpoint-request.md) | Body, Optional | Used to Create or Update Endpoint | ## Response Type -[`EnableWebhooksResponse`](../../doc/models/enable-webhooks-response.md) +[`EndpointResponse`](../../doc/models/endpoint-response.md) ## Example Usage ```python -body = EnableWebhooksRequest( - webhooks_enabled=True +body = CreateOrUpdateEndpointRequest( + endpoint=CreateOrUpdateEndpoint( + url='https://your.site/webhooks', + webhook_subscriptions=[ + WebhookSubscription.PAYMENT_SUCCESS, + WebhookSubscription.PAYMENT_FAILURE + ] + ) ) -result = webhooks_controller.enable_webhooks( +result = webhooks_controller.create_endpoint( body=body ) ``` @@ -141,19 +62,41 @@ result = webhooks_controller.enable_webhooks( ```json { - "webhooks_enabled": true + "endpoint": { + "id": 1, + "url": "https://your.site/webhooks", + "site_id": 1, + "status": "enabled", + "webhook_subscriptions": [ + "payment_success", + "payment_failure" + ] + } } ``` +## Errors -# Replay Webhooks +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -Posting to the replay endpoint does not immediately resend the webhooks. They are added to a queue and will be sent as soon as possible, depending on available system resources. -You may submit an array of up to 1000 webhook IDs to replay in the request. +# Update Endpoint + +You can update an Endpoint via the API with a PUT request to the resource endpoint. + +You can change the `url` of your endpoint which consumes webhooks or list of `webhook_subscriptions`. +Check available [Event keys](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhooks-Reference#events). + +Always send a complete list of events which you want subscribe/watch. +Sending an PUT request for existing endpoint with empty list of `webhook_subscriptions` will end with unsubscribe from all events. + +If you want unsubscribe from specific event, just send a list of `webhook_subscriptions` without the specific event key. ```python -def replay_webhooks(self, +def update_endpoint(self, + endpoint_id, body=None) ``` @@ -161,45 +104,49 @@ def replay_webhooks(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `body` | [`ReplayWebhooksRequest`](../../doc/models/replay-webhooks-request.md) | Body, Optional | - | +| `endpoint_id` | `int` | Template, Required | The Advanced Billing id for the endpoint that should be updated | +| `body` | [`CreateOrUpdateEndpointRequest`](../../doc/models/create-or-update-endpoint-request.md) | Body, Optional | Used to Create or Update Endpoint | ## Response Type -[`ReplayWebhooksResponse`](../../doc/models/replay-webhooks-response.md) +[`EndpointResponse`](../../doc/models/endpoint-response.md) ## Example Usage ```python -body = ReplayWebhooksRequest( - ids=[ - 123456789, - 123456788 - ] +endpoint_id = 42 + +body = CreateOrUpdateEndpointRequest( + endpoint=CreateOrUpdateEndpoint( + url='https://yout.site/webhooks/1/json.', + webhook_subscriptions=[ + WebhookSubscription.PAYMENT_FAILURE, + WebhookSubscription.PAYMENT_SUCCESS, + WebhookSubscription.REFUND_FAILURE + ] + ) ) -result = webhooks_controller.replay_webhooks( +result = webhooks_controller.update_endpoint( + endpoint_id, body=body ) ``` -## Example Response *(as JSON)* - -```json -{ - "status": "ok" -} -``` +## Errors +| HTTP Status Code | Error Description | Exception Class | +| --- | --- | --- | +| 404 | Not Found | `APIException` | +| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | -# Create Endpoint -The Chargify API allows you to create an endpoint and assign a list of webhooks subscriptions (events) to it. +# Enable Webhooks -You can check available events here. -[Event keys](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhooks-Reference#events) +This method allows you to enable webhooks via API for your site ```python -def create_endpoint(self, +def enable_webhooks(self, body=None) ``` @@ -207,26 +154,20 @@ def create_endpoint(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `body` | [`CreateOrUpdateEndpointRequest`](../../doc/models/create-or-update-endpoint-request.md) | Body, Optional | Used to Create or Update Endpoint | +| `body` | [`EnableWebhooksRequest`](../../doc/models/enable-webhooks-request.md) | Body, Optional | - | ## Response Type -[`EndpointResponse`](../../doc/models/endpoint-response.md) +[`EnableWebhooksResponse`](../../doc/models/enable-webhooks-response.md) ## Example Usage ```python -body = CreateOrUpdateEndpointRequest( - endpoint=CreateOrUpdateEndpoint( - url='https://your.site/webhooks', - webhook_subscriptions=[ - WebhookSubscription.PAYMENT_SUCCESS, - WebhookSubscription.PAYMENT_FAILURE - ] - ) +body = EnableWebhooksRequest( + webhooks_enabled=True ) -result = webhooks_controller.create_endpoint( +result = webhooks_controller.enable_webhooks( body=body ) ``` @@ -235,25 +176,10 @@ result = webhooks_controller.create_endpoint( ```json { - "endpoint": { - "id": 1, - "url": "https://your.site/webhooks", - "site_id": 1, - "status": "enabled", - "webhook_subscriptions": [ - "payment_success", - "payment_failure" - ] - } + "webhooks_enabled": true } ``` -## Errors - -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | - # List Endpoints @@ -302,21 +228,14 @@ result = webhooks_controller.list_endpoints() ``` -# Update Endpoint - -You can update an Endpoint via the API with a PUT request to the resource endpoint. - -You can change the `url` of your endpoint which consumes webhooks or list of `webhook_subscriptions`. -Check available [Event keys](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhooks-Reference#events). +# Replay Webhooks -Always send a complete list of events which you want subscribe/watch. -Sending an PUT request for existing endpoint with empty list of `webhook_subscriptions` will end with unsubscribe from all events. +Posting to the replay endpoint does not immediately resend the webhooks. They are added to a queue and will be sent as soon as possible, depending on available system resources. -If you want unsubscribe from specific event, just send a list of `webhook_subscriptions` without the specific event key. +You may submit an array of up to 1000 webhook IDs to replay in the request. ```python -def update_endpoint(self, - endpoint_id, +def replay_webhooks(self, body=None) ``` @@ -324,39 +243,120 @@ def update_endpoint(self, | Parameter | Type | Tags | Description | | --- | --- | --- | --- | -| `endpoint_id` | `int` | Template, Required | The Advanced Billing id for the endpoint that should be updated | -| `body` | [`CreateOrUpdateEndpointRequest`](../../doc/models/create-or-update-endpoint-request.md) | Body, Optional | Used to Create or Update Endpoint | +| `body` | [`ReplayWebhooksRequest`](../../doc/models/replay-webhooks-request.md) | Body, Optional | - | ## Response Type -[`EndpointResponse`](../../doc/models/endpoint-response.md) +[`ReplayWebhooksResponse`](../../doc/models/replay-webhooks-response.md) ## Example Usage ```python -endpoint_id = 42 - -body = CreateOrUpdateEndpointRequest( - endpoint=CreateOrUpdateEndpoint( - url='https://yout.site/webhooks/1/json.', - webhook_subscriptions=[ - WebhookSubscription.PAYMENT_FAILURE, - WebhookSubscription.PAYMENT_SUCCESS, - WebhookSubscription.REFUND_FAILURE - ] - ) +body = ReplayWebhooksRequest( + ids=[ + 123456789, + 123456788 + ] ) -result = webhooks_controller.update_endpoint( - endpoint_id, +result = webhooks_controller.replay_webhooks( body=body ) ``` -## Errors +## Example Response *(as JSON)* -| HTTP Status Code | Error Description | Exception Class | -| --- | --- | --- | -| 404 | Not Found | `APIException` | -| 422 | Unprocessable Entity (WebDAV) | [`ErrorListResponseException`](../../doc/models/error-list-response-exception.md) | +```json +{ + "status": "ok" +} +``` + + +# List Webhooks + +## Webhooks Intro + +The Webhooks API allows you to view a list of all webhooks and to selectively resend individual or groups of webhooks. Webhooks will be sent on endpoints specified by you. Endpoints can be added via API or Web UI. There is also an option to enable / disable webhooks via API request. + +We recommend that you review Advanced Billing's webhook documentation located in our help site. The following resources will help guide you on how to use webhooks in Advanced Billing, in addition to these webhook endpoints: + ++ [Adding/editing new webhooks](https://maxio.zendesk.com/hc/en-us/articles/24286723085197-Webhooks#configure-webhook-url) ++ [Webhooks introduction and delivery information](https://maxio.zendesk.com/hc/en-us/articles/24266143173901-Webhooks-Overview) ++ [Main webhook reference](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhooks-Reference) ++ [Available webhooks and payloads](https://maxio.zendesk.com/hc/en-us/articles/24266136649869-Webhooks-Reference#events) + +## List Webhooks for a Site + +This method allows you to fetch data about webhooks. You can pass query parameters if you want to filter webhooks. + +```python +def list_webhooks(self, + options=dict()) +``` + +## Parameters + +| Parameter | Type | Tags | Description | +| --- | --- | --- | --- | +| `status` | [`WebhookStatus`](../../doc/models/webhook-status.md) | Query, Optional | Webhooks with matching status would be returned. | +| `since_date` | `str` | Query, Optional | Format YYYY-MM-DD. Returns Webhooks with the created_at date greater than or equal to the one specified. | +| `until_date` | `str` | Query, Optional | Format YYYY-MM-DD. Returns Webhooks with the created_at date less than or equal to the one specified. | +| `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`. | +| `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`. | +| `order` | [`WebhookOrder`](../../doc/models/webhook-order.md) | Query, Optional | The order in which the Webhooks are returned. | +| `subscription` | `int` | Query, Optional | The Advanced Billing id of a subscription you'd like to filter for | + +## Response Type + +[`List[WebhookResponse]`](../../doc/models/webhook-response.md) + +## Example Usage + +```python +collect = { + 'page': 2, + 'per_page': 50 +} +result = webhooks_controller.list_webhooks(collect) +``` + +## Example Response *(as JSON)* + +```json +[ + { + "webhook": { + "event": "statement_settled", + "id": 141765032, + "created_at": "2016-11-08T16:22:26-05:00", + "last_error": "404 Resource Not Found (retry 5 of 5)", + "last_error_at": "2016-11-08T16:43:54-05:00", + "accepted_at": null, + "last_sent_at": "2016-11-08T16:43:54-05:00", + "last_sent_url": "http://requestb.in/11u45x71", + "successful": false, + "body": "id=141765032&event=statement_settled&payload[site][id]=31615&payload[site][subdomain]=general-goods&payload[subscription][id]=15100141&payload[subscription][state]=active&payload[subscription][balance_in_cents]=0&payload[customer][id]=14585695&payload[customer][first_name]=Pookie&payload[customer][last_name]=Test&payload[customer][reference]=&payload[customer][organization]=&payload[customer][address]=&payload[customer][address_2]=&payload[customer][city]=&payload[customer][state]=&payload[customer][zip]=&payload[customer][country]=&payload[customer][email]=pookie999%40example.com&payload[customer][phone]=&payload[statement][closed_at]=2016-11-08%2016%3A22%3A20%20-0500&payload[statement][created_at]=2016-11-08%2016%3A22%3A18%20-0500&payload[statement][id]=80168049&payload[statement][opened_at]=2016-11-07%2016%3A22%3A15%20-0500&payload[statement][settled_at]=2016-11-08%2016%3A22%3A20%20-0500&payload[statement][subscription_id]=15100141&payload[statement][updated_at]=2016-11-08%2016%3A22%3A20%20-0500&payload[statement][starting_balance_in_cents]=0&payload[statement][ending_balance_in_cents]=0&payload[statement][total_in_cents]=6400&payload[statement][memo]=We%20thank%20you%20for%20your%20continued%20business!&payload[statement][events][0][id]=346956565&payload[statement][events][0][key]=renewal_success&payload[statement][events][0][message]=Successful%20renewal%20for%20Pookie%20Test's%20subscription%20to%20%2410%20Basic%20Plan&payload[statement][events][1][id]=346956579&payload[statement][events][1][key]=payment_success&payload[statement][events][1][message]=Successful%20payment%20of%20%2464.00%20for%20Pookie%20Test's%20subscription%20to%20%2410%20Basic%20Plan&payload[statement][events][2][id]=347299359&payload[statement][events][2][key]=renewal_success&payload[statement][events][2][message]=Successful%20renewal%20for%20Pookie%20Test's%20subscription%20to%20%2410%20Basic%20Plan&payload[statement][transactions][0][id]=161537343&payload[statement][transactions][0][subscription_id]=15100141&payload[statement][transactions][0][type]=Charge&payload[statement][transactions][0][kind]=baseline&payload[statement][transactions][0][transaction_type]=charge&payload[statement][transactions][0][success]=true&payload[statement][transactions][0][amount_in_cents]=1000&payload[statement][transactions][0][memo]=%2410%20Basic%20Plan%20(11%2F08%2F2016%20-%2011%2F09%2F2016)&payload[statement][transactions][0][created_at]=2016-11-08%2016%3A22%3A18%20-0500&payload[statement][transactions][0][starting_balance_in_cents]=0&payload[statement][transactions][0][ending_balance_in_cents]=1000&payload[statement][transactions][0][gateway_used]=&payload[statement][transactions][0][gateway_transaction_id]=&payload[statement][transactions][0][gateway_order_id]=&payload[statement][transactions][0][payment_id]=161537369&payload[statement][transactions][0][product_id]=3792003&payload[statement][transactions][0][tax_id]=&payload[statement][transactions][0][component_id]=&payload[statement][transactions][0][statement_id]=80168049&payload[statement][transactions][0][customer_id]=14585695&payload[statement][transactions][0][original_amount_in_cents]=&payload[statement][transactions][0][discount_amount_in_cents]=&payload[statement][transactions][0][taxable_amount_in_cents]=&payload[statement][transactions][1][id]=161537344&payload[statement][transactions][1][subscription_id]=15100141&payload[statement][transactions][1][type]=Charge&payload[statement][transactions][1][kind]=quantity_based_component&payload[statement][transactions][1][transaction_type]=charge&payload[statement][transactions][1][success]=true&payload[statement][transactions][1][amount_in_cents]=5400&payload[statement][transactions][1][memo]=Timesheet%20Users%3A%2018%20Timesheet%20Users&payload[statement][transactions][1][created_at]=2016-11-08%2016%3A22%3A18%20-0500&payload[statement][transactions][1][starting_balance_in_cents]=1000&payload[statement][transactions][1][ending_balance_in_cents]=6400&payload[statement][transactions][1][gateway_used]=&payload[statement][transactions][1][gateway_transaction_id]=&payload[statement][transactions][1][gateway_order_id]=&payload[statement][transactions][1][payment_id]=161537369&payload[statement][transactions][1][product_id]=3792003&payload[statement][transactions][1][tax_id]=&payload[statement][transactions][1][component_id]=277221&payload[statement][transactions][1][statement_id]=80168049&payload[statement][transactions][1][customer_id]=14585695&payload[statement][transactions][1][original_amount_in_cents]=&payload[statement][transactions][1][discount_amount_in_cents]=&payload[statement][transactions][1][taxable_amount_in_cents]=&payload[statement][transactions][2][id]=161537369&payload[statement][transactions][2][subscription_id]=15100141&payload[statement][transactions][2][type]=Payment&payload[statement][transactions][2][kind]=&payload[statement][transactions][2][transaction_type]=payment&payload[statement][transactions][2][success]=true&payload[statement][transactions][2][amount_in_cents]=6400&payload[statement][transactions][2][memo]=Pookie%20Test%20-%20%2410%20Basic%20Plan%3A%20Renewal%20payment&payload[statement][transactions][2][created_at]=2016-11-08%2016%3A22%3A20%20-0500&payload[statement][transactions][2][starting_balance_in_cents]=6400&payload[statement][transactions][2][ending_balance_in_cents]=0&payload[statement][transactions][2][gateway_used]=bogus&payload[statement][transactions][2][gateway_transaction_id]=53433&payload[statement][transactions][2][gateway_order_id]=&payload[statement][transactions][2][payment_id]=&payload[statement][transactions][2][product_id]=3792003&payload[statement][transactions][2][tax_id]=&payload[statement][transactions][2][component_id]=&payload[statement][transactions][2][statement_id]=80168049&payload[statement][transactions][2][customer_id]=14585695&payload[statement][transactions][2][card_number]=XXXX-XXXX-XXXX-1&payload[statement][transactions][2][card_expiration]=10%2F2020&payload[statement][transactions][2][card_type]=bogus&payload[statement][transactions][2][refunded_amount_in_cents]=0&payload[product][id]=3792003&payload[product][name]=%2410%20Basic%20Plan&payload[product_family][id]=527890&payload[product_family][name]=Acme%20Projects&payload[payment_profile][id]=10102821&payload[payment_profile][first_name]=Pookie&payload[payment_profile][last_name]=Test&payload[payment_profile][billing_address]=&payload[payment_profile][billing_address_2]=&payload[payment_profile][billing_city]=&payload[payment_profile][billing_country]=&payload[payment_profile][billing_state]=&payload[payment_profile][billing_zip]=&payload[event_id]=347299384", + "signature": "7c606ec4628ce75ec46e284097ce163a", + "signature_hmac_sha_256": "40f25e83dd324508bb2149e3e525821922fb210535ebfbfa81e7ab951996b41d" + } + }, + { + "webhook": { + "event": "payment_success", + "id": 141765008, + "created_at": "2016-11-08T16:22:25-05:00", + "last_error": "404 Resource Not Found (retry 5 of 5)", + "last_error_at": "2016-11-08T16:43:54-05:00", + "accepted_at": null, + "last_sent_at": "2016-11-08T16:43:54-05:00", + "last_sent_url": "http://requestb.in/11u45x71", + "successful": false, + "body": "id=141765008&event=payment_success&payload[site][id]=31615&payload[site][subdomain]=general-goods&payload[subscription][id]=15100141&payload[subscription][state]=active&payload[subscription][trial_started_at]=&payload[subscription][trial_ended_at]=&payload[subscription][activated_at]=2016-11-04%2017%3A06%3A43%20-0400&payload[subscription][created_at]=2016-11-04%2017%3A06%3A42%20-0400&payload[subscription][updated_at]=2016-11-08%2016%3A22%3A22%20-0500&payload[subscription][expires_at]=&payload[subscription][balance_in_cents]=0&payload[subscription][current_period_ends_at]=2016-11-09%2016%3A06%3A42%20-0500&payload[subscription][next_assessment_at]=2016-11-09%2016%3A06%3A42%20-0500&payload[subscription][canceled_at]=&payload[subscription][cancellation_message]=&payload[subscription][next_product_id]=&payload[subscription][cancel_at_end_of_period]=false&payload[subscription][payment_collection_method]=automatic&payload[subscription][snap_day]=&payload[subscription][cancellation_method]=&payload[subscription][current_period_started_at]=2016-11-08%2016%3A06%3A42%20-0500&payload[subscription][previous_state]=active&payload[subscription][signup_payment_id]=161034048&payload[subscription][signup_revenue]=64.00&payload[subscription][delayed_cancel_at]=&payload[subscription][coupon_code]=&payload[subscription][total_revenue_in_cents]=32000&payload[subscription][product_price_in_cents]=1000&payload[subscription][product_version_number]=7&payload[subscription][payment_type]=credit_card&payload[subscription][referral_code]=pggn84&payload[subscription][coupon_use_count]=&payload[subscription][coupon_uses_allowed]=&payload[subscription][customer][id]=14585695&payload[subscription][customer][first_name]=Test&payload[subscription][customer][last_name]=Test&payload[subscription][customer][organization]=&payload[subscription][customer][email]=pookie999%40example.com&payload[subscription][customer][created_at]=2016-11-04%2017%3A06%3A42%20-0400&payload[subscription][customer][updated_at]=2016-11-04%2017%3A06%3A45%20-0400&payload[subscription][customer][reference]=&payload[subscription][customer][address]=&payload[subscription][customer][address_2]=&payload[subscription][customer][city]=&payload[subscription][customer][state]=&payload[subscription][customer][zip]=&payload[subscription][customer][country]=&payload[subscription][customer][phone]=&payload[subscription][customer][portal_invite_last_sent_at]=2016-11-04%2017%3A06%3A45%20-0400&payload[subscription][customer][portal_invite_last_accepted_at]=&payload[subscription][customer][verified]=false&payload[subscription][customer][portal_customer_created_at]=2016-11-04%2017%3A06%3A45%20-0400&payload[subscription][customer][cc_emails]=&payload[subscription][product][id]=3792003&payload[subscription][product][name]=%2410%20Basic%20Plan&payload[subscription][product][handle]=basic&payload[subscription][product][description]=lorem%20ipsum&payload[subscription][product][accounting_code]=basic&payload[subscription][product][request_credit_card]=false&payload[subscription][product][expiration_interval]=&payload[subscription][product][expiration_interval_unit]=never&payload[subscription][product][created_at]=2016-03-24%2013%3A38%3A39%20-0400&payload[subscription][product][updated_at]=2016-11-03%2013%3A03%3A05%20-0400&payload[subscription][product][price_in_cents]=1000&payload[subscription][product][interval]=1&payload[subscription][product][interval_unit]=day&payload[subscription][product][initial_charge_in_cents]=&payload[subscription][product][trial_price_in_cents]=&payload[subscription][product][trial_interval]=&payload[subscription][product][trial_interval_unit]=month&payload[subscription][product][archived_at]=&payload[subscription][product][require_credit_card]=false&payload[subscription][product][return_params]=&payload[subscription][product][taxable]=false&payload[subscription][product][update_return_url]=&payload[subscription][product][initial_charge_after_trial]=false&payload[subscription][product][version_number]=7&payload[subscription][product][update_return_params]=&payload[subscription][product][product_family][id]=527890&payload[subscription][product][product_family][name]=Acme%20Projects&payload[subscription][product][product_family][description]=&payload[subscription][product][product_family][handle]=billing-plans&payload[subscription][product][product_family][accounting_code]=&payload[subscription][product][public_signup_pages][id]=281054&payload[subscription][product][public_signup_pages][return_url]=http%3A%2F%2Fwww.example.com%3Fsuccessfulsignup&payload[subscription][product][public_signup_pages][return_params]=&payload[subscription][product][public_signup_pages][url]=https%3A%2F%2Fgeneral-goods.chargify.com%2Fsubscribe%2Fkqvmfrbgd89q%2Fbasic&payload[subscription][product][public_signup_pages][id]=281240&payload[subscription][product][public_signup_pages][return_url]=&payload[subscription][product][public_signup_pages][return_params]=&payload[subscription][product][public_signup_pages][url]=https%3A%2F%2Fgeneral-goods.chargify.com%2Fsubscribe%2Fdkffht5dxfd8%2Fbasic&payload[subscription][product][public_signup_pages][id]=282694&payload[subscription][product][public_signup_pages][return_url]=&payload[subscription][product][public_signup_pages][return_params]=&payload[subscription][product][public_signup_pages][url]=https%3A%2F%2Fgeneral-goods.chargify.com%2Fsubscribe%2Fjwffwgdd95s8%2Fbasic&payload[subscription][credit_card][id]=10102821&payload[subscription][credit_card][first_name]=Pookie&payload[subscription][credit_card][last_name]=Test&payload[subscription][credit_card][masked_card_number]=XXXX-XXXX-XXXX-1&payload[subscription][credit_card][card_type]=bogus&payload[subscription][credit_card][expiration_month]=10&payload[subscription][credit_card][expiration_year]=2020&payload[subscription][credit_card][customer_id]=14585695&payload[subscription][credit_card][current_vault]=bogus&payload[subscription][credit_card][vault_token]=1&payload[subscription][credit_card][billing_address]=&payload[subscription][credit_card][billing_city]=&payload[subscription][credit_card][billing_state]=&payload[subscription][credit_card][billing_zip]=&payload[subscription][credit_card][billing_country]=&payload[subscription][credit_card][customer_vault_token]=&payload[subscription][credit_card][billing_address_2]=&payload[subscription][credit_card][payment_type]=credit_card&payload[subscription][credit_card][site_gateway_setting_id]=&payload[subscription][credit_card][gateway_handle]=&payload[transaction][id]=161537369&payload[transaction][subscription_id]=15100141&payload[transaction][type]=Payment&payload[transaction][kind]=&payload[transaction][transaction_type]=payment&payload[transaction][success]=true&payload[transaction][amount_in_cents]=6400&payload[transaction][memo]=Pookie%20Test%20-%20%2410%20Basic%20Plan%3A%20Renewal%20payment&payload[transaction][created_at]=2016-11-08%2016%3A22%3A20%20-0500&payload[transaction][starting_balance_in_cents]=6400&payload[transaction][ending_balance_in_cents]=0&payload[transaction][gateway_used]=bogus&payload[transaction][gateway_transaction_id]=53433&payload[transaction][gateway_response_code]=&payload[transaction][gateway_order_id]=&payload[transaction][payment_id]=&payload[transaction][product_id]=3792003&payload[transaction][tax_id]=&payload[transaction][component_id]=&payload[transaction][statement_id]=80168049&payload[transaction][customer_id]=14585695&payload[transaction][card_number]=XXXX-XXXX-XXXX-1&payload[transaction][card_expiration]=10%2F2020&payload[transaction][card_type]=bogus&payload[transaction][refunded_amount_in_cents]=0&payload[transaction][invoice_id]=&payload[event_id]=347299364", + "signature": "fbcf2f6be579f9658cff90c4373e0ca2", + "signature_hmac_sha_256": "db96654f5456c5460062feb944ac8bb1418f9d181ae04a8ed982fe9ffdca8de1" + } + } +] +``` diff --git a/pyproject.toml b/pyproject.toml index 5e9b4f95..613cc054 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,13 +4,13 @@ requires = ["setuptools>=61.0"] [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 = "5.0.0" +version = "5.0.1" readme = "README.md" requires-python = ">=3.7" keywords = ["Maxio", "Advaced Billing", "Payments", "Subscription"] authors = [{name = "Maxio SDK", email = "maxio-sdk@maxio.com"}] urls = {Homepage = "https://www.maxio.com/product/advanced-billing"} -dependencies = ["apimatic-core~=0.2.0, >= 0.2.15", "apimatic-core-interfaces~=0.1.0, >= 0.1.5", "apimatic-requests-client-adapter~=0.1.0, >= 0.1.6", "deprecation~=2.1", "python-dateutil~=2.8.1", "jsonschema~=3.2.0"] +dependencies = ["apimatic-core~=0.2.0, >= 0.2.15", "apimatic-core-interfaces~=0.1.0, >= 0.1.5", "apimatic-requests-client-adapter~=0.1.0, >= 0.1.6", "deprecation~=2.1", "python-dateutil~=2.8.1"] classifiers = [] [project.optional-dependencies] testutils = ["pytest>=7.2.2"] diff --git a/requirements.txt b/requirements.txt index 0cae3f18..59d6422e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,3 @@ apimatic-core-interfaces~=0.1.0, >= 0.1.5 apimatic-requests-client-adapter~=0.1.0, >= 0.1.6 python-dateutil~=2.8.1 deprecation~=2.1 -jsonschema~=3.2.0